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