doc: Make PEP8 happier

This commit is contained in:
Frédéric Pierret (fepitre) 2019-11-22 11:18:34 +01:00
parent 0d20639cc1
commit b4177cf7d2
No known key found for this signature in database
GPG Key ID: 484010B5CDC576E2
2 changed files with 60 additions and 49 deletions

View File

@ -2,6 +2,7 @@
import os import os
import sys import sys
sys.path.insert(0, os.path.abspath('../')) sys.path.insert(0, os.path.abspath('../'))
import argparse import argparse
@ -9,12 +10,14 @@ import qubes.dochelpers
parser = argparse.ArgumentParser(description='prepare new manpage for command') parser = argparse.ArgumentParser(description='prepare new manpage for command')
parser.add_argument('command', metavar='COMMAND', parser.add_argument('command', metavar='COMMAND',
help='program\'s command name; this should translate to ' help='program\'s command name; this should translate to '
'qubes.tools.<command_name>') 'qubes.tools.<command_name>')
def main(): def main():
args = parser.parse_args() args = parser.parse_args()
sys.stdout.write(qubes.dochelpers.prepare_manpage(args.command)) sys.stdout.write(qubes.dochelpers.prepare_manpage(args.command))
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -18,11 +18,11 @@
# License along with this library; if not, see <https://www.gnu.org/licenses/>. # License along with this library; if not, see <https://www.gnu.org/licenses/>.
# #
'''Documentation helpers. """Documentation helpers.
This module contains classes and functions which help to maintain documentation, This module contains classes and functions which help to maintain documentation,
particularly our custom Sphinx extension. particularly our custom Sphinx extension.
''' """
import argparse import argparse
import io import io
@ -55,14 +55,15 @@ class GithubTicket:
self.summary = data['title'] self.summary = data['title']
self.uri = data['html_url'] self.uri = data['html_url']
def fetch_ticket_info(app, number): def fetch_ticket_info(app, number):
'''Fetch info about particular trac ticket given """Fetch info about particular trac ticket given
:param app: Sphinx app object :param app: Sphinx app object
:param str number: number of the ticket, without # :param str number: number of the ticket, without #
:rtype: mapping :rtype: mapping
:raises: urllib.error.HTTPError :raises: urllib.error.HTTPError
''' """
response = urllib.request.urlopen(urllib.request.Request( response = urllib.request.urlopen(urllib.request.Request(
app.config.ticket_base_uri.format(number=number), app.config.ticket_base_uri.format(number=number),
@ -71,8 +72,9 @@ def fetch_ticket_info(app, number):
'User-agent': __name__})) 'User-agent': __name__}))
return GithubTicket(json.load(response)) return GithubTicket(json.load(response))
def ticket(name, rawtext, text, lineno, inliner, options=None, content=None): def ticket(name, rawtext, text, lineno, inliner, options=None, content=None):
'''Link to qubes ticket """Link to qubes ticket
:param str name: The role name used in the document :param str name: The role name used in the document
:param str rawtext: The entire markup snippet, with role :param str rawtext: The entire markup snippet, with role
@ -82,7 +84,7 @@ def ticket(name, rawtext, text, lineno, inliner, options=None, content=None):
that called this function that called this function
:param options: Directive options for customisation :param options: Directive options for customisation
:param content: The directive content for customisation :param content: The directive content for customisation
''' # pylint: disable=unused-argument """ # pylint: disable=unused-argument
if options is None: if options is None:
options = {} options = {}
@ -117,20 +119,23 @@ class versioncheck(docutils.nodes.warning):
# pylint: disable=invalid-name # pylint: disable=invalid-name
pass pass
def visit(self, node): def visit(self, node):
self.visit_admonition(node, 'version') self.visit_admonition(node, 'version')
def depart(self, node): def depart(self, node):
self.depart_admonition(node) self.depart_admonition(node)
sphinx.locale.admonitionlabels['version'] = 'Version mismatch' sphinx.locale.admonitionlabels['version'] = 'Version mismatch'
class VersionCheck(docutils.parsers.rst.Directive): class VersionCheck(docutils.parsers.rst.Directive):
'''Directive versioncheck """Directive versioncheck
Check if current version (from ``conf.py``) equals version specified as Check if current version (from ``conf.py``) equals version specified as
argument. If not, generate warning.''' argument. If not, generate warning."""
has_content = True has_content = True
required_arguments = 1 required_arguments = 1
@ -145,16 +150,16 @@ class VersionCheck(docutils.parsers.rst.Directive):
if current == version: if current == version:
return [] return []
text = ' '.join('''This manual page was written for version **{}**, but text = ' '.join("""This manual page was written for version **{}**, but
current version at the time when this page was generated is **{}**. current version at the time when this page was generated is **{}**.
This may or may not mean that page is outdated or has This may or may not mean that page is outdated or has
inconsistencies.'''.format(version, current).split()) inconsistencies.""".format(version, current).split())
node = versioncheck(text) node = versioncheck(text)
node['classes'] = ['admonition', 'warning'] node['classes'] = ['admonition', 'warning']
self.state.nested_parse(docutils.statemachine.StringList([text]), self.state.nested_parse(docutils.statemachine.StringList([text]),
self.content_offset, node) self.content_offset, node)
return [node] return [node]
@ -168,14 +173,14 @@ def prepare_manpage(command):
stream.write('.. program:: {}\n\n'.format(command)) stream.write('.. program:: {}\n\n'.format(command))
stream.write(make_rst_section( stream.write(make_rst_section(
':program:`{}` -- {}'.format(command, parser.description), '=')) ':program:`{}` -- {}'.format(command, parser.description), '='))
stream.write('''.. warning:: stream.write(""".. warning::
This page was autogenerated from command-line parser. It shouldn't be 1:1 This page was autogenerated from command-line parser. It shouldn't be 1:1
conversion, because it would add little value. Please revise it and add conversion, because it would add little value. Please revise it and add
more descriptive help, which normally won't fit in standard ``--help`` more descriptive help, which normally won't fit in standard ``--help``
option. option.
After rewrite, please remove this admonition.\n\n''') After rewrite, please remove this admonition.\n\n""")
stream.write(make_rst_section('Synopsis', '-')) stream.write(make_rst_section('Synopsis', '-'))
usage = ' '.join(parser.format_usage().strip().split()) usage = ' '.join(parser.format_usage().strip().split())
@ -189,34 +194,35 @@ def prepare_manpage(command):
stream.write(make_rst_section('Options', '-')) stream.write(make_rst_section('Options', '-'))
for action in parser._actions: # pylint: disable=protected-access for action in parser._actions: # pylint: disable=protected-access
stream.write('.. option:: ') stream.write('.. option:: ')
if action.metavar: if action.metavar:
stream.write(', '.join('{}{}{}'.format( stream.write(', '.join('{}{}{}'.format(
option, option,
'=' if option.startswith('--') else ' ', '=' if option.startswith('--') else ' ',
action.metavar) action.metavar)
for option in sorted(action.option_strings))) for option in sorted(action.option_strings)))
else: else:
stream.write(', '.join(sorted(action.option_strings))) stream.write(', '.join(sorted(action.option_strings)))
stream.write('\n\n {}\n\n'.format(action.help)) stream.write('\n\n {}\n\n'.format(action.help))
stream.write(make_rst_section('Authors', '-')) stream.write(make_rst_section('Authors', '-'))
stream.write('''\ stream.write("""\
| Joanna Rutkowska <joanna at invisiblethingslab dot com> | Joanna Rutkowska <joanna at invisiblethingslab dot com>
| Rafal Wojtczuk <rafal at invisiblethingslab dot com> | Rafal Wojtczuk <rafal at invisiblethingslab dot com>
| Marek Marczykowski <marmarek at invisiblethingslab dot com> | Marek Marczykowski <marmarek at invisiblethingslab dot com>
| Wojtek Porczyk <woju at invisiblethingslab dot com> | Wojtek Porczyk <woju at invisiblethingslab dot com>
.. vim: ts=3 sw=3 et tw=80 .. vim: ts=3 sw=3 et tw=80
''') """)
return stream.getvalue() return stream.getvalue()
class OptionsCheckVisitor(docutils.nodes.SparseNodeVisitor): class OptionsCheckVisitor(docutils.nodes.SparseNodeVisitor):
''' Checks if the visited option nodes and the specified args are in sync. """ Checks if the visited option nodes and the specified args are in sync.
''' """
def __init__(self, command, args, document): def __init__(self, command, args, document):
assert isinstance(args, set) assert isinstance(args, set)
docutils.nodes.SparseNodeVisitor.__init__(self, document) docutils.nodes.SparseNodeVisitor.__init__(self, document)
@ -224,14 +230,13 @@ class OptionsCheckVisitor(docutils.nodes.SparseNodeVisitor):
self.args = args self.args = args
def visit_desc(self, node): def visit_desc(self, node):
''' Skips all but 'option' elements ''' """ Skips all but 'option' elements """
# pylint: disable=no-self-use # pylint: disable=no-self-use
if not node.get('desctype', None) == 'option': if not node.get('desctype', None) == 'option':
raise docutils.nodes.SkipChildren raise docutils.nodes.SkipChildren
def visit_desc_name(self, node): def visit_desc_name(self, node):
''' Checks if the option is defined `self.args` ''' """ Checks if the option is defined `self.args` """
if not isinstance(node[0], docutils.nodes.Text): if not isinstance(node[0], docutils.nodes.Text):
raise sphinx.errors.SphinxError('first child should be Text') raise sphinx.errors.SphinxError('first child should be Text')
@ -243,14 +248,14 @@ class OptionsCheckVisitor(docutils.nodes.SparseNodeVisitor):
'No such argument for {!r}: {!r}'.format(self.command, arg)) 'No such argument for {!r}: {!r}'.format(self.command, arg))
def check_undocumented_arguments(self, ignored_options=None): def check_undocumented_arguments(self, ignored_options=None):
''' Call this to check if any undocumented arguments are left. """ Call this to check if any undocumented arguments are left.
While the documentation talks about a While the documentation talks about a
'SparseNodeVisitor.depart_document()' function, this function does 'SparseNodeVisitor.depart_document()' function, this function does
not exists. (For details see implementation of not exists. (For details see implementation of
:py:meth:`NodeVisitor.dispatch_departure()`) So we need to :py:meth:`NodeVisitor.dispatch_departure()`) So we need to
manually call this. manually call this.
''' """
if ignored_options is None: if ignored_options is None:
ignored_options = set() ignored_options = set()
left_over_args = self.args - ignored_options left_over_args = self.args - ignored_options
@ -261,9 +266,9 @@ class OptionsCheckVisitor(docutils.nodes.SparseNodeVisitor):
class CommandCheckVisitor(docutils.nodes.SparseNodeVisitor): class CommandCheckVisitor(docutils.nodes.SparseNodeVisitor):
''' Checks if the visited sub command section nodes and the specified sub """ Checks if the visited sub command section nodes and the specified sub
command args are in sync. command args are in sync.
''' """
def __init__(self, command, sub_commands, document): def __init__(self, command, sub_commands, document):
docutils.nodes.SparseNodeVisitor.__init__(self, document) docutils.nodes.SparseNodeVisitor.__init__(self, document)
@ -271,12 +276,12 @@ class CommandCheckVisitor(docutils.nodes.SparseNodeVisitor):
self.sub_commands = sub_commands self.sub_commands = sub_commands
def visit_section(self, node): def visit_section(self, node):
''' Checks if the visited sub-command section nodes exists and it """ Checks if the visited sub-command section nodes exists and it
options are in sync. options are in sync.
Uses :py:class:`OptionsCheckVisitor` for checking Uses :py:class:`OptionsCheckVisitor` for checking
sub-commands options sub-commands options
''' """
# pylint: disable=no-self-use # pylint: disable=no-self-use
title = str(node[0][0]) title = str(node[0][0])
if title.upper() == SUBCOMMANDS_TITLE: if title.upper() == SUBCOMMANDS_TITLE:
@ -296,10 +301,10 @@ class CommandCheckVisitor(docutils.nodes.SparseNodeVisitor):
'No such sub-command {!r}'.format(sub_cmd)) 'No such sub-command {!r}'.format(sub_cmd))
def visit_Text(self, node): def visit_Text(self, node):
''' If the visited text node starts with 'alias: ', all the provided """ If the visited text node starts with 'alias: ', all the provided
comma separted alias in this node, are removed from comma separted alias in this node, are removed from
`self.sub_commands` `self.sub_commands`
''' """
# pylint: disable=invalid-name # pylint: disable=invalid-name
text = str(node).strip() text = str(node).strip()
if text.startswith('aliases:'): if text.startswith('aliases:'):
@ -308,16 +313,15 @@ class CommandCheckVisitor(docutils.nodes.SparseNodeVisitor):
assert alias in self.sub_commands assert alias in self.sub_commands
del self.sub_commands[alias] del self.sub_commands[alias]
def check_undocumented_sub_commands(self): def check_undocumented_sub_commands(self):
''' Call this to check if any undocumented sub_commands are left. """ Call this to check if any undocumented sub_commands are left.
While the documentation talks about a While the documentation talks about a
'SparseNodeVisitor.depart_document()' function, this function does 'SparseNodeVisitor.depart_document()' function, this function does
not exists. (For details see implementation of not exists. (For details see implementation of
:py:meth:`NodeVisitor.dispatch_departure()`) So we need to :py:meth:`NodeVisitor.dispatch_departure()`) So we need to
manually call this. manually call this.
''' """
if self.sub_commands: if self.sub_commands:
raise sphinx.errors.SphinxError( raise sphinx.errors.SphinxError(
'Undocumented commands for {!r}: {!r}'.format( 'Undocumented commands for {!r}: {!r}'.format(
@ -325,9 +329,10 @@ class CommandCheckVisitor(docutils.nodes.SparseNodeVisitor):
class ManpageCheckVisitor(docutils.nodes.SparseNodeVisitor): class ManpageCheckVisitor(docutils.nodes.SparseNodeVisitor):
''' Checks if the sub-commands and options specified in the 'COMMAND' and """ Checks if the sub-commands and options specified in the 'COMMAND' and
'OPTIONS' (case insensitve) sections in sync the command parser. 'OPTIONS' (case insensitve) sections in sync the command parser.
''' """
def __init__(self, app, command, document): def __init__(self, app, command, document):
docutils.nodes.SparseNodeVisitor.__init__(self, document) docutils.nodes.SparseNodeVisitor.__init__(self, document)
try: try:
@ -362,16 +367,16 @@ class ManpageCheckVisitor(docutils.nodes.SparseNodeVisitor):
self.options.update(action.option_strings) self.options.update(action.option_strings)
def visit_section(self, node): def visit_section(self, node):
''' If section title is OPTIONS or COMMANDS dispatch the apropriate """ If section title is OPTIONS or COMMANDS dispatch the apropriate
`NodeVisitor`. `NodeVisitor`.
''' """
if self.parser is None: if self.parser is None:
return return
section_title = str(node[0][0]).upper() section_title = str(node[0][0]).upper()
if section_title == OPTIONS_TITLE: if section_title == OPTIONS_TITLE:
options_visitor = OptionsCheckVisitor(self.command, self.options, options_visitor = OptionsCheckVisitor(self.command, self.options,
self.document) self.document)
node.walkabout(options_visitor) node.walkabout(options_visitor)
options_visitor.check_undocumented_arguments() options_visitor.check_undocumented_arguments()
elif section_title == SUBCOMMANDS_TITLE: elif section_title == SUBCOMMANDS_TITLE:
@ -380,10 +385,11 @@ class ManpageCheckVisitor(docutils.nodes.SparseNodeVisitor):
node.walkabout(sub_cmd_visitor) node.walkabout(sub_cmd_visitor)
sub_cmd_visitor.check_undocumented_sub_commands() sub_cmd_visitor.check_undocumented_sub_commands()
def check_man_args(app, doctree, docname): def check_man_args(app, doctree, docname):
''' Checks the manpage for undocumented or obsolete sub-commands and """ Checks the manpage for undocumented or obsolete sub-commands and
options. options.
''' """
dirname, command = os.path.split(docname) dirname, command = os.path.split(docname)
if os.path.basename(dirname) != 'manpages': if os.path.basename(dirname) != 'manpages':
return return
@ -398,6 +404,7 @@ def check_man_args(app, doctree, docname):
event_sig_re = re.compile(r'([a-zA-Z-:<>]+)\s*\((.*)\)') event_sig_re = re.compile(r'([a-zA-Z-:<>]+)\s*\((.*)\)')
def parse_event(env, sig, signode): def parse_event(env, sig, signode):
# pylint: disable=unused-argument # pylint: disable=unused-argument
m = event_sig_re.match(sig) m = event_sig_re.match(sig)
@ -413,6 +420,7 @@ def parse_event(env, sig, signode):
signode += plist signode += plist
return name return name
# #
# end of codelifting # end of codelifting
# #
@ -433,17 +441,17 @@ def setup(app):
'env') 'env')
app.add_config_value('break_to_pdb', False, 'env') app.add_config_value('break_to_pdb', False, 'env')
app.add_node(versioncheck, app.add_node(versioncheck,
html=(visit, depart), html=(visit, depart),
man=(visit, depart)) man=(visit, depart))
app.add_directive('versioncheck', VersionCheck) app.add_directive('versioncheck', VersionCheck)
fdesc = sphinx.util.docfields.GroupedField('parameter', label='Parameters', fdesc = sphinx.util.docfields.GroupedField('parameter', label='Parameters',
names=['param'], can_collapse=True) names=['param'],
can_collapse=True)
app.add_object_type('event', 'event', 'pair: %s; event', parse_event, app.add_object_type('event', 'event', 'pair: %s; event', parse_event,
doc_field_types=[fdesc]) doc_field_types=[fdesc])
app.connect('doctree-resolved', break_to_pdb) app.connect('doctree-resolved', break_to_pdb)
app.connect('doctree-resolved', check_man_args) app.connect('doctree-resolved', check_man_args)
# vim: ts=4 sw=4 et # vim: ts=4 sw=4 et