hgext/releasenotes.py
changeset 43076 2372284d9457
parent 41768 aaad36b88298
child 43077 687b865b95ad
--- a/hgext/releasenotes.py	Sat Oct 05 10:29:34 2019 -0400
+++ b/hgext/releasenotes.py	Sun Oct 06 09:45:02 2019 -0400
@@ -28,15 +28,14 @@
     scmutil,
     util,
 )
-from mercurial.utils import (
-    stringutil,
-)
+from mercurial.utils import stringutil
 
 cmdtable = {}
 command = registrar.command(cmdtable)
 
 try:
     import fuzzywuzzy.fuzz as fuzz
+
     fuzz.token_set_ratio
 except ImportError:
     fuzz = None
@@ -60,6 +59,7 @@
 
 BULLET_SECTION = _('Other Changes')
 
+
 class parsedreleasenotes(object):
     def __init__(self):
         self.sections = {}
@@ -103,19 +103,25 @@
         This is used to combine multiple sources of release notes together.
         """
         if not fuzz:
-            ui.warn(_("module 'fuzzywuzzy' not found, merging of similar "
-                      "releasenotes is disabled\n"))
+            ui.warn(
+                _(
+                    "module 'fuzzywuzzy' not found, merging of similar "
+                    "releasenotes is disabled\n"
+                )
+            )
 
         for section in other:
-            existingnotes = (
-                converttitled(self.titledforsection(section)) +
-                convertnontitled(self.nontitledforsection(section)))
+            existingnotes = converttitled(
+                self.titledforsection(section)
+            ) + convertnontitled(self.nontitledforsection(section))
             for title, paragraphs in other.titledforsection(section):
                 if self.hastitledinsection(section, title):
                     # TODO prompt for resolution if different and running in
                     # interactive mode.
-                    ui.write(_('%s already exists in %s section; ignoring\n') %
-                             (title, section))
+                    ui.write(
+                        _('%s already exists in %s section; ignoring\n')
+                        % (title, section)
+                    )
                     continue
 
                 incoming_str = converttitled([(title, paragraphs)])[0]
@@ -146,6 +152,7 @@
 
                 self.addnontitleditem(section, paragraphs)
 
+
 class releasenotessections(object):
     def __init__(self, ui, repo=None):
         if repo:
@@ -170,6 +177,7 @@
 
         return None
 
+
 def converttitled(titledparagraphs):
     """
     Convert titled paragraphs to strings
@@ -182,6 +190,7 @@
         string_list.append(' '.join(lines))
     return string_list
 
+
 def convertnontitled(nontitledparagraphs):
     """
     Convert non-titled bullets to strings
@@ -194,6 +203,7 @@
         string_list.append(' '.join(lines))
     return string_list
 
+
 def getissuenum(incoming_str):
     """
     Returns issue number from the incoming string if it exists
@@ -203,6 +213,7 @@
         issue = issue.group()
     return issue
 
+
 def findissue(ui, existing, issue):
     """
     Returns true if issue number already exists in notes.
@@ -213,6 +224,7 @@
     else:
         return False
 
+
 def similar(ui, existing, incoming_str):
     """
     Returns true if similar note found in existing notes.
@@ -220,14 +232,17 @@
     if len(incoming_str.split()) > 10:
         merge = similaritycheck(incoming_str, existing)
         if not merge:
-            ui.write(_('"%s" already exists in notes file; ignoring\n')
-                     % incoming_str)
+            ui.write(
+                _('"%s" already exists in notes file; ignoring\n')
+                % incoming_str
+            )
             return True
         else:
             return False
     else:
         return False
 
+
 def similaritycheck(incoming_str, existingnotes):
     """
     Returns false when note fragment can be merged to existing notes.
@@ -244,6 +259,7 @@
             break
     return merge
 
+
 def getcustomadmonitions(repo):
     ctx = repo['.']
     p = config.config()
@@ -253,13 +269,15 @@
             data = ctx[f].data()
             p.parse(f, data, sections, remap, read)
         else:
-            raise error.Abort(_(".hgreleasenotes file \'%s\' not found") %
-                              repo.pathto(f))
+            raise error.Abort(
+                _(".hgreleasenotes file \'%s\' not found") % repo.pathto(f)
+            )
 
     if '.hgreleasenotes' in ctx:
         read('.hgreleasenotes')
     return p['sections']
 
+
 def checkadmonitions(ui, repo, directives, revs):
     """
     Checks the commit messages for admonitions and their validity.
@@ -280,10 +298,13 @@
             if admonition.group(1) in directives:
                 continue
             else:
-                ui.write(_("Invalid admonition '%s' present in changeset %s"
-                           "\n") % (admonition.group(1), ctx.hex()[:12]))
-                sim = lambda x: difflib.SequenceMatcher(None,
-                    admonition.group(1), x).ratio()
+                ui.write(
+                    _("Invalid admonition '%s' present in changeset %s" "\n")
+                    % (admonition.group(1), ctx.hex()[:12])
+                )
+                sim = lambda x: difflib.SequenceMatcher(
+                    None, admonition.group(1), x
+                ).ratio()
 
                 similar = [s for s in directives if sim(s) > 0.6]
                 if len(similar) == 1:
@@ -292,18 +313,21 @@
                     ss = ", ".join(sorted(similar))
                     ui.write(_("(did you mean one of %s?)\n") % ss)
 
+
 def _getadmonitionlist(ui, sections):
     for section in sections:
         ui.write("%s: %s\n" % (section[0], section[1]))
 
+
 def parsenotesfromrevisions(repo, directives, revs):
     notes = parsedreleasenotes()
 
     for rev in revs:
         ctx = repo[rev]
 
-        blocks, pruned = minirst.parse(ctx.description(),
-                                       admonitions=directives)
+        blocks, pruned = minirst.parse(
+            ctx.description(), admonitions=directives
+        )
 
         for i, block in enumerate(blocks):
             if block['type'] != 'admonition':
@@ -313,8 +337,13 @@
             title = block['lines'][0].strip() if block['lines'] else None
 
             if i + 1 == len(blocks):
-                raise error.Abort(_('changeset %s: release notes directive %s '
-                        'lacks content') % (ctx, directive))
+                raise error.Abort(
+                    _(
+                        'changeset %s: release notes directive %s '
+                        'lacks content'
+                    )
+                    % (ctx, directive)
+                )
 
             # Now search ahead and find all paragraphs attached to this
             # admonition.
@@ -330,8 +359,13 @@
                     break
 
                 if pblock['type'] != 'paragraph':
-                    repo.ui.warn(_('changeset %s: unexpected block in release '
-                        'notes directive %s\n') % (ctx, directive))
+                    repo.ui.warn(
+                        _(
+                            'changeset %s: unexpected block in release '
+                            'notes directive %s\n'
+                        )
+                        % (ctx, directive)
+                    )
 
                 if pblock['indent'] > 0:
                     paragraphs.append(pblock['lines'])
@@ -340,8 +374,10 @@
 
             # TODO consider using title as paragraph for more concise notes.
             if not paragraphs:
-                repo.ui.warn(_("error parsing releasenotes for revision: "
-                               "'%s'\n") % node.hex(ctx.node()))
+                repo.ui.warn(
+                    _("error parsing releasenotes for revision: " "'%s'\n")
+                    % node.hex(ctx.node())
+                )
             if title:
                 notes.addtitleditem(directive, title, paragraphs)
             else:
@@ -349,6 +385,7 @@
 
     return notes
 
+
 def parsereleasenotesfile(sections, text):
     """Parse text content containing generated release notes."""
     notes = parsedreleasenotes()
@@ -375,7 +412,7 @@
                 else:
                     lines = [[l[1:].strip() for l in block['lines']]]
 
-                    for block in blocks[i + 1:]:
+                    for block in blocks[i + 1 :]:
                         if block['type'] in ('bullet', 'section'):
                             break
                         if block['type'] == 'paragraph':
@@ -383,8 +420,10 @@
                     notefragment.append(lines)
                     continue
             elif block['type'] != 'paragraph':
-                raise error.Abort(_('unexpected block type in release notes: '
-                                    '%s') % block['type'])
+                raise error.Abort(
+                    _('unexpected block type in release notes: ' '%s')
+                    % block['type']
+                )
             if title:
                 notefragment.append(block['lines'])
 
@@ -402,8 +441,9 @@
         if block['underline'] == '=':  # main section
             name = sections.sectionfromtitle(title)
             if not name:
-                raise error.Abort(_('unknown release notes section: %s') %
-                                  title)
+                raise error.Abort(
+                    _('unknown release notes section: %s') % title
+                )
 
             currentsection = name
             bullet_points = gatherparagraphsbullets(i)
@@ -424,6 +464,7 @@
 
     return notes
 
+
 def serializenotes(sections, notes):
     """Serialize release notes from parsed fragments and notes.
 
@@ -449,8 +490,9 @@
             for i, para in enumerate(paragraphs):
                 if i:
                     lines.append('')
-                lines.extend(stringutil.wrap(' '.join(para),
-                                             width=78).splitlines())
+                lines.extend(
+                    stringutil.wrap(' '.join(para), width=78).splitlines()
+                )
 
             lines.append('')
 
@@ -468,17 +510,25 @@
             lines.append('')
 
         for paragraphs in nontitled:
-            lines.extend(stringutil.wrap(' '.join(paragraphs[0]),
-                                         width=78,
-                                         initindent='* ',
-                                         hangindent='  ').splitlines())
+            lines.extend(
+                stringutil.wrap(
+                    ' '.join(paragraphs[0]),
+                    width=78,
+                    initindent='* ',
+                    hangindent='  ',
+                ).splitlines()
+            )
 
             for para in paragraphs[1:]:
                 lines.append('')
-                lines.extend(stringutil.wrap(' '.join(para),
-                                             width=78,
-                                             initindent='  ',
-                                             hangindent='  ').splitlines())
+                lines.extend(
+                    stringutil.wrap(
+                        ' '.join(para),
+                        width=78,
+                        initindent='  ',
+                        hangindent='  ',
+                    ).splitlines()
+                )
 
             lines.append('')
 
@@ -487,14 +537,29 @@
 
     return '\n'.join(lines)
 
-@command('releasenotes',
-    [('r', 'rev', '', _('revisions to process for release notes'), _('REV')),
-    ('c', 'check', False, _('checks for validity of admonitions (if any)'),
-        _('REV')),
-    ('l', 'list', False, _('list the available admonitions with their title'),
-        None)],
+
+@command(
+    'releasenotes',
+    [
+        ('r', 'rev', '', _('revisions to process for release notes'), _('REV')),
+        (
+            'c',
+            'check',
+            False,
+            _('checks for validity of admonitions (if any)'),
+            _('REV'),
+        ),
+        (
+            'l',
+            'list',
+            False,
+            _('list the available admonitions with their title'),
+            None,
+        ),
+    ],
     _('hg releasenotes [-r REV] [-c] FILE'),
-    helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
+    helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
+)
 def releasenotes(ui, repo, file_=None, **opts):
     """parse release notes from commit messages into an output file
 
@@ -616,6 +681,7 @@
     with open(file_, 'wb') as fh:
         fh.write(serializenotes(sections, notes))
 
+
 @command('debugparsereleasenotes', norepo=True)
 def debugparsereleasenotes(ui, path, repo=None):
     """parse release notes and print resulting data structure"""