mercurial/utils/stringutil.py
changeset 43076 2372284d9457
parent 40684 e6c9ef5e11a0
child 43077 687b865b95ad
--- a/mercurial/utils/stringutil.py	Sat Oct 05 10:29:34 2019 -0400
+++ b/mercurial/utils/stringutil.py	Sun Oct 06 09:45:02 2019 -0400
@@ -30,6 +30,7 @@
 _regexescapemap = {ord(i): (b'\\' + i).decode('latin1') for i in _respecial}
 regexbytesescapemap = {i: (b'\\' + i) for i in _respecial}
 
+
 def reescape(pat):
     """Drop-in replacement for re.escape."""
     # NOTE: it is intentional that this works on unicodes and not
@@ -44,10 +45,12 @@
         return pat
     return pat.encode('latin1')
 
+
 def pprint(o, bprefix=False, indent=0, level=0):
     """Pretty print an object."""
     return b''.join(pprintgen(o, bprefix=bprefix, indent=indent, level=level))
 
+
 def pprintgen(o, bprefix=False, indent=0, level=0):
     """Pretty print an object to a generator of atoms.
 
@@ -83,8 +86,9 @@
             yield ' ' * (level * indent)
 
         for i, a in enumerate(o):
-            for chunk in pprintgen(a, bprefix=bprefix, indent=indent,
-                                   level=level):
+            for chunk in pprintgen(
+                a, bprefix=bprefix, indent=indent, level=level
+            ):
                 yield chunk
 
             if i + 1 < len(o):
@@ -113,14 +117,16 @@
             yield ' ' * (level * indent)
 
         for i, (k, v) in enumerate(sorted(o.items())):
-            for chunk in pprintgen(k, bprefix=bprefix, indent=indent,
-                                   level=level):
+            for chunk in pprintgen(
+                k, bprefix=bprefix, indent=indent, level=level
+            ):
                 yield chunk
 
             yield ': '
 
-            for chunk in pprintgen(v, bprefix=bprefix, indent=indent,
-                                   level=level):
+            for chunk in pprintgen(
+                v, bprefix=bprefix, indent=indent, level=level
+            ):
                 yield chunk
 
             if i + 1 < len(o):
@@ -149,8 +155,9 @@
             yield ' ' * (level * indent)
 
         for i, k in enumerate(sorted(o)):
-            for chunk in pprintgen(k, bprefix=bprefix, indent=indent,
-                                   level=level):
+            for chunk in pprintgen(
+                k, bprefix=bprefix, indent=indent, level=level
+            ):
                 yield chunk
 
             if i + 1 < len(o):
@@ -179,8 +186,9 @@
             yield ' ' * (level * indent)
 
         for i, a in enumerate(o):
-            for chunk in pprintgen(a, bprefix=bprefix, indent=indent,
-                                   level=level):
+            for chunk in pprintgen(
+                a, bprefix=bprefix, indent=indent, level=level
+            ):
                 yield chunk
 
             if i + 1 < len(o):
@@ -221,8 +229,9 @@
             except StopIteration:
                 last = True
 
-            for chunk in pprintgen(current, bprefix=bprefix, indent=indent,
-                                   level=level):
+            for chunk in pprintgen(
+                current, bprefix=bprefix, indent=indent, level=level
+            ):
                 yield chunk
 
             if not last:
@@ -241,6 +250,7 @@
     else:
         yield pycompat.byterepr(o)
 
+
 def prettyrepr(o):
     """Pretty print a representation of a possibly-nested object"""
     lines = []
@@ -267,6 +277,7 @@
         p0, p1 = q0, q1
     return '\n'.join('  ' * l + s for l, s in lines)
 
+
 def buildrepr(r):
     """Format an optional printable representation from unexpanded bits
 
@@ -290,10 +301,12 @@
     else:
         return pprint(r)
 
+
 def binary(s):
     """return true if a string is binary data"""
     return bool(s and '\0' in s)
 
+
 def stringmatcher(pattern, casesensitive=True):
     """
     accepts a string, possibly starting with 're:' or 'literal:' prefix.
@@ -340,8 +353,7 @@
                 flags = remod.I
             regex = remod.compile(pattern, flags)
         except remod.error as e:
-            raise error.ParseError(_('invalid regular expression: %s')
-                                   % e)
+            raise error.ParseError(_('invalid regular expression: %s') % e)
         return 're', pattern, regex.search
     elif pattern.startswith('literal:'):
         pattern = pattern[8:]
@@ -353,6 +365,7 @@
         match = lambda s: ipat == encoding.lower(s)
     return 'literal', pattern, match
 
+
 def shortuser(user):
     """Return a short representation of a user name or email address."""
     f = user.find('@')
@@ -360,7 +373,7 @@
         user = user[:f]
     f = user.find('<')
     if f >= 0:
-        user = user[f + 1:]
+        user = user[f + 1 :]
     f = user.find(' ')
     if f >= 0:
         user = user[:f]
@@ -369,6 +382,7 @@
         user = user[:f]
     return user
 
+
 def emailuser(user):
     """Return the user portion of an email address."""
     f = user.find('@')
@@ -376,15 +390,17 @@
         user = user[:f]
     f = user.find('<')
     if f >= 0:
-        user = user[f + 1:]
+        user = user[f + 1 :]
     return user
 
+
 def email(author):
     '''get email of author.'''
     r = author.find('>')
     if r == -1:
         r = None
-    return author[author.find('<') + 1:r]
+    return author[author.find('<') + 1 : r]
+
 
 def person(author):
     """Returns the name before an email address,
@@ -413,13 +429,16 @@
     f = author.find('@')
     return author[:f].replace('.', ' ')
 
+
 @attr.s(hash=True)
 class mailmapping(object):
     '''Represents a username/email key or value in
     a mailmap file'''
+
     email = attr.ib()
     name = attr.ib(default=None)
 
+
 def _ismailmaplineinvalid(names, emails):
     '''Returns True if the parsed names and emails
     in a mailmap entry are invalid.
@@ -444,6 +463,7 @@
     '''
     return not emails or not names and len(emails) < 2
 
+
 def parsemailmap(mailmapcontent):
     """Parses data in the .mailmap format
 
@@ -515,17 +535,16 @@
             continue
 
         mailmapkey = mailmapping(
-            email=emails[-1],
-            name=names[-1] if len(names) == 2 else None,
+            email=emails[-1], name=names[-1] if len(names) == 2 else None,
         )
 
         mailmap[mailmapkey] = mailmapping(
-            email=emails[0],
-            name=names[0] if names else None,
+            email=emails[0], name=names[0] if names else None,
         )
 
     return mailmap
 
+
 def mapname(mailmap, author):
     """Returns the author field according to the mailmap cache, or
     the original author field.
@@ -573,8 +592,10 @@
         proper.email if proper.email else commit.email,
     )
 
+
 _correctauthorformat = remod.compile(br'^[^<]+\s\<[^<>]+@[^<>]+\>$')
 
+
 def isauthorwellformed(author):
     '''Return True if the author field is well formed
     (ie "Contributor Name <contrib@email.dom>")
@@ -596,10 +617,12 @@
     '''
     return _correctauthorformat.match(author) is not None
 
+
 def ellipsis(text, maxlength=400):
     """Trim string to at most maxlength (default: 400) columns in display."""
     return encoding.trim(text, maxlength, ellipsis='...')
 
+
 def escapestr(s):
     if isinstance(s, memoryview):
         s = bytes(s)
@@ -607,9 +630,11 @@
     # Python 3 compatibility
     return codecs.escape_encode(s)[0]
 
+
 def unescapestr(s):
     return codecs.escape_decode(s)[0]
 
+
 def forcebytestr(obj):
     """Portably format an arbitrary object (e.g. exception) into a byte
     string."""
@@ -619,10 +644,12 @@
         # non-ascii string, may be lossy
         return pycompat.bytestr(encoding.strtolocal(str(obj)))
 
+
 def uirepr(s):
     # Avoid double backslash in Windows path repr()
     return pycompat.byterepr(pycompat.bytestr(s)).replace(b'\\\\', b'\\')
 
+
 # delay import of textwrap
 def _MBTextWrapper(**kwargs):
     class tw(textwrap.TextWrapper):
@@ -640,6 +667,7 @@
 
         This requires use decision to determine width of such characters.
         """
+
         def _cutdown(self, ucstr, space_left):
             l = 0
             colwidth = encoding.ucolwidth
@@ -712,8 +740,11 @@
                     self._handle_long_word(chunks, cur_line, cur_len, width)
 
                 # If the last chunk on this line is all whitespace, drop it.
-                if (self.drop_whitespace and
-                    cur_line and cur_line[-1].strip() == r''):
+                if (
+                    self.drop_whitespace
+                    and cur_line
+                    and cur_line[-1].strip() == r''
+                ):
                     del cur_line[-1]
 
                 # Convert current line back to a string and store it in list
@@ -727,25 +758,43 @@
     _MBTextWrapper = tw
     return tw(**kwargs)
 
+
 def wrap(line, width, initindent='', hangindent=''):
     maxindent = max(len(hangindent), len(initindent))
     if width <= maxindent:
         # adjust for weird terminal size
         width = max(78, maxindent + 1)
-    line = line.decode(pycompat.sysstr(encoding.encoding),
-                       pycompat.sysstr(encoding.encodingmode))
-    initindent = initindent.decode(pycompat.sysstr(encoding.encoding),
-                                   pycompat.sysstr(encoding.encodingmode))
-    hangindent = hangindent.decode(pycompat.sysstr(encoding.encoding),
-                                   pycompat.sysstr(encoding.encodingmode))
-    wrapper = _MBTextWrapper(width=width,
-                             initial_indent=initindent,
-                             subsequent_indent=hangindent)
+    line = line.decode(
+        pycompat.sysstr(encoding.encoding),
+        pycompat.sysstr(encoding.encodingmode),
+    )
+    initindent = initindent.decode(
+        pycompat.sysstr(encoding.encoding),
+        pycompat.sysstr(encoding.encodingmode),
+    )
+    hangindent = hangindent.decode(
+        pycompat.sysstr(encoding.encoding),
+        pycompat.sysstr(encoding.encodingmode),
+    )
+    wrapper = _MBTextWrapper(
+        width=width, initial_indent=initindent, subsequent_indent=hangindent
+    )
     return wrapper.fill(line).encode(pycompat.sysstr(encoding.encoding))
 
-_booleans = {'1': True, 'yes': True, 'true': True, 'on': True, 'always': True,
-             '0': False, 'no': False, 'false': False, 'off': False,
-             'never': False}
+
+_booleans = {
+    '1': True,
+    'yes': True,
+    'true': True,
+    'on': True,
+    'always': True,
+    '0': False,
+    'no': False,
+    'false': False,
+    'off': False,
+    'never': False,
+}
+
 
 def parsebool(s):
     """Parse s into a boolean.
@@ -754,6 +803,7 @@
     """
     return _booleans.get(s.lower(), None)
 
+
 def evalpythonliteral(s):
     """Evaluate a string containing a Python literal expression"""
     # We could backport our tokenizer hack to rewrite '' to u'' if we want