mercurial/templatefilters.py
changeset 43076 2372284d9457
parent 41997 4df7c4b70e03
child 43077 687b865b95ad
--- a/mercurial/templatefilters.py	Sat Oct 05 10:29:34 2019 -0400
+++ b/mercurial/templatefilters.py	Sun Oct 06 09:45:02 2019 -0400
@@ -42,6 +42,7 @@
 
 templatefilter = registrar.templatefilter(filters)
 
+
 @templatefilter('addbreaks', intype=bytes)
 def addbreaks(text):
     """Any text. Add an XHTML "<br />" tag before the end of
@@ -49,13 +50,17 @@
     """
     return text.replace('\n', '<br/>\n')
 
-agescales = [("year", 3600 * 24 * 365, 'Y'),
-             ("month", 3600 * 24 * 30, 'M'),
-             ("week", 3600 * 24 * 7, 'W'),
-             ("day", 3600 * 24, 'd'),
-             ("hour", 3600, 'h'),
-             ("minute", 60, 'm'),
-             ("second", 1, 's')]
+
+agescales = [
+    ("year", 3600 * 24 * 365, 'Y'),
+    ("month", 3600 * 24 * 30, 'M'),
+    ("week", 3600 * 24 * 7, 'W'),
+    ("day", 3600 * 24, 'd'),
+    ("hour", 3600, 'h'),
+    ("minute", 60, 'm'),
+    ("second", 1, 's'),
+]
+
 
 @templatefilter('age', intype=templateutil.date)
 def age(date, abbrev=False):
@@ -67,6 +72,7 @@
         if c == 1:
             return t
         return t + "s"
+
     def fmt(t, c, a):
         if abbrev:
             return "%d%s" % (c, a)
@@ -92,6 +98,7 @@
                 return '%s from now' % fmt(t, n, a)
             return '%s ago' % fmt(t, n, a)
 
+
 @templatefilter('basename', intype=bytes)
 def basename(path):
     """Any text. Treats the text as a path, and returns the last
@@ -100,11 +107,13 @@
     """
     return os.path.basename(path)
 
+
 @templatefilter('cbor')
 def cbor(obj):
     """Any object. Serializes the object to CBOR bytes."""
     return b''.join(cborutil.streamencode(obj))
 
+
 @templatefilter('commondir')
 def commondir(filelist):
     """List of text. Treats each list item as file name with /
@@ -118,17 +127,19 @@
     For example, ["foo/bar/baz", "foo/baz/bar"] becomes "foo" and
     ["foo/bar", "baz"] becomes "".
     """
+
     def common(a, b):
         if len(a) > len(b):
-            a = b[:len(a)]
+            a = b[: len(a)]
         elif len(b) > len(a):
-            b = b[:len(a)]
+            b = b[: len(a)]
         if a == b:
             return a
         for i in pycompat.xrange(len(a)):
             if a[i] != b[i]:
                 return a[:i]
         return a
+
     try:
         if not filelist:
             return ""
@@ -144,6 +155,7 @@
     except TypeError:
         raise error.ParseError(_('argument is not a list of text'))
 
+
 @templatefilter('count')
 def count(i):
     """List or text. Returns the length as an integer."""
@@ -152,6 +164,7 @@
     except TypeError:
         raise error.ParseError(_('not countable'))
 
+
 @templatefilter('dirname', intype=bytes)
 def dirname(path):
     """Any text. Treats the text as a path, and strips the last
@@ -159,6 +172,7 @@
     """
     return os.path.dirname(path)
 
+
 @templatefilter('domain', intype=bytes)
 def domain(author):
     """Any text. Finds the first string that looks like an email
@@ -168,12 +182,13 @@
     f = author.find('@')
     if f == -1:
         return ''
-    author = author[f + 1:]
+    author = author[f + 1 :]
     f = author.find('>')
     if f >= 0:
         author = author[:f]
     return author
 
+
 @templatefilter('email', intype=bytes)
 def email(text):
     """Any text. Extracts the first string that looks like an email
@@ -182,6 +197,7 @@
     """
     return stringutil.email(text)
 
+
 @templatefilter('escape', intype=bytes)
 def escape(text):
     """Any text. Replaces the special XML/XHTML characters "&", "<"
@@ -189,9 +205,11 @@
     """
     return url.escape(text.replace('\0', ''), True)
 
+
 para_re = None
 space_re = None
 
+
 def fill(text, width, initindent='', hangindent=''):
     '''fill many paragraphs with optional indentation.'''
     global para_re, space_re
@@ -208,27 +226,40 @@
                 w = len(uctext)
                 while w > 0 and uctext[w - 1].isspace():
                     w -= 1
-                yield (encoding.unitolocal(uctext[:w]),
-                       encoding.unitolocal(uctext[w:]))
+                yield (
+                    encoding.unitolocal(uctext[:w]),
+                    encoding.unitolocal(uctext[w:]),
+                )
                 break
-            yield text[start:m.start(0)], m.group(1)
+            yield text[start : m.start(0)], m.group(1)
             start = m.end(1)
 
-    return "".join([stringutil.wrap(space_re.sub(' ',
-                                                 stringutil.wrap(para, width)),
-                                    width, initindent, hangindent) + rest
-                    for para, rest in findparas()])
+    return "".join(
+        [
+            stringutil.wrap(
+                space_re.sub(' ', stringutil.wrap(para, width)),
+                width,
+                initindent,
+                hangindent,
+            )
+            + rest
+            for para, rest in findparas()
+        ]
+    )
+
 
 @templatefilter('fill68', intype=bytes)
 def fill68(text):
     """Any text. Wraps the text to fit in 68 columns."""
     return fill(text, 68)
 
+
 @templatefilter('fill76', intype=bytes)
 def fill76(text):
     """Any text. Wraps the text to fit in 76 columns."""
     return fill(text, 76)
 
+
 @templatefilter('firstline', intype=bytes)
 def firstline(text):
     """Any text. Returns the first line of text."""
@@ -237,6 +268,7 @@
     except IndexError:
         return ''
 
+
 @templatefilter('hex', intype=bytes)
 def hexfilter(text):
     """Any text. Convert a binary Mercurial node identifier into
@@ -244,6 +276,7 @@
     """
     return node.hex(text)
 
+
 @templatefilter('hgdate', intype=templateutil.date)
 def hgdate(text):
     """Date. Returns the date as a pair of numbers: "1157407993
@@ -251,6 +284,7 @@
     """
     return "%d %d" % text
 
+
 @templatefilter('isodate', intype=templateutil.date)
 def isodate(text):
     """Date. Returns the date in ISO 8601 format: "2009-08-18 13:00
@@ -258,6 +292,7 @@
     """
     return dateutil.datestr(text, '%Y-%m-%d %H:%M %1%2')
 
+
 @templatefilter('isodatesec', intype=templateutil.date)
 def isodatesec(text):
     """Date. Returns the date in ISO 8601 format, including
@@ -266,11 +301,13 @@
     """
     return dateutil.datestr(text, '%Y-%m-%d %H:%M:%S %1%2')
 
+
 def indent(text, prefix):
     '''indent each non-empty line of text after first with prefix.'''
     lines = text.splitlines()
     num_lines = len(lines)
     endswithnewline = text[-1:] == '\n'
+
     def indenter():
         for i in pycompat.xrange(num_lines):
             l = lines[i]
@@ -279,8 +316,10 @@
             yield l
             if i < num_lines - 1 or endswithnewline:
                 yield '\n'
+
     return "".join(indenter())
 
+
 @templatefilter('json')
 def json(obj, paranoid=True):
     """Any object. Serializes the object to a JSON formatted text."""
@@ -296,27 +335,33 @@
         return '"%s"' % encoding.jsonescape(obj, paranoid=paranoid)
     elif isinstance(obj, type(u'')):
         raise error.ProgrammingError(
-            'Mercurial only does output with bytes: %r' % obj)
+            'Mercurial only does output with bytes: %r' % obj
+        )
     elif util.safehasattr(obj, 'keys'):
-        out = ['"%s": %s' % (encoding.jsonescape(k, paranoid=paranoid),
-                             json(v, paranoid))
-               for k, v in sorted(obj.iteritems())]
+        out = [
+            '"%s": %s'
+            % (encoding.jsonescape(k, paranoid=paranoid), json(v, paranoid))
+            for k, v in sorted(obj.iteritems())
+        ]
         return '{' + ', '.join(out) + '}'
     elif util.safehasattr(obj, '__iter__'):
         out = [json(i, paranoid) for i in obj]
         return '[' + ', '.join(out) + ']'
     raise error.ProgrammingError('cannot encode %r' % obj)
 
+
 @templatefilter('lower', intype=bytes)
 def lower(text):
     """Any text. Converts the text to lowercase."""
     return encoding.lower(text)
 
+
 @templatefilter('nonempty', intype=bytes)
 def nonempty(text):
     """Any text. Returns '(none)' if the string is empty."""
     return text or "(none)"
 
+
 @templatefilter('obfuscate', intype=bytes)
 def obfuscate(text):
     """Any text. Returns the input text rendered as a sequence of
@@ -325,6 +370,7 @@
     text = unicode(text, pycompat.sysstr(encoding.encoding), r'replace')
     return ''.join(['&#%d;' % ord(c) for c in text])
 
+
 @templatefilter('permissions', intype=bytes)
 def permissions(flags):
     if "l" in flags:
@@ -333,6 +379,7 @@
         return "-rwxr-xr-x"
     return "-rw-r--r--"
 
+
 @templatefilter('person', intype=bytes)
 def person(author):
     """Any text. Returns the name before an email address,
@@ -340,6 +387,7 @@
     """
     return stringutil.person(author)
 
+
 @templatefilter('revescape', intype=bytes)
 def revescape(text):
     """Any text. Escapes all "special" characters, except @.
@@ -348,6 +396,7 @@
     """
     return urlreq.quote(text, safe='/@').replace('/', '%252F')
 
+
 @templatefilter('rfc3339date', intype=templateutil.date)
 def rfc3339date(text):
     """Date. Returns a date using the Internet date format
@@ -355,6 +404,7 @@
     """
     return dateutil.datestr(text, "%Y-%m-%dT%H:%M:%S%1:%2")
 
+
 @templatefilter('rfc822date', intype=templateutil.date)
 def rfc822date(text):
     """Date. Returns a date using the same format used in email
@@ -362,6 +412,7 @@
     """
     return dateutil.datestr(text, "%a, %d %b %Y %H:%M:%S %1%2")
 
+
 @templatefilter('short', intype=bytes)
 def short(text):
     """Changeset hash. Returns the short form of a changeset hash,
@@ -369,6 +420,7 @@
     """
     return text[:12]
 
+
 @templatefilter('shortbisect', intype=bytes)
 def shortbisect(label):
     """Any text. Treats `label` as a bisection status, and
@@ -380,25 +432,30 @@
         return label[0:1].upper()
     return ' '
 
+
 @templatefilter('shortdate', intype=templateutil.date)
 def shortdate(text):
     """Date. Returns a date like "2006-09-18"."""
     return dateutil.shortdate(text)
 
+
 @templatefilter('slashpath', intype=bytes)
 def slashpath(path):
     """Any text. Replaces the native path separator with slash."""
     return util.pconvert(path)
 
+
 @templatefilter('splitlines', intype=bytes)
 def splitlines(text):
     """Any text. Split text into a list of lines."""
     return templateutil.hybridlist(text.splitlines(), name='line')
 
+
 @templatefilter('stringescape', intype=bytes)
 def stringescape(text):
     return stringutil.escapestr(text)
 
+
 @templatefilter('stringify', intype=bytes)
 def stringify(thing):
     """Any type. Turns the value into text by converting values into
@@ -406,6 +463,7 @@
     """
     return thing  # coerced by the intype
 
+
 @templatefilter('stripdir', intype=bytes)
 def stripdir(text):
     """Treat the text as path and strip a directory level, if
@@ -417,6 +475,7 @@
     else:
         return dir
 
+
 @templatefilter('tabindent', intype=bytes)
 def tabindent(text):
     """Any text. Returns the text, with every non-empty line
@@ -424,11 +483,13 @@
     """
     return indent(text, '\t')
 
+
 @templatefilter('upper', intype=bytes)
 def upper(text):
     """Any text. Converts the text to uppercase."""
     return encoding.upper(text)
 
+
 @templatefilter('urlescape', intype=bytes)
 def urlescape(text):
     """Any text. Escapes all "special" characters. For example,
@@ -436,32 +497,38 @@
     """
     return urlreq.quote(text)
 
+
 @templatefilter('user', intype=bytes)
 def userfilter(text):
     """Any text. Returns a short representation of a user name or email
     address."""
     return stringutil.shortuser(text)
 
+
 @templatefilter('emailuser', intype=bytes)
 def emailuser(text):
     """Any text. Returns the user portion of an email address."""
     return stringutil.emailuser(text)
 
+
 @templatefilter('utf8', intype=bytes)
 def utf8(text):
     """Any text. Converts from the local character encoding to UTF-8."""
     return encoding.fromlocal(text)
 
+
 @templatefilter('xmlescape', intype=bytes)
 def xmlescape(text):
-    text = (text
-            .replace('&', '&amp;')
-            .replace('<', '&lt;')
-            .replace('>', '&gt;')
-            .replace('"', '&quot;')
-            .replace("'", '&#39;')) # &apos; invalid in HTML
+    text = (
+        text.replace('&', '&amp;')
+        .replace('<', '&lt;')
+        .replace('>', '&gt;')
+        .replace('"', '&quot;')
+        .replace("'", '&#39;')
+    )  # &apos; invalid in HTML
     return re.sub('[\x00-\x08\x0B\x0C\x0E-\x1F]', ' ', text)
 
+
 def websub(text, websubtable):
     """:websub: Any text. Only applies to hgweb. Applies the regular
     expression replacements defined in the websub section.
@@ -471,11 +538,13 @@
             text = regexp.sub(format, text)
     return text
 
+
 def loadfilter(ui, extname, registrarobj):
     """Load template filter from specified registrarobj
     """
     for name, func in registrarobj._table.iteritems():
         filters[name] = func
 
+
 # tell hggettext to extract docstrings from these functions:
 i18nfunctions = filters.values()