Enable automatic formatting for `sphinx/directives/` (#12964)

This commit is contained in:
Adam Turner 2024-10-04 15:33:10 +01:00 committed by GitHub
parent b372b2f529
commit c1d192e2c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 170 additions and 110 deletions

View File

@ -447,7 +447,6 @@ exclude = [
"sphinx/builders/*",
"sphinx/cmd/*",
"sphinx/config.py",
"sphinx/directives/*",
"sphinx/domains/*",
"sphinx/environment/*",
"sphinx/ext/autodoc/__init__.py",

View File

@ -111,7 +111,9 @@ class ObjectDescription(SphinxDirective, Generic[ObjDescT]):
"""
raise ValueError
def add_target_and_index(self, name: ObjDescT, sig: str, signode: desc_signature) -> None:
def add_target_and_index(
self, name: ObjDescT, sig: str, signode: desc_signature
) -> None:
"""
Add cross-reference IDs and entries to self.indexnode, if applicable.
@ -228,19 +230,18 @@ class ObjectDescription(SphinxDirective, Generic[ObjDescT]):
self.options['no-index'] = self.options['noindex']
if 'no-index-entry' not in self.options and 'noindexentry' in self.options:
self.options['no-index-entry'] = self.options['noindexentry']
if 'no-contents-entry' not in self.options and 'nocontentsentry' in self.options:
if (
'no-contents-entry' not in self.options
and 'nocontentsentry' in self.options
):
self.options['no-contents-entry'] = self.options['nocontentsentry']
node['no-index'] = node['noindex'] = no_index = (
'no-index' in self.options
)
node['no-index-entry'] = node['noindexentry'] = (
'no-index-entry' in self.options
)
node['no-index'] = node['noindex'] = no_index = 'no-index' in self.options
node['no-index-entry'] = node['noindexentry'] = 'no-index-entry' in self.options
node['no-contents-entry'] = node['nocontentsentry'] = (
'no-contents-entry' in self.options
)
node['no-typesetting'] = ('no-typesetting' in self.options)
node['no-typesetting'] = 'no-typesetting' in self.options
if self.domain:
node['classes'].append(self.domain)
node['classes'].append(node['objtype'])
@ -287,8 +288,9 @@ class ObjectDescription(SphinxDirective, Generic[ObjDescT]):
content_node = addnodes.desc_content('', *content_children)
node.append(content_node)
self.transform_content(content_node)
self.env.app.emit('object-description-transform',
self.domain, self.objtype, content_node)
self.env.app.emit(
'object-description-transform', self.domain, self.objtype, content_node
)
DocFieldTransformer(self).transform_all(content_node)
self.env.temp_data['object'] = None
self.after_content()
@ -299,8 +301,11 @@ class ObjectDescription(SphinxDirective, Generic[ObjDescT]):
# If ``:no-index:`` is set, or there are no ids on the node
# or any of its children, then just return the index node,
# as Docutils expects a target node to have at least one id.
if node_ids := [node_id for el in node.findall(nodes.Element) # type: ignore[var-annotated]
for node_id in el.get('ids', ())]:
if node_ids := [ # type: ignore[var-annotated]
node_id
for el in node.findall(nodes.Element)
for node_id in el.get('ids', ())
]:
target_node = nodes.target(ids=node_ids)
self.set_source_info(target_node)
return [self.indexnode, target_node]
@ -321,16 +326,20 @@ class DefaultRole(SphinxDirective):
docutils.unregister_role('')
return []
role_name = self.arguments[0]
role, messages = roles.role(role_name, self.state_machine.language,
self.lineno, self.state.reporter)
role, messages = roles.role(
role_name, self.state_machine.language, self.lineno, self.state.reporter
)
if role:
docutils.register_role('', role) # type: ignore[arg-type]
self.env.temp_data['default_role'] = role_name
else:
literal_block = nodes.literal_block(self.block_text, self.block_text)
reporter = self.state.reporter
error = reporter.error('Unknown interpreted text role "%s".' % role_name,
literal_block, line=self.lineno)
error = reporter.error(
'Unknown interpreted text role "%s".' % role_name,
literal_block,
line=self.lineno,
)
messages += [error]
return cast(list[nodes.Node], messages)
@ -360,7 +369,7 @@ class DefaultDomain(SphinxDirective):
def setup(app: Sphinx) -> ExtensionMetadata:
app.add_config_value("strip_signature_backslash", False, 'env')
app.add_config_value('strip_signature_backslash', False, 'env')
directives.register_directive('default-role', DefaultRole)
directives.register_directive('default-domain', DefaultDomain)
directives.register_directive('describe', ObjectDescription)

View File

@ -45,13 +45,15 @@ class Highlight(SphinxDirective):
force = 'force' in self.options
self.env.temp_data['highlight_language'] = language
return [addnodes.highlightlang(lang=language,
force=force,
linenothreshold=linenothreshold)]
return [
addnodes.highlightlang(
lang=language, force=force, linenothreshold=linenothreshold
)
]
def dedent_lines(
lines: list[str], dedent: int | None, location: tuple[str, int] | None = None,
lines: list[str], dedent: int | None, location: tuple[str, int] | None = None
) -> list[str]:
if dedent is None:
return textwrap.dedent(''.join(lines)).splitlines(True)
@ -70,10 +72,11 @@ def dedent_lines(
def container_wrapper(
directive: SphinxDirective, literal_node: Node, caption: str,
directive: SphinxDirective, literal_node: Node, caption: str
) -> nodes.container:
container_node = nodes.container('', literal_block=True,
classes=['literal-block-wrapper'])
container_node = nodes.container(
'', literal_block=True, classes=['literal-block-wrapper']
)
parsed = directive.parse_text_to_nodes(caption, offset=directive.content_offset)
node = parsed[0]
if isinstance(node, nodes.system_message):
@ -121,9 +124,12 @@ class CodeBlock(SphinxDirective):
nlines = len(self.content)
hl_lines = parselinenos(linespec, nlines)
if any(i >= nlines for i in hl_lines):
logger.warning(__('line number spec is out of range(1-%d): %r'),
nlines, self.options['emphasize-lines'],
location=location)
logger.warning(
__('line number spec is out of range(1-%d): %r'),
nlines,
self.options['emphasize-lines'],
location=location,
)
hl_lines = [x + 1 for x in hl_lines if x < nlines]
except ValueError as err:
@ -149,8 +155,9 @@ class CodeBlock(SphinxDirective):
# no highlight language specified. Then this directive refers the current
# highlight setting via ``highlight`` directive or ``highlight_language``
# configuration.
literal['language'] = self.env.temp_data.get('highlight_language',
self.config.highlight_language)
literal['language'] = self.env.temp_data.get(
'highlight_language', self.config.highlight_language
)
extra_args = literal['highlight_args'] = {}
if hl_lines is not None:
extra_args['hl_lines'] = hl_lines
@ -200,11 +207,11 @@ class LiteralIncludeReader:
def parse_options(self) -> None:
for option1, option2 in self.INVALID_OPTIONS_PAIR:
if option1 in self.options and option2 in self.options:
raise ValueError(__('Cannot use both "%s" and "%s" options') %
(option1, option2))
msg = __('Cannot use both "%s" and "%s" options') % (option1, option2)
raise ValueError(msg)
def read_file(
self, filename: str, location: tuple[str, int] | None = None,
self, filename: str, location: tuple[str, int] | None = None
) -> list[str]:
try:
with open(filename, encoding=self.encoding, errors='strict') as f:
@ -214,24 +221,28 @@ class LiteralIncludeReader:
return text.splitlines(True)
except OSError as exc:
raise OSError(__('Include file %r not found or reading it failed') %
filename) from exc
msg = __('Include file %r not found or reading it failed') % filename
raise OSError(msg) from exc
except UnicodeError as exc:
raise UnicodeError(__('Encoding %r used for reading included file %r seems to '
'be wrong, try giving an :encoding: option') %
(self.encoding, filename)) from exc
msg = __(
'Encoding %r used for reading included file %r seems to '
'be wrong, try giving an :encoding: option'
) % (self.encoding, filename)
raise UnicodeError(msg) from exc
def read(self, location: tuple[str, int] | None = None) -> tuple[str, int]:
if 'diff' in self.options:
lines = self.show_diff()
else:
filters = [self.pyobject_filter,
self.start_filter,
self.end_filter,
self.lines_filter,
self.dedent_filter,
self.prepend_filter,
self.append_filter]
filters = [
self.pyobject_filter,
self.start_filter,
self.end_filter,
self.lines_filter,
self.dedent_filter,
self.prepend_filter,
self.append_filter,
]
lines = self.read_file(self.filename, location=location)
for func in filters:
lines = func(lines, location=location)
@ -246,33 +257,41 @@ class LiteralIncludeReader:
return list(diff)
def pyobject_filter(
self, lines: list[str], location: tuple[str, int] | None = None,
self, lines: list[str], location: tuple[str, int] | None = None
) -> list[str]:
pyobject = self.options.get('pyobject')
if pyobject:
from sphinx.pycode import ModuleAnalyzer
analyzer = ModuleAnalyzer.for_file(self.filename, '')
tags = analyzer.find_tags()
if pyobject not in tags:
raise ValueError(__('Object named %r not found in include file %r') %
(pyobject, self.filename))
msg = __('Object named %r not found in include file %r') % (
pyobject,
self.filename,
)
raise ValueError(msg)
start = tags[pyobject][1]
end = tags[pyobject][2]
lines = lines[start - 1:end]
lines = lines[start - 1 : end]
if 'lineno-match' in self.options:
self.lineno_start = start
return lines
def lines_filter(
self, lines: list[str], location: tuple[str, int] | None = None,
self, lines: list[str], location: tuple[str, int] | None = None
) -> list[str]:
linespec = self.options.get('lines')
if linespec:
linelist = parselinenos(linespec, len(lines))
if any(i >= len(lines) for i in linelist):
logger.warning(__('line number spec is out of range(1-%d): %r'),
len(lines), linespec, location=location)
logger.warning(
__('line number spec is out of range(1-%d): %r'),
len(lines),
linespec,
location=location,
)
if 'lineno-match' in self.options:
# make sure the line list is not "disjoint".
@ -280,18 +299,21 @@ class LiteralIncludeReader:
if all(first + i == n for i, n in enumerate(linelist)):
self.lineno_start += linelist[0]
else:
raise ValueError(__('Cannot use "lineno-match" with a disjoint '
'set of "lines"'))
msg = __('Cannot use "lineno-match" with a disjoint set of "lines"')
raise ValueError(msg)
lines = [lines[n] for n in linelist if n < len(lines)]
if not lines:
raise ValueError(__('Line spec %r: no lines pulled from include file %r') %
(linespec, self.filename))
msg = __('Line spec %r: no lines pulled from include file %r') % (
linespec,
self.filename,
)
raise ValueError(msg)
return lines
def start_filter(
self, lines: list[str], location: tuple[str, int] | None = None,
self, lines: list[str], location: tuple[str, int] | None = None
) -> list[str]:
if 'start-at' in self.options:
start = self.options.get('start-at')
@ -309,7 +331,7 @@ class LiteralIncludeReader:
if 'lineno-match' in self.options:
self.lineno_start += lineno + 1
return lines[lineno + 1:]
return lines[lineno + 1 :]
else:
if 'lineno-match' in self.options:
self.lineno_start += lineno
@ -324,7 +346,7 @@ class LiteralIncludeReader:
return lines
def end_filter(
self, lines: list[str], location: tuple[str, int] | None = None,
self, lines: list[str], location: tuple[str, int] | None = None
) -> list[str]:
if 'end-at' in self.options:
end = self.options.get('end-at')
@ -339,7 +361,7 @@ class LiteralIncludeReader:
for lineno, line in enumerate(lines):
if end in line:
if inclusive:
return lines[:lineno + 1]
return lines[: lineno + 1]
else:
if lineno == 0:
pass # end-before ignores first line
@ -353,7 +375,7 @@ class LiteralIncludeReader:
return lines
def prepend_filter(
self, lines: list[str], location: tuple[str, int] | None = None,
self, lines: list[str], location: tuple[str, int] | None = None
) -> list[str]:
prepend = self.options.get('prepend')
if prepend:
@ -362,7 +384,7 @@ class LiteralIncludeReader:
return lines
def append_filter(
self, lines: list[str], location: tuple[str, int] | None = None,
self, lines: list[str], location: tuple[str, int] | None = None
) -> list[str]:
append = self.options.get('append')
if append:
@ -371,7 +393,7 @@ class LiteralIncludeReader:
return lines
def dedent_filter(
self, lines: list[str], location: tuple[str, int] | None = None,
self, lines: list[str], location: tuple[str, int] | None = None
) -> list[str]:
if 'dedent' in self.options:
return dedent_lines(lines, self.options.get('dedent'), location=location)
@ -417,8 +439,9 @@ class LiteralInclude(SphinxDirective):
def run(self) -> list[Node]:
document = self.state.document
if not document.settings.file_insertion_enabled:
return [document.reporter.warning('File insertion disabled',
line=self.lineno)]
return [
document.reporter.warning('File insertion disabled', line=self.lineno)
]
# convert options['diff'] to absolute path
if 'diff' in self.options:
_, path = self.env.relfn2path(self.options['diff'])
@ -439,17 +462,23 @@ class LiteralInclude(SphinxDirective):
retnode['language'] = 'udiff'
elif 'language' in self.options:
retnode['language'] = self.options['language']
if ('linenos' in self.options or 'lineno-start' in self.options or
'lineno-match' in self.options):
if (
'linenos' in self.options
or 'lineno-start' in self.options
or 'lineno-match' in self.options
):
retnode['linenos'] = True
retnode['classes'] += self.options.get('class', [])
extra_args = retnode['highlight_args'] = {}
if 'emphasize-lines' in self.options:
hl_lines = parselinenos(self.options['emphasize-lines'], lines)
if any(i >= lines for i in hl_lines):
logger.warning(__('line number spec is out of range(1-%d): %r'),
lines, self.options['emphasize-lines'],
location=location)
logger.warning(
__('line number spec is out of range(1-%d): %r'),
lines,
self.options['emphasize-lines'],
location=location,
)
extra_args['hl_lines'] = [x + 1 for x in hl_lines if x < lines]
extra_args['linenostart'] = reader.lineno_start

View File

@ -112,14 +112,17 @@ class TocTree(SphinxDirective):
if glob and glob_re.match(entry) and not explicit and not url_match:
pat_name = docname_join(current_docname, entry)
doc_names = sorted(
docname for docname in patfilter(all_docnames, pat_name)
docname
for docname in patfilter(all_docnames, pat_name)
# don't include generated documents in globs
if docname not in generated_docnames
)
if not doc_names:
logger.warning(
__("toctree glob pattern %r didn't match any documents"),
entry, location=toctree)
entry,
location=toctree,
)
for docname in doc_names:
all_docnames.remove(docname) # don't include it again
@ -149,22 +152,26 @@ class TocTree(SphinxDirective):
if docname not in frozen_all_docnames:
if excluded(str(self.env.doc2path(docname, False))):
message = __('toctree contains reference to excluded document %r')
msg = __('toctree contains reference to excluded document %r')
subtype = 'excluded'
else:
message = __('toctree contains reference to nonexisting document %r')
msg = __('toctree contains reference to nonexisting document %r')
subtype = 'not_readable'
logger.warning(message, docname, type='toc', subtype=subtype,
location=toctree)
logger.warning(
msg, docname, type='toc', subtype=subtype, location=toctree
)
self.env.note_reread()
continue
if docname in all_docnames:
all_docnames.remove(docname)
else:
logger.warning(__('duplicated entry found in toctree: %s'), docname,
location=toctree)
logger.warning(
__('duplicated entry found in toctree: %s'),
docname,
location=toctree,
)
toctree['entries'].append((title, docname))
toctree['includefiles'].append(docname)
@ -273,8 +280,10 @@ class Acks(SphinxDirective):
def run(self) -> list[Node]:
children = self.parse_content_to_nodes()
if len(children) != 1 or not isinstance(children[0], nodes.bullet_list):
logger.warning(__('.. acks content is not a list'),
location=(self.env.docname, self.lineno))
logger.warning(
__('.. acks content is not a list'),
location=(self.env.docname, self.lineno),
)
return []
return [addnodes.acks('', *children)]
@ -296,8 +305,10 @@ class HList(SphinxDirective):
ncolumns = self.options.get('columns', 2)
children = self.parse_content_to_nodes()
if len(children) != 1 or not isinstance(children[0], nodes.bullet_list):
logger.warning(__('.. hlist content is not a list'),
location=(self.env.docname, self.lineno))
logger.warning(
__('.. hlist content is not a list'),
location=(self.env.docname, self.lineno),
)
return []
fulllist = children[0]
# create a hlist node where the items are distributed
@ -339,13 +350,16 @@ class Only(SphinxDirective):
memo.title_styles = []
memo.section_level = 0
try:
self.state.nested_parse(self.content, self.content_offset,
node, match_titles=True)
self.state.nested_parse(
self.content, self.content_offset, node, match_titles=True
)
title_styles = memo.title_styles
if (not surrounding_title_styles or
not title_styles or
title_styles[0] not in surrounding_title_styles or
not self.state.parent):
if (
not surrounding_title_styles
or not title_styles
or title_styles[0] not in surrounding_title_styles
or not self.state.parent
):
# No nested sections so no special handling needed.
return [node]
# Calculate the depths of the current and nested sections.
@ -380,7 +394,6 @@ class Include(BaseInclude, SphinxDirective):
"""
def run(self) -> Sequence[Node]:
# To properly emit "include-read" events from included RST text,
# we must patch the ``StateMachine.insert_input()`` method.
# In the future, docutils will hopefully offer a way for Sphinx
@ -392,7 +405,7 @@ class Include(BaseInclude, SphinxDirective):
# In docutils 0.18 and later, there are two lines at the end
# that act as markers.
# We must preserve them and leave them out of the include-read event:
text = "\n".join(include_lines[:-2])
text = '\n'.join(include_lines[:-2])
path = Path(relpath(abspath(source), start=self.env.srcdir))
docname = self.env.docname
@ -415,8 +428,7 @@ class Include(BaseInclude, SphinxDirective):
# See https://github.com/python/mypy/issues/2427 for details on the mypy issue
self.state_machine.insert_input = _insert_input
if self.arguments[0].startswith('<') and \
self.arguments[0].endswith('>'):
if self.arguments[0].startswith('<') and self.arguments[0].endswith('>'):
# docutils "standard" includes, do not do path processing
return super().run()
rel_filename, filename = self.env.relfn2path(self.arguments[0])

View File

@ -62,10 +62,14 @@ class CSVTable(tables.CSVTable): # type: ignore[misc]
env = self.state.document.settings.env
filename = self.options['file']
if path.exists(filename):
logger.warning(__('":file:" option for csv-table directive now recognizes '
'an absolute path as a relative path from source directory. '
'Please update your document.'),
location=(env.docname, self.lineno))
logger.warning(
__(
'":file:" option for csv-table directive now recognizes '
'an absolute path as a relative path from source directory. '
'Please update your document.'
),
location=(env.docname, self.lineno),
)
else:
abspath = path.join(env.srcdir, os_path(self.options['file'][1:]))
docdir = path.dirname(env.doc2path(env.docname))
@ -94,10 +98,13 @@ class Code(SphinxDirective):
set_classes(self.options)
code = '\n'.join(self.content)
node = nodes.literal_block(code, code,
classes=self.options.get('classes', []),
force='force' in self.options,
highlight_args={})
node = nodes.literal_block(
code,
code,
classes=self.options.get('classes', []),
force='force' in self.options,
highlight_args={},
)
self.add_name(node)
set_source_info(self, node)
@ -108,8 +115,9 @@ class Code(SphinxDirective):
# no highlight language specified. Then this directive refers the current
# highlight setting via ``highlight`` directive or ``highlight_language``
# configuration.
node['language'] = self.env.temp_data.get('highlight_language',
self.config.highlight_language)
node['language'] = self.env.temp_data.get(
'highlight_language', self.config.highlight_language
)
if 'number-lines' in self.options:
node['linenos'] = True
@ -138,12 +146,15 @@ class MathDirective(SphinxDirective):
if self.arguments and self.arguments[0]:
latex = self.arguments[0] + '\n\n' + latex
label = self.options.get('label', self.options.get('name'))
node = nodes.math_block(latex, latex,
classes=self.options.get('class', []),
docname=self.env.docname,
number=None,
label=label,
nowrap='nowrap' in self.options)
node = nodes.math_block(
latex,
latex,
classes=self.options.get('class', []),
docname=self.env.docname,
number=None,
label=label,
nowrap='nowrap' in self.options,
)
self.add_name(node)
self.set_source_info(node)
@ -157,7 +168,7 @@ class MathDirective(SphinxDirective):
# assign label automatically if math_number_all enabled
if node['label'] == '' or (self.config.math_number_all and not node['label']):
seq = self.env.new_serialno('sphinx.ext.math#equations')
node['label'] = "%s:%d" % (self.env.docname, seq)
node['label'] = f'{self.env.docname}:{seq}'
# no targets and numbers are needed
if not node['label']: