diff mercurial/patch.py @ 43076:2372284d9457

formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:45:02 -0400
parents db33e4f25729
children 687b865b95ad
line wrap: on
line diff
--- a/mercurial/patch.py	Sat Oct 05 10:29:34 2019 -0400
+++ b/mercurial/patch.py	Sun Oct 06 09:45:02 2019 -0400
@@ -49,15 +49,18 @@
 
 gitre = re.compile(br'diff --git a/(.*) b/(.*)')
 tabsplitter = re.compile(br'(\t+|[^\t]+)')
-wordsplitter = re.compile(br'(\t+| +|[a-zA-Z0-9_\x80-\xff]+|'
-                          b'[^ \ta-zA-Z0-9_\x80-\xff])')
+wordsplitter = re.compile(
+    br'(\t+| +|[a-zA-Z0-9_\x80-\xff]+|' b'[^ \ta-zA-Z0-9_\x80-\xff])'
+)
 
 PatchError = error.PatchError
 
 # public functions
 
+
 def split(stream):
     '''return an iterator of individual patches from a stream'''
+
     def isheader(line, inheader):
         if inheader and line.startswith((' ', '\t')):
             # continuation
@@ -185,12 +188,15 @@
     # if we are here, we have a very plain patch
     return remainder(cur)
 
+
 ## Some facility for extensible patch parsing:
 # list of pairs ("header to match", "data key")
-patchheadermap = [('Date', 'date'),
-                  ('Branch', 'branch'),
-                  ('Node ID', 'nodeid'),
-                 ]
+patchheadermap = [
+    ('Date', 'date'),
+    ('Branch', 'branch'),
+    ('Node ID', 'nodeid'),
+]
+
 
 @contextlib.contextmanager
 def extract(ui, fileobj):
@@ -218,15 +224,18 @@
         tmpfp.close()
         os.unlink(tmpname)
 
+
 def _extract(ui, fileobj, tmpname, tmpfp):
 
     # attempt to detect the start of a patch
     # (this heuristic is borrowed from quilt)
-    diffre = re.compile(br'^(?:Index:[ \t]|diff[ \t]-|RCS file: |'
-                        br'retrieving revision [0-9]+(\.[0-9]+)*$|'
-                        br'---[ \t].*?^\+\+\+[ \t]|'
-                        br'\*\*\*[ \t].*?^---[ \t])',
-                        re.MULTILINE | re.DOTALL)
+    diffre = re.compile(
+        br'^(?:Index:[ \t]|diff[ \t]-|RCS file: |'
+        br'retrieving revision [0-9]+(\.[0-9]+)*$|'
+        br'---[ \t].*?^\+\+\+[ \t]|'
+        br'\*\*\*[ \t].*?^---[ \t])',
+        re.MULTILINE | re.DOTALL,
+    )
 
     data = {}
 
@@ -236,8 +245,12 @@
     data['user'] = msg[r'From'] and mail.headdecode(msg[r'From'])
     if not subject and not data['user']:
         # Not an email, restore parsed headers if any
-        subject = '\n'.join(': '.join(map(encoding.strtolocal, h))
-                            for h in msg.items()) + '\n'
+        subject = (
+            '\n'.join(
+                ': '.join(map(encoding.strtolocal, h)) for h in msg.items()
+            )
+            + '\n'
+        )
 
     # should try to parse msg['Date']
     parents = []
@@ -246,7 +259,7 @@
         if subject.startswith('[PATCH'):
             pend = subject.find(']')
             if pend >= 0:
-                subject = subject[pend + 1:].lstrip()
+                subject = subject[pend + 1 :].lstrip()
         subject = re.sub(br'\n[ \t]+', ' ', subject)
         ui.debug('Subject: %s\n' % subject)
     if data['user']:
@@ -269,7 +282,7 @@
             ui.debug('found patch at byte %d\n' % m.start(0))
             diffs_seen += 1
             cfp = stringio()
-            for line in payload[:m.start(0)].splitlines():
+            for line in payload[: m.start(0)].splitlines():
                 if line.startswith('# HG changeset patch') and not hgpatch:
                     ui.debug('patch generated by hg export\n')
                     hgpatch = True
@@ -288,7 +301,7 @@
                         for header, key in patchheadermap:
                             prefix = '# %s ' % header
                             if line.startswith(prefix):
-                                data[key] = line[len(prefix):]
+                                data[key] = line[len(prefix) :]
                                 ui.debug('%s: %s\n' % (header, data[key]))
                     else:
                         hgpatchheader = False
@@ -319,6 +332,7 @@
 
     return data
 
+
 class patchmeta(object):
     """Patched file metadata
 
@@ -329,6 +343,7 @@
     'islink' is True if the file is a symlink and 'isexec' is True if
     the file is executable. Otherwise, 'mode' is None.
     """
+
     def __init__(self, path):
         self.path = path
         self.oldpath = None
@@ -365,6 +380,7 @@
     def __repr__(self):
         return r"<patchmeta %s %r>" % (self.op, self.path)
 
+
 def readgitpatch(lr):
     """extract git-style metadata about patches from <patchname>"""
 
@@ -409,6 +425,7 @@
 
     return gitpatches
 
+
 class linereader(object):
     # simple class to allow pushing lines back into the input stream
     def __init__(self, fp):
@@ -429,6 +446,7 @@
     def __iter__(self):
         return iter(self.readline, '')
 
+
 class abstractbackend(object):
     def __init__(self, ui):
         self.ui = ui
@@ -463,6 +481,7 @@
     def close(self):
         raise NotImplementedError
 
+
 class fsbackend(abstractbackend):
     def __init__(self, ui, basedir):
         super(fsbackend, self).__init__(ui)
@@ -504,8 +523,9 @@
     def writerej(self, fname, failed, total, lines):
         fname = fname + ".rej"
         self.ui.warn(
-            _("%d out of %d hunks FAILED -- saving rejects to file %s\n") %
-            (failed, total, fname))
+            _("%d out of %d hunks FAILED -- saving rejects to file %s\n")
+            % (failed, total, fname)
+        )
         fp = self.opener(fname, 'w')
         fp.writelines(lines)
         fp.close()
@@ -513,6 +533,7 @@
     def exists(self, fname):
         return self.opener.lexists(fname)
 
+
 class workingbackend(fsbackend):
     def __init__(self, ui, repo, similarity):
         super(workingbackend, self).__init__(ui, repo.root)
@@ -557,6 +578,7 @@
             scmutil.marktouched(self.repo, changed, self.similarity)
         return sorted(self.changed)
 
+
 class filestore(object):
     def __init__(self, maxsize=None):
         self.opener = None
@@ -564,7 +586,7 @@
         self.created = 0
         self.maxsize = maxsize
         if self.maxsize is None:
-            self.maxsize = 4*(2**20)
+            self.maxsize = 4 * (2 ** 20)
         self.size = 0
         self.data = {}
 
@@ -594,6 +616,7 @@
         if self.opener:
             shutil.rmtree(self.opener.base)
 
+
 class repobackend(abstractbackend):
     def __init__(self, ui, repo, ctx, store):
         super(repobackend, self).__init__(ui)
@@ -636,11 +659,13 @@
     def close(self):
         return self.changed | self.removed
 
+
 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
 unidesc = re.compile(br'@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@')
 contextdesc = re.compile(br'(?:---|\*\*\*) (\d+)(?:,(\d+))? (?:---|\*\*\*)')
 eolmodes = ['strict', 'crlf', 'lf', 'auto']
 
+
 class patchfile(object):
     def __init__(self, ui, gp, backend, store, eolmode='strict'):
         self.fname = gp.path
@@ -686,8 +711,12 @@
                 self.mode = (False, False)
         if self.missing:
             self.ui.warn(_("unable to find '%s' for patching\n") % self.fname)
-            self.ui.warn(_("(use '--prefix' to apply patch relative to the "
-                           "current directory)\n"))
+            self.ui.warn(
+                _(
+                    "(use '--prefix' to apply patch relative to the "
+                    "current directory)\n"
+                )
+            )
 
         self.hash = {}
         self.dirty = 0
@@ -727,7 +756,6 @@
         else:
             self.ui.note(s)
 
-
     def findlines(self, l, linenum):
         # looks through the hash and finds candidate lines.  The
         # result is a list of line numbers sorted based on distance
@@ -757,9 +785,10 @@
 
     def apply(self, h):
         if not h.complete():
-            raise PatchError(_("bad hunk #%d %s (%d %d %d %d)") %
-                            (h.number, h.desc, len(h.a), h.lena, len(h.b),
-                            h.lenb))
+            raise PatchError(
+                _("bad hunk #%d %s (%d %d %d %d)")
+                % (h.number, h.desc, len(h.a), h.lena, len(h.b), h.lenb)
+            )
 
         self.hunks += 1
 
@@ -769,8 +798,10 @@
 
         if self.exists and self.create:
             if self.copysource:
-                self.ui.warn(_("cannot create %s: destination already "
-                               "exists\n") % self.fname)
+                self.ui.warn(
+                    _("cannot create %s: destination already " "exists\n")
+                    % self.fname
+                )
             else:
                 self.ui.warn(_("file %s already exists\n") % self.fname)
             self.rej.append(h)
@@ -787,8 +818,11 @@
             return 0
 
         horig = h
-        if (self.eolmode in ('crlf', 'lf')
-            or self.eolmode == 'auto' and self.eol):
+        if (
+            self.eolmode in ('crlf', 'lf')
+            or self.eolmode == 'auto'
+            and self.eol
+        ):
             # If new eols are going to be normalized, then normalize
             # hunk data before patching. Otherwise, preserve input
             # line-endings.
@@ -805,7 +839,7 @@
             if self.remove:
                 self.backend.unlink(self.fname)
             else:
-                self.lines[oldstart:oldstart + len(old)] = new
+                self.lines[oldstart : oldstart + len(old)] = new
                 self.offset += len(new) - len(old)
                 self.dirty = True
             return 0
@@ -835,15 +869,20 @@
                         self.dirty = True
                         offset = l - orig_start - fuzzlen
                         if fuzzlen:
-                            msg = _("Hunk #%d succeeded at %d "
-                                    "with fuzz %d "
-                                    "(offset %d lines).\n")
+                            msg = _(
+                                "Hunk #%d succeeded at %d "
+                                "with fuzz %d "
+                                "(offset %d lines).\n"
+                            )
                             self.printfile(True)
-                            self.ui.warn(msg %
-                                (h.number, l + 1, fuzzlen, offset))
+                            self.ui.warn(
+                                msg % (h.number, l + 1, fuzzlen, offset)
+                            )
                         else:
-                            msg = _("Hunk #%d succeeded at %d "
-                                    "(offset %d lines).\n")
+                            msg = _(
+                                "Hunk #%d succeeded at %d "
+                                "(offset %d lines).\n"
+                            )
                             self.ui.note(msg % (h.number, l + 1, offset))
                         return fuzzlen
         self.printfile(True)
@@ -857,9 +896,11 @@
         self.write_rej()
         return len(self.rej)
 
+
 class header(object):
     """patch header
     """
+
     diffgit_re = re.compile('diff --git a/(.*) b/(.*)$')
     diff_re = re.compile('diff -r .* (.*)$')
     allhunks_re = re.compile('(?:index|deleted file) ')
@@ -885,9 +926,13 @@
                     fp.write(_('this is a binary file\n'))
                 break
             if h.startswith('---'):
-                fp.write(_('%d hunks, %d lines changed\n') %
-                         (len(self.hunks),
-                          sum([max(h.added, h.removed) for h in self.hunks])))
+                fp.write(
+                    _('%d hunks, %d lines changed\n')
+                    % (
+                        len(self.hunks),
+                        sum([max(h.added, h.removed) for h in self.hunks]),
+                    )
+                )
                 break
             fp.write(h)
 
@@ -926,8 +971,10 @@
         # if they have some content as we want to be able to change it
         nocontent = len(self.header) == 2
         emptynewfile = self.isnewfile() and nocontent
-        return (emptynewfile
-                or any(self.special_re.match(h) for h in self.header))
+        return emptynewfile or any(
+            self.special_re.match(h) for h in self.header
+        )
+
 
 class recordhunk(object):
     """patch hunk
@@ -935,8 +982,17 @@
     XXX shouldn't we merge this with the other hunk class?
     """
 
-    def __init__(self, header, fromline, toline, proc, before, hunk, after,
-                 maxcontext=None):
+    def __init__(
+        self,
+        header,
+        fromline,
+        toline,
+        proc,
+        before,
+        hunk,
+        after,
+        maxcontext=None,
+    ):
         def trimcontext(lines, reverse=False):
             if maxcontext is not None:
                 delta = len(lines) - maxcontext
@@ -960,16 +1016,22 @@
         if not isinstance(v, recordhunk):
             return False
 
-        return ((v.hunk == self.hunk) and
-                (v.proc == self.proc) and
-                (self.fromline == v.fromline) and
-                (self.header.files() == v.header.files()))
+        return (
+            (v.hunk == self.hunk)
+            and (v.proc == self.proc)
+            and (self.fromline == v.fromline)
+            and (self.header.files() == v.header.files())
+        )
 
     def __hash__(self):
-        return hash((tuple(self.hunk),
-            tuple(self.header.files()),
-            self.fromline,
-            self.proc))
+        return hash(
+            (
+                tuple(self.hunk),
+                tuple(self.header.files()),
+                self.fromline,
+                self.proc,
+            )
+        )
 
     def countchanges(self, hunk):
         """hunk -> (n+,n-)"""
@@ -986,8 +1048,15 @@
         """
         m = {'+': '-', '-': '+', '\\': '\\'}
         hunk = ['%s%s' % (m[l[0:1]], l[1:]) for l in self.hunk]
-        return recordhunk(self.header, self.toline, self.fromline, self.proc,
-                          self.before, hunk, self.after)
+        return recordhunk(
+            self.header,
+            self.toline,
+            self.fromline,
+            self.proc,
+            self.before,
+            hunk,
+            self.after,
+        )
 
     def write(self, fp):
         delta = len(self.before) + len(self.after)
@@ -995,9 +1064,16 @@
             delta -= 1
         fromlen = delta + self.removed
         tolen = delta + self.added
-        fp.write('@@ -%d,%d +%d,%d @@%s\n' %
-                 (self.fromline, fromlen, self.toline, tolen,
-                  self.proc and (' ' + self.proc)))
+        fp.write(
+            '@@ -%d,%d +%d,%d @@%s\n'
+            % (
+                self.fromline,
+                fromlen,
+                self.toline,
+                tolen,
+                self.proc and (' ' + self.proc),
+            )
+        )
         fp.write(''.join(self.before + self.hunk + self.after))
 
     pretty = write
@@ -1008,6 +1084,7 @@
     def __repr__(self):
         return '<hunk %r@%d>' % (self.filename(), self.fromline)
 
+
 def getmessages():
     return {
         'multiple': {
@@ -1023,49 +1100,58 @@
             'record': _("record this change to '%s'?"),
         },
         'help': {
-            'apply': _('[Ynesfdaq?]'
-                         '$$ &Yes, apply this change'
-                         '$$ &No, skip this change'
-                         '$$ &Edit this change manually'
-                         '$$ &Skip remaining changes to this file'
-                         '$$ Apply remaining changes to this &file'
-                         '$$ &Done, skip remaining changes and files'
-                         '$$ Apply &all changes to all remaining files'
-                         '$$ &Quit, applying no changes'
-                         '$$ &? (display help)'),
-            'discard': _('[Ynesfdaq?]'
-                         '$$ &Yes, discard this change'
-                         '$$ &No, skip this change'
-                         '$$ &Edit this change manually'
-                         '$$ &Skip remaining changes to this file'
-                         '$$ Discard remaining changes to this &file'
-                         '$$ &Done, skip remaining changes and files'
-                         '$$ Discard &all changes to all remaining files'
-                         '$$ &Quit, discarding no changes'
-                         '$$ &? (display help)'),
-            'keep': _('[Ynesfdaq?]'
-                         '$$ &Yes, keep this change'
-                         '$$ &No, skip this change'
-                         '$$ &Edit this change manually'
-                         '$$ &Skip remaining changes to this file'
-                         '$$ Keep remaining changes to this &file'
-                         '$$ &Done, skip remaining changes and files'
-                         '$$ Keep &all changes to all remaining files'
-                         '$$ &Quit, keeping all changes'
-                         '$$ &? (display help)'),
-            'record': _('[Ynesfdaq?]'
-                        '$$ &Yes, record this change'
-                        '$$ &No, skip this change'
-                        '$$ &Edit this change manually'
-                        '$$ &Skip remaining changes to this file'
-                        '$$ Record remaining changes to this &file'
-                        '$$ &Done, skip remaining changes and files'
-                        '$$ Record &all changes to all remaining files'
-                        '$$ &Quit, recording no changes'
-                        '$$ &? (display help)'),
-        }
+            'apply': _(
+                '[Ynesfdaq?]'
+                '$$ &Yes, apply this change'
+                '$$ &No, skip this change'
+                '$$ &Edit this change manually'
+                '$$ &Skip remaining changes to this file'
+                '$$ Apply remaining changes to this &file'
+                '$$ &Done, skip remaining changes and files'
+                '$$ Apply &all changes to all remaining files'
+                '$$ &Quit, applying no changes'
+                '$$ &? (display help)'
+            ),
+            'discard': _(
+                '[Ynesfdaq?]'
+                '$$ &Yes, discard this change'
+                '$$ &No, skip this change'
+                '$$ &Edit this change manually'
+                '$$ &Skip remaining changes to this file'
+                '$$ Discard remaining changes to this &file'
+                '$$ &Done, skip remaining changes and files'
+                '$$ Discard &all changes to all remaining files'
+                '$$ &Quit, discarding no changes'
+                '$$ &? (display help)'
+            ),
+            'keep': _(
+                '[Ynesfdaq?]'
+                '$$ &Yes, keep this change'
+                '$$ &No, skip this change'
+                '$$ &Edit this change manually'
+                '$$ &Skip remaining changes to this file'
+                '$$ Keep remaining changes to this &file'
+                '$$ &Done, skip remaining changes and files'
+                '$$ Keep &all changes to all remaining files'
+                '$$ &Quit, keeping all changes'
+                '$$ &? (display help)'
+            ),
+            'record': _(
+                '[Ynesfdaq?]'
+                '$$ &Yes, record this change'
+                '$$ &No, skip this change'
+                '$$ &Edit this change manually'
+                '$$ &Skip remaining changes to this file'
+                '$$ Record remaining changes to this &file'
+                '$$ &Done, skip remaining changes and files'
+                '$$ Record &all changes to all remaining files'
+                '$$ &Quit, recording no changes'
+                '$$ &? (display help)'
+            ),
+        },
     }
 
+
 def filterpatch(ui, headers, match, operation=None):
     """Interactively filter patch chunks into applied-only chunks"""
     messages = getmessages()
@@ -1094,15 +1180,15 @@
             # chars is a good target) because of issue6158.
             r = ui.promptchoice("%s\n(enter ? for help) %s" % (query, resps))
             ui.write("\n")
-            if r == 8: # ?
+            if r == 8:  # ?
                 for c, t in ui.extractchoices(resps)[1]:
                     ui.write('%s - %s\n' % (c, encoding.lower(t)))
                 continue
-            elif r == 0: # yes
+            elif r == 0:  # yes
                 ret = True
-            elif r == 1: # no
+            elif r == 1:  # no
                 ret = False
-            elif r == 2: # Edit patch
+            elif r == 2:  # Edit patch
                 if chunk is None:
                     ui.write(_('cannot edit patch for whole file'))
                     ui.write("\n")
@@ -1113,7 +1199,8 @@
                     continue
                 # Patch comment based on the Git one (based on comment at end of
                 # https://mercurial-scm.org/wiki/RecordExtension)
-                phelp = '---' + _("""
+                phelp = '---' + _(
+                    """
 To remove '-' lines, make them ' ' lines (context).
 To remove '+' lines, delete them.
 Lines starting with # will be removed from the patch.
@@ -1123,23 +1210,28 @@
 file will be generated: you can use that when you try again. If
 all lines of the hunk are removed, then the edit is aborted and
 the hunk is left unchanged.
-""")
-                (patchfd, patchfn) = pycompat.mkstemp(prefix="hg-editor-",
-                                                      suffix=".diff")
+"""
+                )
+                (patchfd, patchfn) = pycompat.mkstemp(
+                    prefix="hg-editor-", suffix=".diff"
+                )
                 ncpatchfp = None
                 try:
                     # Write the initial patch
                     f = util.nativeeolwriter(os.fdopen(patchfd, r'wb'))
                     chunk.header.write(f)
                     chunk.write(f)
-                    f.write(''.join(['# ' + i + '\n'
-                                     for i in phelp.splitlines()]))
+                    f.write(
+                        ''.join(['# ' + i + '\n' for i in phelp.splitlines()])
+                    )
                     f.close()
                     # Start the editor and wait for it to complete
                     editor = ui.geteditor()
-                    ret = ui.system("%s \"%s\"" % (editor, patchfn),
-                                    environ={'HGUSER': ui.username()},
-                                    blockedtag='filterpatch')
+                    ret = ui.system(
+                        "%s \"%s\"" % (editor, patchfn),
+                        environ={'HGUSER': ui.username()},
+                        blockedtag='filterpatch',
+                    )
                     if ret != 0:
                         ui.warn(_("editor exited with exit code %d\n") % ret)
                         continue
@@ -1159,20 +1251,20 @@
                 # Signal that the chunk shouldn't be applied as-is, but
                 # provide the new patch to be used instead.
                 ret = False
-            elif r == 3: # Skip
+            elif r == 3:  # Skip
                 ret = skipfile = False
-            elif r == 4: # file (Record remaining)
+            elif r == 4:  # file (Record remaining)
                 ret = skipfile = True
-            elif r == 5: # done, skip remaining
+            elif r == 5:  # done, skip remaining
                 ret = skipall = False
-            elif r == 6: # all
+            elif r == 6:  # all
                 ret = skipall = True
-            elif r == 7: # quit
+            elif r == 7:  # quit
                 raise error.Abort(_('user quit'))
             return ret, skipfile, skipall, newpatches
 
     seen = set()
-    applied = {}        # 'filename' -> [] of chunks
+    applied = {}  # 'filename' -> [] of chunks
     skipfile, skipall = None, None
     pos, total = 1, sum(len(h.hunks) for h in headers)
     for h in headers:
@@ -1186,8 +1278,9 @@
         if skipall is None:
             h.pretty(ui)
         files = h.files()
-        msg = (_('examine changes to %s?') %
-               _(' and ').join("'%s'" % f for f in files))
+        msg = _('examine changes to %s?') % _(' and ').join(
+            "'%s'" % f for f in files
+        )
         if all(match.exact(f) for f in files):
             r, skipall, np = True, None, None
         else:
@@ -1205,10 +1298,14 @@
                 msg = messages['single'][operation] % chunk.filename()
             else:
                 idx = pos - len(h.hunks) + i
-                msg = messages['multiple'][operation] % (idx, total,
-                                                         chunk.filename())
-            r, skipfile, skipall, newpatches = prompt(skipfile,
-                    skipall, msg, chunk)
+                msg = messages['multiple'][operation] % (
+                    idx,
+                    total,
+                    chunk.filename(),
+                )
+            r, skipfile, skipall, newpatches = prompt(
+                skipfile, skipall, msg, chunk
+            )
             if r:
                 if fixoffset:
                     chunk = copy.copy(chunk)
@@ -1222,8 +1319,15 @@
                         applied[newhunk.filename()].append(newhunk)
             else:
                 fixoffset += chunk.removed - chunk.added
-    return (sum([h for h in applied.itervalues()
-               if h[0].special() or len(h) > 1], []), {})
+    return (
+        sum(
+            [h for h in applied.itervalues() if h[0].special() or len(h) > 1],
+            [],
+        ),
+        {},
+    )
+
+
 class hunk(object):
     def __init__(self, desc, num, lr, context):
         self.number = num
@@ -1279,8 +1383,9 @@
         self.starta = int(self.starta)
         self.startb = int(self.startb)
         try:
-            diffhelper.addlines(lr, self.hunk, self.lena, self.lenb,
-                                self.a, self.b)
+            diffhelper.addlines(
+                lr, self.hunk, self.lena, self.lenb, self.a, self.b
+            )
         except error.ParseError as e:
             raise PatchError(_("bad hunk #%d: %s") % (self.number, e))
         # if we hit eof before finishing out the hunk, the last line will
@@ -1317,8 +1422,9 @@
             elif l.startswith('  '):
                 u = ' ' + s
             else:
-                raise PatchError(_("bad hunk #%d old text line %d") %
-                                 (self.number, x))
+                raise PatchError(
+                    _("bad hunk #%d old text line %d") % (self.number, x)
+                )
             self.a.append(u)
             self.hunk.append(u)
 
@@ -1363,8 +1469,9 @@
                 lr.push(l)
                 break
             else:
-                raise PatchError(_("bad hunk #%d old text line %d") %
-                                 (self.number, x))
+                raise PatchError(
+                    _("bad hunk #%d old text line %d") % (self.number, x)
+                )
             self.b.append(s)
             while True:
                 if hunki >= len(self.hunk):
@@ -1391,8 +1498,12 @@
                 if x.startswith('+') or x.startswith(' '):
                     self.b.append(x[1:])
         # @@ -start,len +start,len @@
-        self.desc = "@@ -%d,%d +%d,%d @@\n" % (self.starta, self.lena,
-                                             self.startb, self.lenb)
+        self.desc = "@@ -%d,%d +%d,%d @@\n" % (
+            self.starta,
+            self.lena,
+            self.startb,
+            self.lenb,
+        )
         self.hunk[0] = self.desc
         self._fixnewline(lr)
 
@@ -1430,7 +1541,7 @@
 
             bot = min(fuzz, bot)
             top = min(fuzz, top)
-            return old[top:len(old) - bot], new[top:len(new) - bot], top
+            return old[top : len(old) - bot], new[top : len(new) - bot], top
         return old, new, 0
 
     def fuzzit(self, fuzz, toponly):
@@ -1444,8 +1555,10 @@
             newstart -= 1
         return old, oldstart, new, newstart
 
+
 class binhunk(object):
     'A binary patch file.'
+
     def __init__(self, lr, fname):
         self.text = None
         self.delta = False
@@ -1470,8 +1583,9 @@
         while True:
             line = getline(lr, self.hunk)
             if not line:
-                raise PatchError(_('could not extract "%s" binary data')
-                                 % self._fname)
+                raise PatchError(
+                    _('could not extract "%s" binary data') % self._fname
+                )
             if line.startswith('literal '):
                 size = int(line[8:].rstrip())
                 break
@@ -1490,15 +1604,20 @@
             try:
                 dec.append(util.b85decode(line[1:])[:l])
             except ValueError as e:
-                raise PatchError(_('could not decode "%s" binary patch: %s')
-                                 % (self._fname, stringutil.forcebytestr(e)))
+                raise PatchError(
+                    _('could not decode "%s" binary patch: %s')
+                    % (self._fname, stringutil.forcebytestr(e))
+                )
             line = getline(lr, self.hunk)
         text = zlib.decompress(''.join(dec))
         if len(text) != size:
-            raise PatchError(_('"%s" length is %d bytes, should be %d')
-                             % (self._fname, len(text), size))
+            raise PatchError(
+                _('"%s" length is %d bytes, should be %d')
+                % (self._fname, len(text), size)
+            )
         self.text = text
 
+
 def parsefilename(str):
     # --- filename \t|space stuff
     s = str[4:].rstrip('\r\n')
@@ -1509,6 +1628,7 @@
             return s
     return s[:i]
 
+
 def reversehunks(hunks):
     '''reverse the signs in the hunks given as argument
 
@@ -1572,6 +1692,7 @@
         newhunks.append(c)
     return newhunks
 
+
 def parsepatch(originalchunks, maxcontext=None):
     """patch -> [] of headers -> [] of hunks
 
@@ -1615,8 +1736,10 @@
      8
     +9
     """
+
     class parser(object):
         """patch parsing state machine"""
+
         def __init__(self):
             self.fromline = 0
             self.toline = 0
@@ -1636,8 +1759,16 @@
 
         def addcontext(self, context):
             if self.hunk:
-                h = recordhunk(self.header, self.fromline, self.toline,
-                        self.proc, self.before, self.hunk, context, maxcontext)
+                h = recordhunk(
+                    self.header,
+                    self.fromline,
+                    self.toline,
+                    self.proc,
+                    self.before,
+                    self.hunk,
+                    context,
+                    maxcontext,
+                )
                 self.header.hunks.append(h)
                 self.fromline += len(self.before) + h.removed
                 self.toline += len(self.before) + h.added
@@ -1660,28 +1791,29 @@
             self.header = h
 
         def addother(self, line):
-            pass # 'other' lines are ignored
+            pass  # 'other' lines are ignored
 
         def finished(self):
             self.addcontext([])
             return self.headers
 
         transitions = {
-            'file': {'context': addcontext,
-                     'file': newfile,
-                     'hunk': addhunk,
-                     'range': addrange},
-            'context': {'file': newfile,
-                        'hunk': addhunk,
-                        'range': addrange,
-                        'other': addother},
-            'hunk': {'context': addcontext,
-                     'file': newfile,
-                     'range': addrange},
-            'range': {'context': addcontext,
-                      'hunk': addhunk},
+            'file': {
+                'context': addcontext,
+                'file': newfile,
+                'hunk': addhunk,
+                'range': addrange,
+            },
+            'context': {
+                'file': newfile,
+                'hunk': addhunk,
+                'range': addrange,
+                'other': addother,
+            },
+            'hunk': {'context': addcontext, 'file': newfile, 'range': addrange},
+            'range': {'context': addcontext, 'hunk': addhunk},
             'other': {'other': addother},
-            }
+        }
 
     p = parser()
     fp = stringio()
@@ -1693,12 +1825,14 @@
         try:
             p.transitions[state][newstate](p, data)
         except KeyError:
-            raise PatchError('unhandled transition: %s -> %s' %
-                                   (state, newstate))
+            raise PatchError(
+                'unhandled transition: %s -> %s' % (state, newstate)
+            )
         state = newstate
     del fp
     return p.finished()
 
+
 def pathtransform(path, strip, prefix):
     '''turn a path from a patch into a path suitable for the repository
 
@@ -1728,15 +1862,18 @@
     while count > 0:
         i = path.find('/', i)
         if i == -1:
-            raise PatchError(_("unable to strip away %d of %d dirs from %s") %
-                             (count, strip, path))
+            raise PatchError(
+                _("unable to strip away %d of %d dirs from %s")
+                % (count, strip, path)
+            )
         i += 1
         # consume '//' in the path
-        while i < pathlen - 1 and path[i:i + 1] == '/':
+        while i < pathlen - 1 and path[i : i + 1] == '/':
             i += 1
         count -= 1
     return path[:i].lstrip(), prefix + path[i:].rstrip()
 
+
 def makepatchmeta(backend, afile_orig, bfile_orig, hunk, strip, prefix):
     nulla = afile_orig == "/dev/null"
     nullb = bfile_orig == "/dev/null"
@@ -1753,17 +1890,22 @@
 
     # some diff programs apparently produce patches where the afile is
     # not /dev/null, but afile starts with bfile
-    abasedir = afile[:afile.rfind('/') + 1]
-    bbasedir = bfile[:bfile.rfind('/') + 1]
-    if (missing and abasedir == bbasedir and afile.startswith(bfile)
-        and hunk.starta == 0 and hunk.lena == 0):
+    abasedir = afile[: afile.rfind('/') + 1]
+    bbasedir = bfile[: bfile.rfind('/') + 1]
+    if (
+        missing
+        and abasedir == bbasedir
+        and afile.startswith(bfile)
+        and hunk.starta == 0
+        and hunk.lena == 0
+    ):
         create = True
         missing = False
 
     # If afile is "a/b/foo" and bfile is "a/b/foo.orig" we assume the
     # diff is between a file and its backup. In this case, the original
     # file should be patched (see original mpatch code).
-    isbackup = (abase == bbase and bfile.startswith(afile))
+    isbackup = abase == bbase and bfile.startswith(afile)
     fname = None
     if not missing:
         if gooda and goodb:
@@ -1792,6 +1934,7 @@
         gp.op = 'DELETE'
     return gp
 
+
 def scanpatch(fp):
     """like patch.iterhunks, but yield different events
 
@@ -1816,9 +1959,11 @@
 
     for line in iter(lr.readline, ''):
         if line.startswith('diff --git a/') or line.startswith('diff -r '):
+
             def notheader(line):
                 s = line.split(None, 1)
                 return not s or s[0] not in ('---', 'diff')
+
             header = scanwhile(line, notheader)
             fromfile = lr.readline()
             if fromfile.startswith('---'):
@@ -1840,6 +1985,7 @@
             else:
                 yield 'other', line
 
+
 def scangitpatch(lr, firstline):
     """
     Git patches can emit:
@@ -1866,6 +2012,7 @@
     fp.seek(pos)
     return gitpatches
 
+
 def iterhunks(fp):
     """Read a patch and yield the following events:
     - ("file", afile, bfile, firsthunk): select a new target file.
@@ -1890,10 +2037,10 @@
         if state == BFILE and (
             (not context and x.startswith('@'))
             or (context is not False and x.startswith('***************'))
-            or x.startswith('GIT binary patch')):
+            or x.startswith('GIT binary patch')
+        ):
             gp = None
-            if (gitpatches and
-                gitpatches[-1].ispatching(afile, bfile)):
+            if gitpatches and gitpatches[-1].ispatching(afile, bfile):
                 gp = gitpatches.pop()
             if x.startswith('GIT binary patch'):
                 h = binhunk(lr, gp.path)
@@ -1913,8 +2060,9 @@
             if gitpatches is None:
                 # scan whole input for git metadata
                 gitpatches = scangitpatch(lr, x)
-                yield 'git', [g.copy() for g in gitpatches
-                              if g.op in ('COPY', 'RENAME')]
+                yield 'git', [
+                    g.copy() for g in gitpatches if g.op in ('COPY', 'RENAME')
+                ]
                 gitpatches.reverse()
             afile = 'a/' + m.group(1)
             bfile = 'b/' + m.group(2)
@@ -1922,8 +2070,9 @@
                 gp = gitpatches.pop()
                 yield 'file', ('a/' + gp.path, 'b/' + gp.path, None, gp.copy())
             if not gitpatches:
-                raise PatchError(_('failed to synchronize metadata for "%s"')
-                                 % afile[2:])
+                raise PatchError(
+                    _('failed to synchronize metadata for "%s"') % afile[2:]
+                )
             newfile = True
         elif x.startswith('---'):
             # check for a unified diff
@@ -1961,10 +2110,12 @@
         gp = gitpatches.pop()
         yield 'file', ('a/' + gp.path, 'b/' + gp.path, None, gp.copy())
 
+
 def applybindelta(binchunk, data):
     """Apply a binary delta hunk
     The algorithm used is the algorithm from git's patch-delta.c
     """
+
     def deltahead(binchunk):
         i = 0
         for c in pycompat.bytestr(binchunk):
@@ -1972,6 +2123,7 @@
             if not (ord(c) & 0x80):
                 return i
         return i
+
     out = ""
     s = deltahead(binchunk)
     binchunk = binchunk[s:]
@@ -1979,31 +2131,31 @@
     binchunk = binchunk[s:]
     i = 0
     while i < len(binchunk):
-        cmd = ord(binchunk[i:i + 1])
+        cmd = ord(binchunk[i : i + 1])
         i += 1
-        if (cmd & 0x80):
+        if cmd & 0x80:
             offset = 0
             size = 0
-            if (cmd & 0x01):
-                offset = ord(binchunk[i:i + 1])
+            if cmd & 0x01:
+                offset = ord(binchunk[i : i + 1])
                 i += 1
-            if (cmd & 0x02):
-                offset |= ord(binchunk[i:i + 1]) << 8
+            if cmd & 0x02:
+                offset |= ord(binchunk[i : i + 1]) << 8
                 i += 1
-            if (cmd & 0x04):
-                offset |= ord(binchunk[i:i + 1]) << 16
+            if cmd & 0x04:
+                offset |= ord(binchunk[i : i + 1]) << 16
                 i += 1
-            if (cmd & 0x08):
-                offset |= ord(binchunk[i:i + 1]) << 24
+            if cmd & 0x08:
+                offset |= ord(binchunk[i : i + 1]) << 24
                 i += 1
-            if (cmd & 0x10):
-                size = ord(binchunk[i:i + 1])
+            if cmd & 0x10:
+                size = ord(binchunk[i : i + 1])
                 i += 1
-            if (cmd & 0x20):
-                size |= ord(binchunk[i:i + 1]) << 8
+            if cmd & 0x20:
+                size |= ord(binchunk[i : i + 1]) << 8
                 i += 1
-            if (cmd & 0x40):
-                size |= ord(binchunk[i:i + 1]) << 16
+            if cmd & 0x40:
+                size |= ord(binchunk[i : i + 1]) << 16
                 i += 1
             if size == 0:
                 size = 0x10000
@@ -2017,6 +2169,7 @@
             raise PatchError(_('unexpected delta opcode 0'))
     return out
 
+
 def applydiff(ui, fp, backend, store, strip=1, prefix='', eolmode='strict'):
     """Reads a patch from fp and tries to apply it.
 
@@ -2027,8 +2180,17 @@
     read in binary mode. Otherwise, line endings are ignored when
     patching then normalized according to 'eolmode'.
     """
-    return _applydiff(ui, fp, patchfile, backend, store, strip=strip,
-                      prefix=prefix, eolmode=eolmode)
+    return _applydiff(
+        ui,
+        fp,
+        patchfile,
+        backend,
+        store,
+        strip=strip,
+        prefix=prefix,
+        eolmode=eolmode,
+    )
+
 
 def _canonprefix(repo, prefix):
     if prefix:
@@ -2037,9 +2199,12 @@
             prefix += '/'
     return prefix
 
-def _applydiff(ui, fp, patcher, backend, store, strip=1, prefix='',
-               eolmode='strict'):
+
+def _applydiff(
+    ui, fp, patcher, backend, store, strip=1, prefix='', eolmode='strict'
+):
     prefix = _canonprefix(backend.repo, prefix)
+
     def pstrip(p):
         return pathtransform(p, strip - 1, prefix)[1]
 
@@ -2064,8 +2229,9 @@
                 if gp.oldpath:
                     gp.oldpath = pstrip(gp.oldpath)
             else:
-                gp = makepatchmeta(backend, afile, bfile, first_hunk, strip,
-                                   prefix)
+                gp = makepatchmeta(
+                    backend, afile, bfile, first_hunk, strip, prefix
+                )
             if gp.op == 'RENAME':
                 backend.unlink(gp.oldpath)
             if not first_hunk:
@@ -2077,8 +2243,9 @@
                     data, mode = store.getfile(gp.oldpath)[:2]
                     if data is None:
                         # This means that the old path does not exist
-                        raise PatchError(_("source file '%s' does not exist")
-                                           % gp.oldpath)
+                        raise PatchError(
+                            _("source file '%s' does not exist") % gp.oldpath
+                        )
                 if gp.mode:
                     mode = gp.mode
                     if gp.op == 'ADD':
@@ -2086,15 +2253,17 @@
                         # must be created
                         data = ''
                 if data or mode:
-                    if (gp.op in ('ADD', 'RENAME', 'COPY')
-                        and backend.exists(gp.path)):
-                        raise PatchError(_("cannot create %s: destination "
-                                           "already exists") % gp.path)
+                    if gp.op in ('ADD', 'RENAME', 'COPY') and backend.exists(
+                        gp.path
+                    ):
+                        raise PatchError(
+                            _("cannot create %s: destination " "already exists")
+                            % gp.path
+                        )
                     backend.setfile(gp.path, data, mode, gp.oldpath)
                 continue
             try:
-                current_file = patcher(ui, gp, backend, store,
-                                       eolmode=eolmode)
+                current_file = patcher(ui, gp, backend, store, eolmode=eolmode)
             except PatchError as inst:
                 ui.warn(str(inst) + '\n')
                 current_file = None
@@ -2122,8 +2291,8 @@
         return -1
     return err
 
-def _externalpatch(ui, repo, patcher, patchname, strip, files,
-                   similarity):
+
+def _externalpatch(ui, repo, patcher, patchname, strip, files, similarity):
     """use <patcher> to apply <patchname> to the working directory.
     returns whether patch was applied with fuzz factor."""
 
@@ -2132,8 +2301,12 @@
     cwd = repo.root
     if cwd:
         args.append('-d %s' % procutil.shellquote(cwd))
-    cmd = ('%s %s -p%d < %s'
-           % (patcher, ' '.join(args), strip, procutil.shellquote(patchname)))
+    cmd = '%s %s -p%d < %s' % (
+        patcher,
+        ' '.join(args),
+        strip,
+        procutil.shellquote(patchname),
+    )
     ui.debug('Using external patch tool: %s\n' % cmd)
     fp = procutil.popen(cmd, 'rb')
     try:
@@ -2162,12 +2335,15 @@
             scmutil.marktouched(repo, files, similarity)
     code = fp.close()
     if code:
-        raise PatchError(_("patch command failed: %s") %
-                         procutil.explainexit(code))
+        raise PatchError(
+            _("patch command failed: %s") % procutil.explainexit(code)
+        )
     return fuzz
 
-def patchbackend(ui, backend, patchobj, strip, prefix, files=None,
-                 eolmode='strict'):
+
+def patchbackend(
+    ui, backend, patchobj, strip, prefix, files=None, eolmode='strict'
+):
     if files is None:
         files = set()
     if eolmode is None:
@@ -2182,8 +2358,9 @@
     except TypeError:
         fp = patchobj
     try:
-        ret = applydiff(ui, fp, backend, store, strip=strip, prefix=prefix,
-                        eolmode=eolmode)
+        ret = applydiff(
+            ui, fp, backend, store, strip=strip, prefix=prefix, eolmode=eolmode
+        )
     finally:
         if fp != patchobj:
             fp.close()
@@ -2193,20 +2370,40 @@
         raise PatchError(_('patch failed to apply'))
     return ret > 0
 
-def internalpatch(ui, repo, patchobj, strip, prefix='', files=None,
-                  eolmode='strict', similarity=0):
+
+def internalpatch(
+    ui,
+    repo,
+    patchobj,
+    strip,
+    prefix='',
+    files=None,
+    eolmode='strict',
+    similarity=0,
+):
     """use builtin patch to apply <patchobj> to the working directory.
     returns whether patch was applied with fuzz factor."""
     backend = workingbackend(ui, repo, similarity)
     return patchbackend(ui, backend, patchobj, strip, prefix, files, eolmode)
 
-def patchrepo(ui, repo, ctx, store, patchobj, strip, prefix, files=None,
-              eolmode='strict'):
+
+def patchrepo(
+    ui, repo, ctx, store, patchobj, strip, prefix, files=None, eolmode='strict'
+):
     backend = repobackend(ui, repo, ctx, store)
     return patchbackend(ui, backend, patchobj, strip, prefix, files, eolmode)
 
-def patch(ui, repo, patchname, strip=1, prefix='', files=None, eolmode='strict',
-          similarity=0):
+
+def patch(
+    ui,
+    repo,
+    patchname,
+    strip=1,
+    prefix='',
+    files=None,
+    eolmode='strict',
+    similarity=0,
+):
     """Apply <patchname> to the working directory.
 
     'eolmode' specifies how end of lines should be handled. It can be:
@@ -2222,10 +2419,13 @@
     if files is None:
         files = set()
     if patcher:
-        return _externalpatch(ui, repo, patcher, patchname, strip,
-                              files, similarity)
-    return internalpatch(ui, repo, patchname, strip, prefix, files, eolmode,
-                         similarity)
+        return _externalpatch(
+            ui, repo, patcher, patchname, strip, files, similarity
+        )
+    return internalpatch(
+        ui, repo, patchname, strip, prefix, files, eolmode, similarity
+    )
+
 
 def changedfiles(ui, repo, patchpath, strip=1, prefix=''):
     backend = fsbackend(ui, repo.root)
@@ -2238,11 +2438,13 @@
                 if gp:
                     gp.path = pathtransform(gp.path, strip - 1, prefix)[1]
                     if gp.oldpath:
-                        gp.oldpath = pathtransform(gp.oldpath, strip - 1,
-                                                   prefix)[1]
+                        gp.oldpath = pathtransform(
+                            gp.oldpath, strip - 1, prefix
+                        )[1]
                 else:
-                    gp = makepatchmeta(backend, afile, bfile, first_hunk, strip,
-                                       prefix)
+                    gp = makepatchmeta(
+                        backend, afile, bfile, first_hunk, strip, prefix
+                    )
                 changed.add(gp.path)
                 if gp.op == 'RENAME':
                     changed.add(gp.oldpath)
@@ -2250,16 +2452,29 @@
                 raise error.Abort(_('unsupported parser state: %s') % state)
         return changed
 
+
 class GitDiffRequired(Exception):
     pass
 
+
 diffopts = diffutil.diffallopts
 diffallopts = diffutil.diffallopts
 difffeatureopts = diffutil.difffeatureopts
 
-def diff(repo, node1=None, node2=None, match=None, changes=None,
-         opts=None, losedatafn=None, pathfn=None, copy=None,
-         copysourcematch=None, hunksfilterfn=None):
+
+def diff(
+    repo,
+    node1=None,
+    node2=None,
+    match=None,
+    changes=None,
+    opts=None,
+    losedatafn=None,
+    pathfn=None,
+    copy=None,
+    copysourcematch=None,
+    hunksfilterfn=None,
+):
     '''yields diff of changes to files between two nodes, or node and
     working directory.
 
@@ -2296,15 +2511,24 @@
     ctx2 = repo[node2]
 
     for fctx1, fctx2, hdr, hunks in diffhunks(
-            repo, ctx1=ctx1, ctx2=ctx2, match=match, changes=changes, opts=opts,
-            losedatafn=losedatafn, pathfn=pathfn, copy=copy,
-            copysourcematch=copysourcematch):
+        repo,
+        ctx1=ctx1,
+        ctx2=ctx2,
+        match=match,
+        changes=changes,
+        opts=opts,
+        losedatafn=losedatafn,
+        pathfn=pathfn,
+        copy=copy,
+        copysourcematch=copysourcematch,
+    ):
         if hunksfilterfn is not None:
             # If the file has been removed, fctx2 is None; but this should
             # not occur here since we catch removed files early in
             # logcmdutil.getlinerangerevs() for 'hg log -L'.
-            assert fctx2 is not None, (
-                'fctx2 unexpectly None in diff hunks filtering')
+            assert (
+                fctx2 is not None
+            ), 'fctx2 unexpectly None in diff hunks filtering'
             hunks = hunksfilterfn(fctx2, hunks)
         text = ''.join(sum((list(hlines) for hrange, hlines in hunks), []))
         if hdr and (text or len(hdr) > 1):
@@ -2312,8 +2536,19 @@
         if text:
             yield text
 
-def diffhunks(repo, ctx1, ctx2, match=None, changes=None, opts=None,
-              losedatafn=None, pathfn=None, copy=None, copysourcematch=None):
+
+def diffhunks(
+    repo,
+    ctx1,
+    ctx2,
+    match=None,
+    changes=None,
+    opts=None,
+    losedatafn=None,
+    pathfn=None,
+    copy=None,
+    copysourcematch=None,
+):
     """Yield diff of changes to files in the form of (`header`, `hunks`) tuples
     where `header` is a list of diff headers and `hunks` is an iterable of
     (`hunkrange`, `hunklines`) tuples.
@@ -2327,6 +2562,7 @@
     def lrugetfilectx():
         cache = {}
         order = collections.deque()
+
         def getfilectx(f, ctx):
             fctx = ctx.filectx(f, filelog=cache.get(f))
             if f not in cache:
@@ -2337,7 +2573,9 @@
                 order.remove(f)
             order.append(f)
             return fctx
+
         return getfilectx
+
     getfilectx = lrugetfilectx()
 
     if not changes:
@@ -2361,8 +2599,9 @@
     if copysourcematch:
         # filter out copies where source side isn't inside the matcher
         # (copies.pathcopies() already filtered out the destination)
-        copy = {dst: src for dst, src in copy.iteritems()
-                if copysourcematch(src)}
+        copy = {
+            dst: src for dst, src in copy.iteritems() if copysourcematch(src)
+        }
 
     modifiedset = set(modified)
     addedset = set(added)
@@ -2388,17 +2627,33 @@
             del copy[dst]
 
     prefetchmatch = scmutil.matchfiles(
-        repo, list(modifiedset | addedset | removedset))
+        repo, list(modifiedset | addedset | removedset)
+    )
     scmutil.prefetchfiles(repo, [ctx1.rev(), ctx2.rev()], prefetchmatch)
 
     def difffn(opts, losedata):
-        return trydiff(repo, revs, ctx1, ctx2, modified, added, removed,
-                       copy, getfilectx, opts, losedata, pathfn)
+        return trydiff(
+            repo,
+            revs,
+            ctx1,
+            ctx2,
+            modified,
+            added,
+            removed,
+            copy,
+            getfilectx,
+            opts,
+            losedata,
+            pathfn,
+        )
+
     if opts.upgrade and not opts.git:
         try:
+
             def losedata(fn):
                 if not losedatafn or not losedatafn(fn=fn):
                     raise GitDiffRequired
+
             # Buffer the whole output until we are sure it can be generated
             return list(difffn(opts.copy(git=False), losedata))
         except GitDiffRequired:
@@ -2406,6 +2661,7 @@
     else:
         return difffn(opts, None)
 
+
 def diffsinglehunk(hunklines):
     """yield tokens for a list of lines in a single hunk"""
     for line in hunklines:
@@ -2426,9 +2682,10 @@
                 yield (token, label)
 
         if chompline != stripline:
-            yield (chompline[len(stripline):], 'diff.trailingwhitespace')
+            yield (chompline[len(stripline) :], 'diff.trailingwhitespace')
         if chompline != line:
-            yield (line[len(chompline):], '')
+            yield (line[len(chompline) :], '')
+
 
 def diffsinglehunkinline(hunklines):
     """yield tokens for a list of lines in a single hunk, with inline colors"""
@@ -2467,8 +2724,10 @@
             btokens.append((changed, token))
 
     # yield deleted tokens, then inserted ones
-    for prefix, label, tokens in [('-', 'diff.deleted', atokens),
-                                  ('+', 'diff.inserted', btokens)]:
+    for prefix, label, tokens in [
+        ('-', 'diff.deleted', atokens),
+        ('+', 'diff.inserted', btokens),
+    ]:
         nextisnewline = True
         for changed, token in tokens:
             if nextisnewline:
@@ -2477,12 +2736,12 @@
             # special handling line end
             isendofline = token.endswith('\n')
             if isendofline:
-                chomp = token[:-1] # chomp
+                chomp = token[:-1]  # chomp
                 if chomp.endswith('\r'):
                     chomp = chomp[:-1]
-                endofline = token[len(chomp):]
-                token = chomp.rstrip() # detect spaces at the end
-                endspaces = chomp[len(token):]
+                endofline = token[len(chomp) :]
+                token = chomp.rstrip()  # detect spaces at the end
+                endspaces = chomp[len(token) :]
             # scan tabs
             for maybetab in tabsplitter.findall(token):
                 if b'\t' == maybetab[0:1]:
@@ -2499,29 +2758,34 @@
                 yield (endofline, '')
                 nextisnewline = True
 
+
 def difflabel(func, *args, **kw):
     '''yields 2-tuples of (output, label) based on the output of func()'''
     if kw.get(r'opts') and kw[r'opts'].worddiff:
         dodiffhunk = diffsinglehunkinline
     else:
         dodiffhunk = diffsinglehunk
-    headprefixes = [('diff', 'diff.diffline'),
-                    ('copy', 'diff.extended'),
-                    ('rename', 'diff.extended'),
-                    ('old', 'diff.extended'),
-                    ('new', 'diff.extended'),
-                    ('deleted', 'diff.extended'),
-                    ('index', 'diff.extended'),
-                    ('similarity', 'diff.extended'),
-                    ('---', 'diff.file_a'),
-                    ('+++', 'diff.file_b')]
-    textprefixes = [('@', 'diff.hunk'),
-                    # - and + are handled by diffsinglehunk
-                   ]
+    headprefixes = [
+        ('diff', 'diff.diffline'),
+        ('copy', 'diff.extended'),
+        ('rename', 'diff.extended'),
+        ('old', 'diff.extended'),
+        ('new', 'diff.extended'),
+        ('deleted', 'diff.extended'),
+        ('index', 'diff.extended'),
+        ('similarity', 'diff.extended'),
+        ('---', 'diff.file_a'),
+        ('+++', 'diff.file_b'),
+    ]
+    textprefixes = [
+        ('@', 'diff.hunk'),
+        # - and + are handled by diffsinglehunk
+    ]
     head = False
 
     # buffers a hunk, i.e. adjacent "-", "+" lines without other changes.
     hunkbuffer = []
+
     def consumehunkbuffer():
         if hunkbuffer:
             for token in dodiffhunk(hunkbuffer):
@@ -2560,8 +2824,10 @@
                     if stripline.startswith(prefix):
                         yield (stripline, label)
                         if line != stripline:
-                            yield (line[len(stripline):],
-                                   'diff.trailingwhitespace')
+                            yield (
+                                line[len(stripline) :],
+                                'diff.trailingwhitespace',
+                            )
                         break
                 else:
                     yield (line, '')
@@ -2570,10 +2836,12 @@
         for token in consumehunkbuffer():
             yield token
 
+
 def diffui(*args, **kw):
     '''like diff(), but yields 2-tuples of (output, label) for ui.write()'''
     return difflabel(diff, *args, **kw)
 
+
 def _filepairs(modified, added, removed, copy, opts):
     '''generates tuples (f1, f2, copyop), where f1 is the name of the file
     before and f2 is the the name after. For added files, f1 will be None,
@@ -2602,13 +2870,29 @@
             f2 = None
             if opts.git:
                 # have we already reported a copy above?
-                if (f in copyto and copyto[f] in addedset
-                    and copy[copyto[f]] == f):
+                if (
+                    f in copyto
+                    and copyto[f] in addedset
+                    and copy[copyto[f]] == f
+                ):
                     continue
         yield f1, f2, copyop
 
-def trydiff(repo, revs, ctx1, ctx2, modified, added, removed,
-            copy, getfilectx, opts, losedatafn, pathfn):
+
+def trydiff(
+    repo,
+    revs,
+    ctx1,
+    ctx2,
+    modified,
+    added,
+    removed,
+    copy,
+    getfilectx,
+    opts,
+    losedatafn,
+    pathfn,
+):
     '''given input data, generate a diff and yield it in blocks
 
     If generating a diff would lose data like flags or binary data and
@@ -2668,28 +2952,36 @@
             binary = any(f.isbinary() for f in [fctx1, fctx2] if f is not None)
 
         if losedatafn and not opts.git:
-            if (binary or
+            if (
+                binary
+                or
                 # copy/rename
-                f2 in copy or
+                f2 in copy
+                or
                 # empty file creation
-                (not f1 and isempty(fctx2)) or
+                (not f1 and isempty(fctx2))
+                or
                 # empty file deletion
-                (isempty(fctx1) and not f2) or
+                (isempty(fctx1) and not f2)
+                or
                 # create with flags
-                (not f1 and flag2) or
+                (not f1 and flag2)
+                or
                 # change flags
-                (f1 and f2 and flag1 != flag2)):
+                (f1 and f2 and flag1 != flag2)
+            ):
                 losedatafn(f2 or f1)
 
         path1 = pathfn(f1 or f2)
         path2 = pathfn(f2 or f1)
         header = []
         if opts.git:
-            header.append('diff --git %s%s %s%s' %
-                          (aprefix, path1, bprefix, path2))
-            if not f1: # added
+            header.append(
+                'diff --git %s%s %s%s' % (aprefix, path1, bprefix, path2)
+            )
+            if not f1:  # added
                 header.append('new file mode %s' % gitmode[flag2])
-            elif not f2: # removed
+            elif not f2:  # removed
                 header.append('deleted file mode %s' % gitmode[flag1])
             else:  # modified/copied/renamed
                 mode1, mode2 = gitmode[flag1], gitmode[flag2]
@@ -2716,8 +3008,9 @@
         #  yes      | yes  *        *   *     | text diff | yes
         #  no       | *    *        *   *     | text diff | yes
         # [1]: hash(fctx.data()) is outputted. so fctx.data() cannot be faked
-        if binary and (not opts.git or (opts.git and opts.nobinary and not
-                                        opts.index)):
+        if binary and (
+            not opts.git or (opts.git and opts.nobinary and not opts.index)
+        ):
             # fast path: no binary content will be displayed, content1 and
             # content2 are only used for equivalent test. cmp() could have a
             # fast path.
@@ -2725,7 +3018,7 @@
                 content1 = b'\0'
             if fctx2 is not None:
                 if fctx1 is not None and not fctx1.cmp(fctx2):
-                    content2 = b'\0' # not different
+                    content2 = b'\0'  # not different
                 else:
                     content2 = b'\0\0'
         else:
@@ -2738,26 +3031,38 @@
         if binary and opts.git and not opts.nobinary:
             text = mdiff.b85diff(content1, content2)
             if text:
-                header.append('index %s..%s' %
-                              (gitindex(content1), gitindex(content2)))
-            hunks = (None, [text]),
+                header.append(
+                    'index %s..%s' % (gitindex(content1), gitindex(content2))
+                )
+            hunks = ((None, [text]),)
         else:
             if opts.git and opts.index > 0:
                 flag = flag1
                 if flag is None:
                     flag = flag2
-                header.append('index %s..%s %s' %
-                              (gitindex(content1)[0:opts.index],
-                               gitindex(content2)[0:opts.index],
-                               gitmode[flag]))
-
-            uheaders, hunks = mdiff.unidiff(content1, date1,
-                                            content2, date2,
-                                            path1, path2,
-                                            binary=binary, opts=opts)
+                header.append(
+                    'index %s..%s %s'
+                    % (
+                        gitindex(content1)[0 : opts.index],
+                        gitindex(content2)[0 : opts.index],
+                        gitmode[flag],
+                    )
+                )
+
+            uheaders, hunks = mdiff.unidiff(
+                content1,
+                date1,
+                content2,
+                date2,
+                path1,
+                path2,
+                binary=binary,
+                opts=opts,
+            )
             header.extend(uheaders)
         yield fctx1, fctx2, header, hunks
 
+
 def diffstatsum(stats):
     maxfile, maxtotal, addtotal, removetotal, binary = 0, 0, 0, 0, False
     for f, a, r, b in stats:
@@ -2769,6 +3074,7 @@
 
     return maxfile, maxtotal, addtotal, removetotal, binary
 
+
 def diffstatdata(lines):
     diffre = re.compile(br'^diff .*-r [a-z0-9]+\s(.*)$')
 
@@ -2802,8 +3108,9 @@
             adds += 1
         elif line.startswith('-') and not inheader:
             removes += 1
-        elif (line.startswith('GIT binary patch') or
-              line.startswith('Binary file')):
+        elif line.startswith('GIT binary patch') or line.startswith(
+            'Binary file'
+        ):
             isbinary = True
         elif line.startswith('rename from'):
             filename = line[12:]
@@ -2812,6 +3119,7 @@
     addresult()
     return results
 
+
 def diffstat(lines, width=80):
     output = []
     stats = diffstatdata(lines)
@@ -2839,17 +3147,27 @@
             count = '%d' % (adds + removes)
         pluses = '+' * scale(adds)
         minuses = '-' * scale(removes)
-        output.append(' %s%s |  %*s %s%s\n' %
-                      (filename, ' ' * (maxname - encoding.colwidth(filename)),
-                       countwidth, count, pluses, minuses))
+        output.append(
+            ' %s%s |  %*s %s%s\n'
+            % (
+                filename,
+                ' ' * (maxname - encoding.colwidth(filename)),
+                countwidth,
+                count,
+                pluses,
+                minuses,
+            )
+        )
 
     if stats:
-        output.append(_(' %d files changed, %d insertions(+), '
-                        '%d deletions(-)\n')
-                      % (len(stats), totaladds, totalremoves))
+        output.append(
+            _(' %d files changed, %d insertions(+), ' '%d deletions(-)\n')
+            % (len(stats), totaladds, totalremoves)
+        )
 
     return ''.join(output)
 
+
 def diffstatui(*args, **kw):
     '''like diffstat(), but yields 2-tuples of (output, label) for
     ui.write()