##// END OF EJS Templates
helpers: python3 port
super-admin -
r5084:536057f6 default
parent child Browse files
Show More
@@ -29,15 +29,16 b' import collections'
29 29 import os
30 30 import random
31 31 import hashlib
32 from io import StringIO
32 import io
33 33 import textwrap
34 import urllib.request, urllib.parse, urllib.error
34 import urllib.request
35 import urllib.parse
36 import urllib.error
35 37 import math
36 38 import logging
37 39 import re
38 40 import time
39 41 import string
40 import hashlib
41 42 import regex
42 43 from collections import OrderedDict
43 44
@@ -70,19 +71,22 b' from webhelpers2.html.tags import ('
70 71 form as insecure_form,
71 72 auto_discovery_link, checkbox, end_form, file,
72 73 hidden, image, javascript_link, link_to, link_to_if, link_to_unless, ol,
73 select as raw_select, stylesheet_link, submit, text, password, textarea,
74 stylesheet_link, submit, text, password, textarea,
74 75 ul, radio, Options)
75 76
76 77 from webhelpers2.number import format_byte_size
78 # python3.11 backport fixes for webhelpers2
79 from rhodecode.lib._vendor.webhelpers_backports import raw_select
77 80
78 81 from rhodecode.lib.action_parser import action_parser
79 82 from rhodecode.lib.pagination import Page, RepoPage, SqlPage
80 83 from rhodecode.lib import ext_json
81 84 from rhodecode.lib.ext_json import json
82 from rhodecode.lib.str_utils import safe_bytes
85 from rhodecode.lib.str_utils import safe_bytes, convert_special_chars
83 86 from rhodecode.lib.utils import repo_name_slug, get_custom_lexer
87 from rhodecode.lib.str_utils import safe_str
84 88 from rhodecode.lib.utils2 import (
85 str2bool, safe_unicode, safe_str,
89 str2bool,
86 90 get_commit_safe, datetime_to_time, time_to_datetime, time_to_utcdatetime,
87 91 AttributeDict, safe_int, md5, md5_safe, get_host_info)
88 92 from rhodecode.lib.markup_renderer import MarkupRenderer, relative_links
@@ -123,11 +127,11 b' def asset(path, ver=None, **kwargs):'
123 127
124 128
125 129 default_html_escape_table = {
126 ord('&'): u'&',
127 ord('<'): u'&lt;',
128 ord('>'): u'&gt;',
129 ord('"'): u'&quot;',
130 ord("'"): u'&#39;',
130 ord('&'): '&amp;',
131 ord('<'): '&lt;',
132 ord('>'): '&gt;',
133 ord('"'): '&quot;',
134 ord("'"): '&#39;',
131 135 }
132 136
133 137
@@ -265,14 +269,12 b' class _ToolTip(object):'
265 269
266 270 tooltip = _ToolTip()
267 271
268 files_icon = u'<i class="file-breadcrumb-copy tooltip icon-clipboard clipboard-action" data-clipboard-text="{}" title="Copy file path"></i>'
272 files_icon = '<i class="file-breadcrumb-copy tooltip icon-clipboard clipboard-action" data-clipboard-text="{}" title="Copy file path"></i>'
269 273
270 274
271 275 def files_breadcrumbs(repo_name, repo_type, commit_id, file_path, landing_ref_name=None, at_ref=None,
272 276 limit_items=False, linkify_last_item=False, hide_last_item=False,
273 277 copy_path_icon=True):
274 if isinstance(file_path, str):
275 file_path = safe_unicode(file_path)
276 278
277 279 if at_ref:
278 280 route_qry = {'at': at_ref}
@@ -282,7 +284,7 b' def files_breadcrumbs(repo_name, repo_ty'
282 284 default_landing_ref = commit_id
283 285
284 286 # first segment is a `HOME` link to repo files root location
285 root_name = literal(u'<i class="icon-home"></i>')
287 root_name = literal('<i class="icon-home"></i>')
286 288
287 289 url_segments = [
288 290 link_to(
@@ -345,7 +347,6 b' def files_breadcrumbs(repo_name, repo_ty'
345 347
346 348
347 349 def files_url_data(request):
348 import urllib.request, urllib.parse, urllib.error
349 350 matchdict = request.matchdict
350 351
351 352 if 'f_path' not in matchdict:
@@ -426,17 +427,17 b' class CodeHtmlFormatter(HtmlFormatter):'
426 427 My code Html Formatter for source codes
427 428 """
428 429
429 def wrap(self, source, outfile):
430 def wrap(self, source):
430 431 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
431 432
432 433 def _wrap_code(self, source):
433 434 for cnt, it in enumerate(source):
434 435 i, t = it
435 t = '<div id="L%s">%s</div>' % (cnt + 1, t)
436 t = f'<div id="L{cnt+1}">{t}</div>'
436 437 yield i, t
437 438
438 439 def _wrap_tablelinenos(self, inner):
439 dummyoutfile = StringIO.StringIO()
440 dummyoutfile = io.StringIO()
440 441 lncount = 0
441 442 for t, line in inner:
442 443 if t:
@@ -594,7 +595,7 b' def unique_color_generator(n=10000, satu'
594 595 h %= 1
595 596 HSV_tuple = [h, saturation, lightness]
596 597 RGB_tuple = hsv_to_rgb(*HSV_tuple)
597 yield map(lambda x: str(int(x * 256)), RGB_tuple)
598 yield [str(int(x * 256)) for x in RGB_tuple]
598 599
599 600
600 601 def color_hasher(n=10000, saturation=0.10, lightness=0.95):
@@ -692,7 +693,7 b' class _Message(object):'
692 693 __unicode__ = __str__
693 694
694 695 def __html__(self):
695 return escape(safe_unicode(self.message))
696 return escape(safe_str(self.message))
696 697
697 698
698 699 class Flash(object):
@@ -771,7 +772,7 b' class Flash(object):'
771 772 for message in messages:
772 773 payloads.append({
773 774 'message': {
774 'message': u'{}'.format(message.message),
775 'message': '{}'.format(message.message),
775 776 'level': message.category,
776 777 'force': True,
777 778 'subdata': message.sub_data
@@ -816,8 +817,7 b' def hide_credentials(url):'
816 817 from rhodecode.lib.utils2 import credentials_filter
817 818 return credentials_filter(url)
818 819
819
820 import pytz
820 import zoneinfo
821 821 import tzlocal
822 822 local_timezone = tzlocal.get_localzone()
823 823
@@ -829,9 +829,10 b' def get_timezone(datetime_iso, time_is_l'
829 829 if time_is_local and isinstance(datetime_iso, datetime) and not datetime_iso.tzinfo:
830 830 force_timezone = os.environ.get('RC_TIMEZONE', '')
831 831 if force_timezone:
832 force_timezone = pytz.timezone(force_timezone)
832 force_timezone = zoneinfo.ZoneInfo(force_timezone)
833 833 timezone = force_timezone or local_timezone
834 offset = timezone.localize(datetime_iso).strftime('%z')
834
835 offset = datetime_iso.replace(tzinfo=timezone).strftime('%z')
835 836 tzinfo = '{}:{}'.format(offset[:-2], offset[-2:])
836 837 return tzinfo
837 838
@@ -883,9 +884,9 b' def format_date(date):'
883 884
884 885 if date:
885 886 _fmt = "%a, %d %b %Y %H:%M:%S"
886 return safe_unicode(date.strftime(_fmt))
887
888 return u""
887 return safe_str(date.strftime(_fmt))
888
889 return ""
889 890
890 891
891 892 class _RepoChecker(object):
@@ -1021,7 +1022,8 b' def author_string(email):'
1021 1022
1022 1023 def person_by_id(id_, show_attr="username_and_name"):
1023 1024 # attr to return from fetched user
1024 person_getter = lambda usr: getattr(usr, show_attr)
1025 def person_getter(usr):
1026 return getattr(usr, show_attr)
1025 1027
1026 1028 #maybe it's an ID ?
1027 1029 if str(id_).isdigit() or isinstance(id_, int):
@@ -1074,7 +1076,7 b' def extract_metatags(value):'
1074 1076 if not value:
1075 1077 return tags, ''
1076 1078
1077 for key, val in tags_paterns.items():
1079 for key, val in list(tags_paterns.items()):
1078 1080 pat, replace_html = val
1079 1081 tags.extend([(key, x.group()) for x in pat.finditer(value)])
1080 1082 value = pat.sub('', value)
@@ -1093,8 +1095,8 b' def style_metatag(tag_type, value):'
1093 1095 tag_data = tags_paterns.get(tag_type)
1094 1096 if tag_data:
1095 1097 pat, replace_html = tag_data
1096 # convert to plain `unicode` instead of a markup tag to be used in
1097 # regex expressions. safe_unicode doesn't work here
1098 # convert to plain `str` instead of a markup tag to be used in
1099 # regex expressions. safe_str doesn't work here
1098 1100 html_value = pat.sub(replace_html, value)
1099 1101
1100 1102 return html_value
@@ -1117,7 +1119,7 b' def bool2icon(value, show_at_false=True)'
1117 1119
1118 1120
1119 1121 def b64(inp):
1120 return base64.b64encode(inp)
1122 return base64.b64encode(safe_bytes(inp))
1121 1123
1122 1124 #==============================================================================
1123 1125 # PERMS
@@ -1230,23 +1232,22 b' class InitialsGravatar(object):'
1230 1232 return color_bank[pos]
1231 1233
1232 1234 def normalize_email(self, email_address):
1233 import unicodedata
1234 1235 # default host used to fill in the fake/missing email
1235 1236 default_host = 'localhost'
1236 1237
1237 1238 if not email_address:
1238 email_address = '%s@%s' % (User.DEFAULT_USER, default_host)
1239
1240 email_address = safe_unicode(email_address)
1241
1242 if u'@' not in email_address:
1243 email_address = u'%s@%s' % (email_address, default_host)
1244
1245 if email_address.endswith(u'@'):
1246 email_address = u'%s%s' % (email_address, default_host)
1247
1248 email_address = unicodedata.normalize('NFKD', email_address)\
1249 .encode('ascii', 'ignore')
1239 email_address = f'{User.DEFAULT_USER}@{default_host}'
1240
1241 email_address = safe_str(email_address)
1242
1243 if '@' not in email_address:
1244 email_address = f'{email_address}@{default_host}'
1245
1246 if email_address.endswith('@'):
1247 email_address = f'{email_address}{default_host}'
1248
1249 email_address = convert_special_chars(email_address)
1250
1250 1251 return email_address
1251 1252
1252 1253 def get_initials(self):
@@ -1266,12 +1267,11 b' class InitialsGravatar(object):'
1266 1267 Function also normalizes the non-ascii characters to they ascii
1267 1268 representation, eg Δ„ => A
1268 1269 """
1269 import unicodedata
1270 1270 # replace non-ascii to ascii
1271 first_name = unicodedata.normalize(
1272 'NFKD', safe_unicode(self.first_name)).encode('ascii', 'ignore')
1273 last_name = unicodedata.normalize(
1274 'NFKD', safe_unicode(self.last_name)).encode('ascii', 'ignore')
1271 first_name = convert_special_chars(self.first_name)
1272 last_name = convert_special_chars(self.last_name)
1273 # multi word last names, Guido Von Rossum, we take the last part only
1274 last_name = last_name.split(' ', 1)[-1]
1275 1275
1276 1276 # do NFKD encoding, and also make sure email has proper format
1277 1277 email_address = self.normalize_email(self.email_address)
@@ -1286,9 +1286,9 b' class InitialsGravatar(object):'
1286 1286 else:
1287 1287 initials = [prefix[0], server[0]]
1288 1288
1289 # then try to replace either first_name or last_name
1289 # get first letter of first and last names to create initials
1290 1290 fn_letter = (first_name or " ")[0].strip()
1291 ln_letter = (last_name.split(' ', 1)[-1] or " ")[0].strip()
1291 ln_letter = (last_name or " ")[0].strip()
1292 1292
1293 1293 if fn_letter:
1294 1294 initials[0] = fn_letter
@@ -1305,6 +1305,7 b' class InitialsGravatar(object):'
1305 1305 viewBox="-15 -10 439.165 429.164"
1306 1306
1307 1307 xml:space="preserve"
1308 font-family="{font_family}
1308 1309 style="background:{background};" >
1309 1310
1310 1311 <path d="M204.583,216.671c50.664,0,91.74-48.075,
@@ -1374,8 +1375,8 b' class InitialsGravatar(object):'
1374 1375 return img_data
1375 1376
1376 1377 def generate_svg(self, svg_type=None):
1377 img_data = self.get_img_data(svg_type)
1378 return "data:image/svg+xml;base64,%s" % base64.b64encode(img_data)
1378 img_data = safe_bytes(self.get_img_data(svg_type))
1379 return "data:image/svg+xml;base64,%s" % safe_str(base64.b64encode(img_data))
1379 1380
1380 1381
1381 1382 def initials_gravatar(request, email_address, first_name, last_name, size=30, store_on_disk=False):
@@ -1421,7 +1422,7 b' def initials_gravatar(request, email_add'
1421 1422 file_uid=store_uid, filename=metadata["filename"],
1422 1423 file_hash=metadata["sha256"], file_size=metadata["size"],
1423 1424 file_display_name=filename,
1424 file_description=u'user gravatar `{}`'.format(safe_unicode(filename)),
1425 file_description=f'user gravatar `{safe_str(filename)}`',
1425 1426 hidden=True, check_acl=False, user_id=1
1426 1427 )
1427 1428 Session().add(entry)
@@ -1694,7 +1695,7 b' def process_patterns(text_string, repo_n'
1694 1695
1695 1696 log.debug('Got %s pattern entries to process', len(active_entries))
1696 1697
1697 for uid, entry in active_entries.items():
1698 for uid, entry in list(active_entries.items()):
1698 1699
1699 1700 if not (entry['pat'] and entry['url']):
1700 1701 log.debug('skipping due to missing data')
@@ -1841,10 +1842,10 b" def render(source, renderer='rst', menti"
1841 1842 for issue in issues:
1842 1843 issues_container_callback(issue)
1843 1844
1844 return literal(
1845 '<div class="rst-block">%s</div>' %
1846 maybe_convert_relative_links(
1847 MarkupRenderer.rst(source, mentions=mentions)))
1845 rendered_block = maybe_convert_relative_links(
1846 MarkupRenderer.rst(source, mentions=mentions))
1847
1848 return literal(f'<div class="rst-block">{rendered_block}</div>')
1848 1849
1849 1850 elif renderer == 'markdown':
1850 1851 if repo_name:
@@ -1856,18 +1857,14 b" def render(source, renderer='rst', menti"
1856 1857 for issue in issues:
1857 1858 issues_container_callback(issue)
1858 1859
1859
1860 return literal(
1861 '<div class="markdown-block">%s</div>' %
1862 maybe_convert_relative_links(
1863 MarkupRenderer.markdown(source, flavored=True,
1864 mentions=mentions)))
1860 rendered_block = maybe_convert_relative_links(
1861 MarkupRenderer.markdown(source, flavored=True, mentions=mentions))
1862 return literal(f'<div class="markdown-block">{rendered_block}</div>')
1865 1863
1866 1864 elif renderer == 'jupyter':
1867 return literal(
1868 '<div class="ipynb">%s</div>' %
1869 maybe_convert_relative_links(
1870 MarkupRenderer.jupyter(source)))
1865 rendered_block = maybe_convert_relative_links(
1866 MarkupRenderer.jupyter(source))
1867 return literal(f'<div class="ipynb">{rendered_block}</div>')
1871 1868
1872 1869 # None means just show the file-source
1873 1870 return None
@@ -2020,10 +2017,10 b' def get_visual_attr(tmpl_context_var, at'
2020 2017
2021 2018 def get_last_path_part(file_node):
2022 2019 if not file_node.path:
2023 return u'/'
2024
2025 path = safe_unicode(file_node.path.split('/')[-1])
2026 return u'../' + path
2020 return '/'
2021
2022 path = safe_str(file_node.path.split('/')[-1])
2023 return '../' + path
2027 2024
2028 2025
2029 2026 def route_url(*args, **kwargs):
General Comments 0
You need to be logged in to leave comments. Login now