From f7fbfaa4717f7dad907671e42c9cfba615b90c05 Mon Sep 17 00:00:00 2001 From: danieleades <33452915+danieleades@users.noreply.github.com> Date: Sun, 14 Jan 2024 21:13:46 +0000 Subject: [PATCH] Enable various pydocstyle (D) rules (#11878) Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com> --- .ruff.toml | 26 +++++++++++-------- doc/conf.py | 3 +-- sphinx/addnodes.py | 22 +++++++++++++++- sphinx/builders/_epub_base.py | 4 +-- sphinx/builders/changes.py | 1 + sphinx/builders/dirhtml.py | 1 + sphinx/builders/epub3.py | 3 ++- sphinx/builders/gettext.py | 4 +++ sphinx/builders/html/__init__.py | 9 ++++--- sphinx/builders/html/transforms.py | 1 + sphinx/builders/latex/__init__.py | 11 ++++---- sphinx/builders/latex/nodes.py | 8 ++++-- sphinx/builders/latex/transforms.py | 12 +++++++-- sphinx/builders/latex/util.py | 2 +- sphinx/builders/linkcheck.py | 2 +- sphinx/builders/manpage.py | 3 ++- sphinx/builders/singlehtml.py | 1 + sphinx/builders/texinfo.py | 3 ++- sphinx/builders/xml.py | 2 ++ sphinx/cmd/quickstart.py | 1 - sphinx/config.py | 1 + sphinx/deprecation.py | 1 - sphinx/directives/other.py | 8 ++++++ sphinx/directives/patches.py | 1 + sphinx/domains/c.py | 1 + sphinx/domains/changeset.py | 1 + sphinx/domains/citation.py | 2 ++ sphinx/domains/cpp.py | 1 + sphinx/domains/index.py | 2 ++ sphinx/domains/javascript.py | 3 +++ sphinx/domains/math.py | 1 + sphinx/domains/python.py | 2 ++ sphinx/domains/rst.py | 5 ++++ sphinx/domains/std.py | 2 ++ sphinx/environment/__init__.py | 5 ++-- sphinx/environment/adapters/indexentries.py | 4 +-- sphinx/environment/adapters/toctree.py | 3 --- sphinx/environment/collectors/__init__.py | 9 ++++--- sphinx/environment/collectors/asset.py | 2 +- sphinx/errors.py | 13 +++++++++- sphinx/events.py | 1 - sphinx/ext/autodoc/__init__.py | 26 ++++++++++++++++--- sphinx/ext/autodoc/directive.py | 1 + sphinx/ext/autodoc/importer.py | 4 +-- sphinx/ext/autodoc/mock.py | 8 +++--- sphinx/ext/autosummary/__init__.py | 1 + sphinx/ext/autosummary/generate.py | 4 +-- sphinx/ext/coverage.py | 3 ++- sphinx/ext/doctest.py | 4 ++- sphinx/ext/duration.py | 1 + sphinx/ext/graphviz.py | 3 +++ sphinx/ext/inheritance_diagram.py | 3 +++ sphinx/ext/intersphinx.py | 2 -- sphinx/ext/napoleon/__init__.py | 3 ++- sphinx/ext/napoleon/docstring.py | 1 + sphinx/ext/viewcode.py | 1 + sphinx/io.py | 1 + sphinx/locale/__init__.py | 1 + sphinx/project.py | 1 - sphinx/testing/fixtures.py | 1 - sphinx/testing/util.py | 9 ++++--- sphinx/theming.py | 3 ++- sphinx/transforms/__init__.py | 16 ++++++++++++ sphinx/transforms/compact_bullet_list.py | 1 + sphinx/transforms/i18n.py | 5 ++++ sphinx/transforms/post_transforms/__init__.py | 3 +++ sphinx/transforms/post_transforms/code.py | 2 ++ sphinx/transforms/post_transforms/images.py | 1 + sphinx/transforms/references.py | 1 + sphinx/util/__init__.py | 2 ++ sphinx/util/_io.py | 1 + sphinx/util/build_phase.py | 1 + sphinx/util/docfields.py | 4 +++ sphinx/util/docutils.py | 3 +++ sphinx/util/inspect.py | 1 + sphinx/util/logging.py | 10 +++++++ sphinx/util/matching.py | 3 ++- sphinx/util/nodes.py | 2 +- sphinx/util/osutil.py | 7 +++-- sphinx/util/requests.py | 13 ++++++---- sphinx/versioning.py | 1 + sphinx/writers/latex.py | 2 +- sphinx/writers/manpage.py | 1 + sphinx/writers/texinfo.py | 10 ++++--- sphinx/writers/text.py | 20 +++++--------- sphinx/writers/xml.py | 2 +- tests/ext_napoleon_pep526_data_google.py | 2 +- tests/ext_napoleon_pep526_data_numpy.py | 1 + tests/test_addnodes.py | 1 - tests/test_build_epub.py | 1 + tests/test_config.py | 4 --- tests/test_ext_apidoc.py | 15 +++++------ tests/test_ext_autodoc.py | 1 + tests/test_ext_intersphinx.py | 10 ++++--- tests/test_ext_napoleon.py | 2 +- tests/test_ext_napoleon_docstring.py | 3 ++- tests/test_ext_todo.py | 1 - tests/test_transforms_post_transforms.py | 1 + tests/test_util_nodes.py | 4 +-- utils/babel_runner.py | 2 -- 100 files changed, 301 insertions(+), 127 deletions(-) diff --git a/.ruff.toml b/.ruff.toml index b3d92b55aab..5cfb32d67f0 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -73,26 +73,25 @@ select = [ # "D107", # Missing docstring in `__init__` # "D200", # One-line docstring should fit on one line "D201", # No blank lines allowed before function docstring (found {num_lines}) -# "D202", # No blank lines allowed after function docstring (found {num_lines}) -# "D203", # 1 blank line required before class docstring -# "D204", # 1 blank line required after class docstring + "D202", # No blank lines allowed after function docstring (found {num_lines}) + "D204", # 1 blank line required after class docstring # "D205", # 1 blank line required between summary line and description "D206", # Docstring should be indented with spaces, not tabs -# "D207", # Docstring is under-indented -# "D208", # Docstring is over-indented -# "D209", # Multi-line docstring closing quotes should be on a separate line -# "D210", # No whitespaces allowed surrounding docstring text + "D207", # Docstring is under-indented + "D208", # Docstring is over-indented + "D209", # Multi-line docstring closing quotes should be on a separate line + "D210", # No whitespaces allowed surrounding docstring text "D211", # No blank lines allowed before class docstring # "D212", # Multi-line docstring summary should start at the first line # "D213", # Multi-line docstring summary should start at the second line # "D214", # Section is over-indented ("{name}") # "D215", # Section underline is over-indented ("{name}") -# "D300", # Use triple double quotes `"""` -# "D301", # Use `r"""` if any backslashes in a docstring + "D300", # Use triple double quotes `"""` + "D301", # Use `r"""` if any backslashes in a docstring # "D400", # First line should end with a period # "D401", # First line of docstring should be in imperative mood: "{first_line}" -# "D402", # First line should not be the function's signature -# "D403", # First word of the first line should be capitalized: `{}` -> `{}` + "D402", # First line should not be the function's signature + "D403", # First word of the first line should be capitalized: `{}` -> `{}` # "D404", # First word of the docstring should not be "This" "D405", # Section name should be properly capitalized ("{name}") # "D406", # Section name should end with a newline ("{name}") @@ -499,9 +498,14 @@ select = [ # Ruff bug: https://github.com/astral-sh/ruff/issues/6540 "sphinx/transforms/i18n.py" = ["PGH004"] +# Function wrappers +"sphinx/ext/autodoc/importer.py" = ["D402"] +"sphinx/util/requests.py" = ["D402"] + "tests/*" = [ "E501", "ANN", # tests don't need annotations + "D402", "T201", # whitelist ``print`` for tests ] diff --git a/doc/conf.py b/doc/conf.py index 73956aee45f..3015ae23c57 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -210,8 +210,7 @@ def parse_event(env, sig, signode): def linkify_issues_in_changelog(app, docname, source): - """ Linkify issue references like #123 in changelog to GitHub. """ - + """Linkify issue references like #123 in changelog to GitHub.""" if docname == 'changes': changelog_path = os.path.join(os.path.dirname(__file__), "../CHANGES.rst") # this path trickery is needed because this script can diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index 75bf8e5b2f5..28b67f7babf 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -79,6 +79,7 @@ def extract_original_messages(self) -> Sequence[str]: class not_smartquotable: """A node which does not support smart-quotes.""" + support_smartquotes = False @@ -163,6 +164,7 @@ class desc_signature(_desc_classes_injector, nodes.Part, nodes.Inline, nodes.Tex This node always has the classes ``sig``, ``sig-object``, and the domain it belongs to. """ + # Note: the domain name is being added through a post-transform DescSigAddDomainAsClass classes = ['sig', 'sig-object'] @@ -181,6 +183,7 @@ class desc_signature_line(nodes.Part, nodes.Inline, nodes.FixedTextElement): with ``is_multiline`` set to ``True``. Set ``add_permalink = True`` for the line that should get the permalink. """ + sphinx_line_type = '' @@ -199,6 +202,7 @@ class desc_inline(_desc_classes_injector, nodes.Inline, nodes.TextElement): This node always has the classes ``sig``, ``sig-inline``, and the name of the domain it belongs to. """ + classes = ['sig', 'sig-inline'] def __init__(self, domain: str, *args: Any, **kwargs: Any) -> None: @@ -219,6 +223,7 @@ class desc_name(_desc_classes_injector, nodes.Part, nodes.Inline, nodes.FixedTex This node always has the class ``sig-name``. """ + classes = ['sig-name', 'descname'] # 'descname' is for backwards compatibility @@ -230,6 +235,7 @@ class desc_addname(_desc_classes_injector, nodes.Part, nodes.Inline, nodes.Fixed This node always has the class ``sig-prename``. """ + # 'descclassname' is for backwards compatibility classes = ['sig-prename', 'descclassname'] @@ -256,6 +262,7 @@ class desc_parameterlist(nodes.Part, nodes.Inline, nodes.FixedTextElement): Set ``multi_line_parameter_list = True`` to describe a multi-line parameter list. In that case each parameter will then be written on its own, indented line. """ + child_text_separator = ', ' def astext(self) -> str: @@ -269,6 +276,7 @@ class desc_type_parameter_list(nodes.Part, nodes.Inline, nodes.FixedTextElement) Set ``multi_line_parameter_list = True`` to describe a multi-line type parameters list. In that case each type parameter will then be written on its own, indented line. """ + child_text_separator = ', ' def astext(self) -> str: @@ -285,6 +293,7 @@ class desc_type_parameter(nodes.Part, nodes.Inline, nodes.FixedTextElement): class desc_optional(nodes.Part, nodes.Inline, nodes.FixedTextElement): """Node for marking optional parts of the parameter list.""" + child_text_separator = ', ' def astext(self) -> str: @@ -315,6 +324,7 @@ class desc_annotation(nodes.Part, nodes.Inline, nodes.FixedTextElement): class desc_sig_element(nodes.inline, _desc_classes_injector): """Common parent class of nodes for inline text of a signature.""" + classes: list[str] = [] def __init__(self, rawsource: str = '', text: str = '', @@ -334,6 +344,7 @@ def __init_subclass__(cls, *, _sig_element: bool = False, **kwargs: Any): class desc_sig_space(desc_sig_element, _sig_element=True): """Node for a space in a signature.""" + classes = ["w"] def __init__(self, rawsource: str = '', text: str = ' ', @@ -343,41 +354,49 @@ def __init__(self, rawsource: str = '', text: str = ' ', class desc_sig_name(desc_sig_element, _sig_element=True): """Node for an identifier in a signature.""" + classes = ["n"] class desc_sig_operator(desc_sig_element, _sig_element=True): """Node for an operator in a signature.""" + classes = ["o"] class desc_sig_punctuation(desc_sig_element, _sig_element=True): """Node for punctuation in a signature.""" + classes = ["p"] class desc_sig_keyword(desc_sig_element, _sig_element=True): """Node for a general keyword in a signature.""" + classes = ["k"] class desc_sig_keyword_type(desc_sig_element, _sig_element=True): """Node for a keyword which is a built-in type in a signature.""" + classes = ["kt"] class desc_sig_literal_number(desc_sig_element, _sig_element=True): """Node for a numeric literal in a signature.""" + classes = ["m"] class desc_sig_literal_string(desc_sig_element, _sig_element=True): """Node for a string literal in a signature.""" + classes = ["s"] class desc_sig_literal_char(desc_sig_element, _sig_element=True): """Node for a character literal in a signature.""" + classes = ["sc"] @@ -425,7 +444,7 @@ class index(nodes.Invisible, nodes.Inline, nodes.TextElement): class centered(nodes.Part, nodes.TextElement): - """This node is deprecated.""" + """Deprecated.""" class acks(nodes.Element): @@ -479,6 +498,7 @@ class pending_xref(nodes.Inline, nodes.Element): These nodes are resolved before writing output, in BuildEnvironment.resolve_references. """ + child_text_separator = '' diff --git a/sphinx/builders/_epub_base.py b/sphinx/builders/_epub_base.py index aa1b9ec95db..6da64b8da6d 100644 --- a/sphinx/builders/_epub_base.py +++ b/sphinx/builders/_epub_base.py @@ -317,7 +317,8 @@ def make_footnote(doc: nodes.document, label: str, uri: str) -> nodes.footnote: def footnote_spot(tree: nodes.document) -> tuple[Element, int]: """Find or create a spot to place footnotes. - The function returns the tuple (parent, index).""" + The function returns the tuple (parent, index). + """ # The code uses the following heuristic: # a) place them after the last existing footnote # b) place them after an (empty) Footnotes rubric @@ -480,7 +481,6 @@ def content_metadata(self) -> dict[str, Any]: """Create a dictionary with all metadata for the content.opf file properly escaped. """ - if (source_date_epoch := os.getenv('SOURCE_DATE_EPOCH')) is not None: time_tuple = time.gmtime(int(source_date_epoch)) else: diff --git a/sphinx/builders/changes.py b/sphinx/builders/changes.py index 3e24e7dc65c..19d688dd3bf 100644 --- a/sphinx/builders/changes.py +++ b/sphinx/builders/changes.py @@ -26,6 +26,7 @@ class ChangesBuilder(Builder): """ Write a summary with all versionadded/changed directives. """ + name = 'changes' epilog = __('The overview file is in %(outdir)s.') diff --git a/sphinx/builders/dirhtml.py b/sphinx/builders/dirhtml.py index 9683ee6f01e..e4660b449da 100644 --- a/sphinx/builders/dirhtml.py +++ b/sphinx/builders/dirhtml.py @@ -21,6 +21,7 @@ class DirectoryHTMLBuilder(StandaloneHTMLBuilder): a directory given by their pagename, so that generated URLs don't have ``.html`` in them. """ + name = 'dirhtml' def get_target_uri(self, docname: str, typ: str | None = None) -> str: diff --git a/sphinx/builders/epub3.py b/sphinx/builders/epub3.py index 0b438cce7eb..8550b89ff78 100644 --- a/sphinx/builders/epub3.py +++ b/sphinx/builders/epub3.py @@ -75,6 +75,7 @@ class Epub3Builder(_epub_base.EpubBuilder): and META-INF/container.xml. Afterwards, all necessary files are zipped to an epub file. """ + name = 'epub' epilog = __('The ePub file is in %(outdir)s.') @@ -240,7 +241,7 @@ def validate_config_values(app: Sphinx) -> None: def convert_epub_css_files(app: Sphinx, config: Config) -> None: - """This converts string styled epub_css_files to tuple styled one.""" + """Convert string styled epub_css_files to tuple styled one.""" epub_css_files: list[tuple[str, dict[str, Any]]] = [] for entry in config.epub_css_files: if isinstance(entry, str): diff --git a/sphinx/builders/gettext.py b/sphinx/builders/gettext.py index 6f086701f7f..71a700f4089 100644 --- a/sphinx/builders/gettext.py +++ b/sphinx/builders/gettext.py @@ -39,6 +39,7 @@ class Message: """An entry of translatable message.""" + def __init__(self, text: str, locations: list[tuple[str, int]], uuids: list[str]): self.text = text self.locations = locations @@ -119,6 +120,7 @@ class I18nTags(Tags): To translate all text inside of only nodes, this class always returns True value even if no tags are defined. """ + def eval_condition(self, condition: Any) -> bool: return True @@ -127,6 +129,7 @@ class I18nBuilder(Builder): """ General i18n builder. """ + name = 'i18n' versioning_method = 'text' use_message_catalog = False @@ -212,6 +215,7 @@ class MessageCatalogBuilder(I18nBuilder): """ Builds gettext-style message catalogs (.pot files). """ + name = 'gettext' epilog = __('The message catalogs are in %(outdir)s.') diff --git a/sphinx/builders/html/__init__.py b/sphinx/builders/html/__init__.py index bd47c9657f3..c99bdeba04b 100644 --- a/sphinx/builders/html/__init__.py +++ b/sphinx/builders/html/__init__.py @@ -160,6 +160,7 @@ class StandaloneHTMLBuilder(Builder): """ Builds standalone HTML docs. """ + name = 'html' format = 'html' epilog = __('The HTML pages are in %(outdir)s.') @@ -782,7 +783,7 @@ def to_relpath(f: str) -> str: path.join(self.srcdir, src), err) def create_pygments_style_file(self) -> None: - """create a style file for pygments.""" + """Create a style file for pygments.""" with open(path.join(self.outdir, '_static', 'pygments.css'), 'w', encoding="utf-8") as f: f.write(self.highlighter.get_stylesheet()) @@ -863,7 +864,7 @@ def copy_static_files(self) -> None: logger.warning(__('cannot copy static file %r'), err) def copy_extra_files(self) -> None: - """copy html_extra_path files.""" + """Copy html_extra_path files.""" try: with progress_message(__('copying extra files')): excluded = Matcher(self.config.exclude_patterns) @@ -1169,7 +1170,7 @@ def dump_search_index(self) -> None: def convert_html_css_files(app: Sphinx, config: Config) -> None: - """This converts string styled html_css_files to tuple styled one.""" + """Convert string styled html_css_files to tuple styled one.""" html_css_files: list[tuple[str, dict]] = [] for entry in config.html_css_files: if isinstance(entry, str): @@ -1192,7 +1193,7 @@ def _format_modified_time(timestamp: float) -> str: def convert_html_js_files(app: Sphinx, config: Config) -> None: - """This converts string styled html_js_files to tuple styled one.""" + """Convert string styled html_js_files to tuple styled one.""" html_js_files: list[tuple[str, dict]] = [] for entry in config.html_js_files: if isinstance(entry, str): diff --git a/sphinx/builders/html/transforms.py b/sphinx/builders/html/transforms.py index 18a8d380b5b..606d6caa62d 100644 --- a/sphinx/builders/html/transforms.py +++ b/sphinx/builders/html/transforms.py @@ -31,6 +31,7 @@ class KeyboardTransform(SphinxPostTransform): x """ + default_priority = 400 formats = ('html',) pattern = re.compile(r'(?<=.)(-|\+|\^|\s+)(?=.)') diff --git a/sphinx/builders/latex/__init__.py b/sphinx/builders/latex/__init__.py index c86c0fa9dd7..7fbc0e363a4 100644 --- a/sphinx/builders/latex/__init__.py +++ b/sphinx/builders/latex/__init__.py @@ -108,6 +108,7 @@ class LaTeXBuilder(Builder): """ Builds LaTeX output to create PDF. """ + name = 'latex' format = 'latex' epilog = __('The LaTeX files are in %(outdir)s.') @@ -389,7 +390,7 @@ def finish(self) -> None: @progress_message(__('copying TeX support files')) def copy_support_files(self) -> None: - """copy TeX support files from texinputs.""" + """Copy TeX support files from texinputs.""" # configure usage of xindy (impacts Makefile and latexmkrc) # FIXME: convert this rather to a confval with suitable default # according to language ? but would require extra documentation @@ -479,7 +480,7 @@ def install_packages_for_ja(app: Sphinx) -> None: def default_latex_engine(config: Config) -> str: - """ Better default latex_engine settings for specific languages. """ + """Better default latex_engine settings for specific languages.""" if config.language == 'ja': return 'uplatex' if config.language.startswith('zh'): @@ -490,7 +491,7 @@ def default_latex_engine(config: Config) -> str: def default_latex_docclass(config: Config) -> dict[str, str]: - """ Better default latex_docclass settings for specific languages. """ + """Better default latex_docclass settings for specific languages.""" if config.language == 'ja': if config.latex_engine == 'uplatex': return {'manual': 'ujbook', @@ -503,12 +504,12 @@ def default_latex_docclass(config: Config) -> dict[str, str]: def default_latex_use_xindy(config: Config) -> bool: - """ Better default latex_use_xindy settings for specific engines. """ + """Better default latex_use_xindy settings for specific engines.""" return config.latex_engine in {'xelatex', 'lualatex'} def default_latex_documents(config: Config) -> list[tuple[str, str, str, str, str]]: - """ Better default latex_documents settings. """ + """Better default latex_documents settings.""" project = texescape.escape(config.project, config.latex_engine) author = texescape.escape(config.author, config.latex_engine) return [(config.root_doc, diff --git a/sphinx/builders/latex/nodes.py b/sphinx/builders/latex/nodes.py index 2c008b9a749..68b743d4072 100644 --- a/sphinx/builders/latex/nodes.py +++ b/sphinx/builders/latex/nodes.py @@ -5,26 +5,30 @@ class captioned_literal_block(nodes.container): """A node for a container of literal_block having a caption.""" + pass class footnotemark(nodes.Inline, nodes.Referential, nodes.TextElement): - """A node represents ``\footnotemark``.""" + r"""A node represents ``\footnotemark``.""" + pass class footnotetext(nodes.General, nodes.BackLinkable, nodes.Element, nodes.Labeled, nodes.Targetable): - """A node represents ``\footnotetext``.""" + r"""A node represents ``\footnotetext``.""" class math_reference(nodes.Inline, nodes.Referential, nodes.TextElement): """A node for a reference for equation.""" + pass class thebibliography(nodes.container): """A node for wrapping bibliographies.""" + pass diff --git a/sphinx/builders/latex/transforms.py b/sphinx/builders/latex/transforms.py index ca1e4f3a836..99c5f4f316a 100644 --- a/sphinx/builders/latex/transforms.py +++ b/sphinx/builders/latex/transforms.py @@ -31,6 +31,7 @@ class FootnoteDocnameUpdater(SphinxTransform): """Add docname to footnote and footnote_reference nodes.""" + default_priority = 700 TARGET_NODES = (nodes.footnote, nodes.footnote_reference) @@ -59,6 +60,7 @@ class ShowUrlsTransform(SphinxPostTransform): .. note:: This transform is used for integrated doctree """ + default_priority = 400 formats = ('latex',) @@ -509,6 +511,7 @@ class BibliographyTransform(SphinxPostTransform): ... """ + default_priority = 750 formats = ('latex',) @@ -528,6 +531,7 @@ class CitationReferenceTransform(SphinxPostTransform): To handle citation reference easily on LaTeX writer, this converts pending_xref nodes to citation_reference. """ + default_priority = 5 # before ReferencesResolver formats = ('latex',) @@ -548,6 +552,7 @@ class MathReferenceTransform(SphinxPostTransform): To handle math reference easily on LaTeX writer, this converts pending_xref nodes to math_reference. """ + default_priority = 5 # before ReferencesResolver formats = ('latex',) @@ -563,6 +568,7 @@ def run(self, **kwargs: Any) -> None: class LiteralBlockTransform(SphinxPostTransform): """Replace container nodes for literal_block by captioned_literal_block.""" + default_priority = 400 formats = ('latex',) @@ -575,6 +581,7 @@ def run(self, **kwargs: Any) -> None: class DocumentTargetTransform(SphinxPostTransform): """Add :doc label to the first section of each document.""" + default_priority = 400 formats = ('latex',) @@ -586,10 +593,10 @@ def run(self, **kwargs: Any) -> None: class IndexInSectionTitleTransform(SphinxPostTransform): - """Move index nodes in section title to outside of the title. + r"""Move index nodes in section title to outside of the title. LaTeX index macro is not compatible with some handling of section titles - such as uppercasing done on LaTeX side (cf. fncychap handling of ``\\chapter``). + such as uppercasing done on LaTeX side (cf. fncychap handling of ``\chapter``). Moving the index node to after the title node fixes that. Before:: @@ -611,6 +618,7 @@ class IndexInSectionTitleTransform(SphinxPostTransform): blah blah blah ... """ + default_priority = 400 formats = ('latex',) diff --git a/sphinx/builders/latex/util.py b/sphinx/builders/latex/util.py index 01597f99538..aeef2601418 100644 --- a/sphinx/builders/latex/util.py +++ b/sphinx/builders/latex/util.py @@ -35,7 +35,7 @@ def language_name(self, language_code: str) -> str: return 'english' # fallback to english def get_mainlanguage_options(self) -> str | None: - """Return options for polyglossia's ``\\setmainlanguage``.""" + r"""Return options for polyglossia's ``\setmainlanguage``.""" if self.use_polyglossia is False: return None elif self.language == 'german': diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index 3b4813783c9..089bf162b5b 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -59,6 +59,7 @@ class CheckExternalLinksBuilder(DummyBuilder): """ Checks for broken external links. """ + name = 'linkcheck' epilog = __('Look for any errors in the above output or in ' '%(outdir)s/output.txt') @@ -582,7 +583,6 @@ def _get_request_headers( def contains_anchor(response: Response, anchor: str) -> bool: """Determine if an anchor is contained within an HTTP response.""" - parser = AnchorCheckParser(unquote(anchor)) # Read file in chunks. If we find a matching anchor, we break # the loop early in hopes not to have to download the whole thing. diff --git a/sphinx/builders/manpage.py b/sphinx/builders/manpage.py index a5ef29794f6..4b4bc202758 100644 --- a/sphinx/builders/manpage.py +++ b/sphinx/builders/manpage.py @@ -30,6 +30,7 @@ class ManualPageBuilder(Builder): """ Builds groff output in manual page format. """ + name = 'man' format = 'man' epilog = __('The manual pages are in %(outdir)s.') @@ -107,7 +108,7 @@ def finish(self) -> None: def default_man_pages(config: Config) -> list[tuple[str, str, str, list[str], int]]: - """ Better default man_pages settings. """ + """Better default man_pages settings.""" filename = make_filename_from_project(config.project) return [(config.root_doc, filename, f'{config.project} {config.release}', [config.author], 1)] diff --git a/sphinx/builders/singlehtml.py b/sphinx/builders/singlehtml.py index cd669530314..9addbe23db5 100644 --- a/sphinx/builders/singlehtml.py +++ b/sphinx/builders/singlehtml.py @@ -28,6 +28,7 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder): A StandaloneHTMLBuilder subclass that puts the whole document tree on one HTML page. """ + name = 'singlehtml' epilog = __('The HTML page is in %(outdir)s.') diff --git a/sphinx/builders/texinfo.py b/sphinx/builders/texinfo.py index ae4bb7091db..69d412de0aa 100644 --- a/sphinx/builders/texinfo.py +++ b/sphinx/builders/texinfo.py @@ -41,6 +41,7 @@ class TexinfoBuilder(Builder): """ Builds Texinfo output to create Info documentation. """ + name = 'texinfo' format = 'texinfo' epilog = __('The Texinfo files are in %(outdir)s.') @@ -205,7 +206,7 @@ def copy_support_files(self) -> None: def default_texinfo_documents( config: Config, ) -> list[tuple[str, str, str, str, str, str, str]]: - """ Better default texinfo_documents settings. """ + """Better default texinfo_documents settings.""" filename = make_filename_from_project(config.project) return [(config.root_doc, filename, config.project, config.author, filename, 'One line description of project', 'Miscellaneous')] diff --git a/sphinx/builders/xml.py b/sphinx/builders/xml.py index 5b885314787..2e7efdbc914 100644 --- a/sphinx/builders/xml.py +++ b/sphinx/builders/xml.py @@ -29,6 +29,7 @@ class XMLBuilder(Builder): """ Builds Docutils-native XML. """ + name = 'xml' format = 'xml' epilog = __('The XML files are in %(outdir)s.') @@ -101,6 +102,7 @@ class PseudoXMLBuilder(XMLBuilder): """ Builds pseudo-XML for display purposes. """ + name = 'pseudoxml' format = 'pseudoxml' epilog = __('The pseudo-XML files are in %(outdir)s.') diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index fac494ac1ec..f56e95fb146 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -211,7 +211,6 @@ def ask_user(d: dict[str, Any]) -> None: * makefile: make Makefile * batchfile: make command file """ - print(bold(__('Welcome to the Sphinx %s quickstart utility.')) % __display_version__) print() print(__('Please enter values for the following settings (just press Enter to\n' diff --git a/sphinx/config.py b/sphinx/config.py index 28d19dba9dd..5675cfba370 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -71,6 +71,7 @@ class ENUM: Example: app.add_config_value('latex_show_urls', 'no', None, ENUM('no', 'footnote', 'inline')) """ + def __init__(self, *candidates: str | bool | None) -> None: self.candidates = candidates diff --git a/sphinx/deprecation.py b/sphinx/deprecation.py index e36f4dac4d2..088604fab16 100644 --- a/sphinx/deprecation.py +++ b/sphinx/deprecation.py @@ -46,7 +46,6 @@ def __getattr__(name: str) -> Any: _deprecation_warning(__name__, name, canonical_name, remove=remove) return deprecated_object """ - if remove == (8, 0): warning_class: type[Warning] = RemovedInSphinx80Warning elif remove == (9, 0): diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py index 7639406f9a7..d705e0eccd9 100644 --- a/sphinx/directives/other.py +++ b/sphinx/directives/other.py @@ -43,6 +43,7 @@ class TocTree(SphinxDirective): Directive to notify Sphinx about the hierarchical structure of the docs, and to include a table-of-contents like tree in the current document. """ + has_content = True required_arguments = 0 optional_arguments = 0 @@ -173,6 +174,7 @@ class Author(SphinxDirective): Directive to give the name of the author of the current document or section. Shown in the output only if the show_authors option is on. """ + has_content = False required_arguments = 1 optional_arguments = 0 @@ -206,6 +208,7 @@ class SeeAlso(BaseAdmonition): """ An admonition mentioning things to look at as reference. """ + node_class = addnodes.seealso @@ -213,6 +216,7 @@ class TabularColumns(SphinxDirective): """ Directive to give an explicit tabulary column definition to LaTeX. """ + has_content = False required_arguments = 1 optional_arguments = 0 @@ -230,6 +234,7 @@ class Centered(SphinxDirective): """ Directive to create a centered line of bold text. """ + has_content = False required_arguments = 1 optional_arguments = 0 @@ -252,6 +257,7 @@ class Acks(SphinxDirective): """ Directive for a list of names. """ + has_content = True required_arguments = 0 optional_arguments = 0 @@ -274,6 +280,7 @@ class HList(SphinxDirective): """ Directive for a list that gets compacted horizontally. """ + has_content = True required_arguments = 0 optional_arguments = 0 @@ -311,6 +318,7 @@ class Only(SphinxDirective): """ Directive to only include text if the given tag(s) are enabled. """ + has_content = True required_arguments = 1 optional_arguments = 0 diff --git a/sphinx/directives/patches.py b/sphinx/directives/patches.py index 965b385b7ec..b14805c85ce 100644 --- a/sphinx/directives/patches.py +++ b/sphinx/directives/patches.py @@ -80,6 +80,7 @@ class Code(SphinxDirective): This is compatible with docutils' :rst:dir:`code` directive. """ + optional_arguments = 1 option_spec: OptionSpec = { 'class': directives.class_option, diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index 01f4e9fc9a8..e3570e6fc03 100644 --- a/sphinx/domains/c.py +++ b/sphinx/domains/c.py @@ -3721,6 +3721,7 @@ def run(self) -> tuple[list[Node], list[system_message]]: class CDomain(Domain): """C language domain.""" + name = 'c' label = 'C' object_types = { diff --git a/sphinx/domains/changeset.py b/sphinx/domains/changeset.py index 849779516f6..2d594b29605 100644 --- a/sphinx/domains/changeset.py +++ b/sphinx/domains/changeset.py @@ -45,6 +45,7 @@ class VersionChange(SphinxDirective): """ Directive to describe a change/addition/deprecation in a specific version. """ + has_content = True required_arguments = 1 optional_arguments = 1 diff --git a/sphinx/domains/citation.py b/sphinx/domains/citation.py index d12c0f124d0..72e95083d0e 100644 --- a/sphinx/domains/citation.py +++ b/sphinx/domains/citation.py @@ -103,6 +103,7 @@ def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Bui class CitationDefinitionTransform(SphinxTransform): """Mark citation definition labels as not smartquoted.""" + default_priority = 619 def apply(self, **kwargs: Any) -> None: @@ -122,6 +123,7 @@ class CitationReferenceTransform(SphinxTransform): Replace citation references by pending_xref nodes before the default docutils transform tries to resolve them. """ + default_priority = 619 def apply(self, **kwargs: Any) -> None: diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index f5622bef22b..76b19f3f3d0 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -7913,6 +7913,7 @@ class CPPDomain(Domain): object_types dict below. They are the core different types of declarations in C++ that one can document. """ + name = 'cpp' label = 'C++' object_types = { diff --git a/sphinx/domains/index.py b/sphinx/domains/index.py index c084516a645..42ac2b460a7 100644 --- a/sphinx/domains/index.py +++ b/sphinx/domains/index.py @@ -29,6 +29,7 @@ class IndexDomain(Domain): """Mathematics domain.""" + name = 'index' label = 'index' @@ -62,6 +63,7 @@ class IndexDirective(SphinxDirective): """ Directive to add entries to the index. """ + has_content = False required_arguments = 1 optional_arguments = 0 diff --git a/sphinx/domains/javascript.py b/sphinx/domains/javascript.py index 529228be024..e0d879000f0 100644 --- a/sphinx/domains/javascript.py +++ b/sphinx/domains/javascript.py @@ -37,6 +37,7 @@ class JSObject(ObjectDescription[tuple[str, str]]): """ Description of a JavaScript object. """ + #: If set to ``True`` this object is callable and a `desc_parameterlist` is #: added has_arguments = False @@ -247,6 +248,7 @@ def _toc_entry_name(self, sig_node: desc_signature) -> str: class JSCallable(JSObject): """Description of a JavaScript function, method or constructor.""" + has_arguments = True doc_field_types = [ @@ -358,6 +360,7 @@ def process_link(self, env: BuildEnvironment, refnode: Element, class JavaScriptDomain(Domain): """JavaScript language domain.""" + name = 'js' label = 'JavaScript' # if you add a new object type make sure to edit JSObject.get_index_string diff --git a/sphinx/domains/math.py b/sphinx/domains/math.py index d45a35944b8..d266fe06367 100644 --- a/sphinx/domains/math.py +++ b/sphinx/domains/math.py @@ -34,6 +34,7 @@ def result_nodes(self, document: nodes.document, env: BuildEnvironment, node: El class MathDomain(Domain): """Mathematics domain.""" + name = 'math' label = 'mathematics' diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index ebf6dd9f706..aa1e0260e95 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -667,6 +667,7 @@ class PyObject(ObjectDescription[tuple[str, str]]): :cvar allow_nesting: Class is an object that allows for nested namespaces :vartype allow_nesting: bool """ + option_spec: OptionSpec = { 'no-index': directives.flag, 'no-index-entry': directives.flag, @@ -1452,6 +1453,7 @@ def generate(self, docnames: Iterable[str] | None = None, class PythonDomain(Domain): """Python language domain.""" + name = 'py' label = 'Python' object_types: dict[str, ObjType] = { diff --git a/sphinx/domains/rst.py b/sphinx/domains/rst.py index 480aba5251f..b96c9067cab 100644 --- a/sphinx/domains/rst.py +++ b/sphinx/domains/rst.py @@ -35,6 +35,7 @@ class ReSTMarkup(ObjectDescription[str]): """ Description of generic reST markup. """ + option_spec: OptionSpec = { 'no-index': directives.flag, 'no-index-entry': directives.flag, @@ -112,6 +113,7 @@ class ReSTDirective(ReSTMarkup): """ Description of a reST directive. """ + def handle_signature(self, sig: str, signode: desc_signature) -> str: name, args = parse_directive(sig) desc_name = f'.. {name}::' @@ -139,6 +141,7 @@ class ReSTDirectiveOption(ReSTMarkup): """ Description of an option for reST directive. """ + option_spec: OptionSpec = ReSTMarkup.option_spec.copy() option_spec.update({ 'type': directives.unchanged, @@ -199,6 +202,7 @@ class ReSTRole(ReSTMarkup): """ Description of a reST role. """ + def handle_signature(self, sig: str, signode: desc_signature) -> str: desc_name = f':{sig}:' signode['fullname'] = sig.strip() @@ -211,6 +215,7 @@ def get_index_text(self, objectname: str, name: str) -> str: class ReSTDomain(Domain): """ReStructuredText domain.""" + name = 'rst' label = 'reStructuredText' diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py index fc09f4ac0c3..e132e484a9f 100644 --- a/sphinx/domains/std.py +++ b/sphinx/domains/std.py @@ -43,6 +43,7 @@ class GenericObject(ObjectDescription[str]): """ A generic x-ref directive registered with Sphinx.add_object_type(). """ + indextemplate: str = '' parse_node: Callable[[BuildEnvironment, str, desc_signature], str] | None = None @@ -104,6 +105,7 @@ class Target(SphinxDirective): """ Generic target for user-defined cross-reference types. """ + indextemplate = '' has_content = False diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 2e9e7919344..c96ea142c68 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -340,7 +340,7 @@ def _update_settings(self, config: Config) -> None: self.settings.setdefault('smart_quotes', True) def set_versioning_method(self, method: str | Callable, compare: bool) -> None: - """This sets the doctree versioning method for this environment. + """Set the doctree versioning method for this environment. Versioning methods are a builder property; only builders with the same versioning method can share the same doctree directory. Therefore, we @@ -426,7 +426,7 @@ def relfn2path(self, filename: str, docname: str | None = None) -> tuple[str, st @property def found_docs(self) -> set[str]: - """contains all existing docnames.""" + """Contains all existing docnames.""" return self.project.docnames def find_files(self, config: Config, builder: Builder) -> None: @@ -745,7 +745,6 @@ def _last_modified_time(filename: str | os.PathLike[str]) -> int: We prefer to err on the side of re-rendering a file, so we round up to the nearest microsecond. """ - # upside-down floor division to get the ceiling return -(os.stat(filename).st_mtime_ns // -1_000) diff --git a/sphinx/environment/adapters/indexentries.py b/sphinx/environment/adapters/indexentries.py index 6fdbea6fa5d..a12e131fb73 100644 --- a/sphinx/environment/adapters/indexentries.py +++ b/sphinx/environment/adapters/indexentries.py @@ -129,7 +129,7 @@ def _add_entry(word: str, subword: str, main: str | None, *, def _key_func_0(entry: tuple[str, str]) -> tuple[bool, str]: - """sort the index entries for same keyword.""" + """Sort the index entries for same keyword.""" main, uri = entry return not main, uri # show main entries at first @@ -156,7 +156,7 @@ def _key_func_1(entry: tuple[str, list]) -> tuple[tuple[int, str], str]: def _key_func_2(entry: tuple[str, list]) -> str: - """sort the sub-index entries""" + """Sort the sub-index entries""" key = unicodedata.normalize('NFD', entry[0].lower()) if key.startswith('\N{RIGHT-TO-LEFT MARK}'): key = key[1:] diff --git a/sphinx/environment/adapters/toctree.py b/sphinx/environment/adapters/toctree.py index e50d10b7783..afdf4a18da4 100644 --- a/sphinx/environment/adapters/toctree.py +++ b/sphinx/environment/adapters/toctree.py @@ -47,7 +47,6 @@ def document_toc(env: BuildEnvironment, docname: str, tags: Tags) -> Node: For a ToC tree that shows the document's place in the ToC structure, use `get_toctree_for`. """ - tocdepth = env.metadata[docname].get('tocdepth', 0) try: toc = _toctree_copy(env.tocs[docname], 2, tocdepth, False, tags) @@ -74,7 +73,6 @@ def global_toctree_for_doc( This gives the global ToC, with all ancestors and their siblings. """ - toctrees: list[Element] = [] for toctree_node in env.master_doctree.findall(addnodes.toctree): if toctree := _resolve_toctree( @@ -113,7 +111,6 @@ def _resolve_toctree( If *collapse* is True, all branches not containing docname will be collapsed. """ - if toctree.get('hidden', False) and not includehidden: return None diff --git a/sphinx/environment/collectors/__init__.py b/sphinx/environment/collectors/__init__.py index c7e069a36e7..c12dd50b3e6 100644 --- a/sphinx/environment/collectors/__init__.py +++ b/sphinx/environment/collectors/__init__.py @@ -41,19 +41,22 @@ def disable(self, app: Sphinx) -> None: def clear_doc(self, app: Sphinx, env: BuildEnvironment, docname: str) -> None: """Remove specified data of a document. - This method is called on the removal of the document.""" + This method is called on the removal of the document. + """ raise NotImplementedError def merge_other(self, app: Sphinx, env: BuildEnvironment, docnames: set[str], other: BuildEnvironment) -> None: """Merge in specified data regarding docnames from a different `BuildEnvironment` - object which coming from a subprocess in parallel builds.""" + object which coming from a subprocess in parallel builds. + """ raise NotImplementedError def process_doc(self, app: Sphinx, doctree: nodes.document) -> None: """Process a document and gather specific data from it. - This method is called after the document is read.""" + This method is called after the document is read. + """ raise NotImplementedError def get_updated_docs(self, app: Sphinx, env: BuildEnvironment) -> list[str]: diff --git a/sphinx/environment/collectors/asset.py b/sphinx/environment/collectors/asset.py index c2066f4122e..358c6b43ee9 100644 --- a/sphinx/environment/collectors/asset.py +++ b/sphinx/environment/collectors/asset.py @@ -121,7 +121,7 @@ def merge_other(self, app: Sphinx, env: BuildEnvironment, env.dlfiles.merge_other(docnames, other.dlfiles) def process_doc(self, app: Sphinx, doctree: nodes.document) -> None: - """Process downloadable file paths. """ + """Process downloadable file paths.""" for node in doctree.findall(addnodes.download_reference): targetname = node['reftarget'] if '://' in targetname: diff --git a/sphinx/errors.py b/sphinx/errors.py index 5db68dd1714..2958408e09a 100644 --- a/sphinx/errors.py +++ b/sphinx/errors.py @@ -25,16 +25,19 @@ class SphinxError(Exception): exception to a string ("category: message"). Should be set accordingly in subclasses. """ + category = 'Sphinx error' class SphinxWarning(SphinxError): """Warning, treated as error.""" + category = 'Warning, treated as error' class ApplicationError(SphinxError): """Application initialization error.""" + category = 'Application error' @@ -70,26 +73,31 @@ def __str__(self) -> str: class BuildEnvironmentError(SphinxError): """BuildEnvironment error.""" + category = 'BuildEnvironment error' class ConfigError(SphinxError): """Configuration error.""" + category = 'Configuration error' class DocumentError(SphinxError): """Document error.""" + category = 'Document error' class ThemeError(SphinxError): """Theme error.""" + category = 'Theme error' class VersionRequirementError(SphinxError): """Incompatible Sphinx version error.""" + category = 'Sphinx version error' @@ -118,10 +126,13 @@ def __str__(self) -> str: class NoUri(Exception): """Raised by builder.get_relative_uri() or from missing-reference handlers - if there is no URI available.""" + if there is no URI available. + """ + pass class FiletypeNotFoundError(Exception): """Raised by get_filetype() if a filename matches no source suffix.""" + pass diff --git a/sphinx/events.py b/sphinx/events.py index f406a399d7b..91154d18576 100644 --- a/sphinx/events.py +++ b/sphinx/events.py @@ -84,7 +84,6 @@ def disconnect(self, listener_id: int) -> None: def emit(self, name: str, *args: Any, allowed_exceptions: tuple[type[Exception], ...] = ()) -> list: """Emit a Sphinx event.""" - # not every object likes to be repr()'d (think # random stuff coming via autodoc) with contextlib.suppress(Exception): diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 53fbac6efb1..7b30047405a 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -245,6 +245,7 @@ def process(app: Sphinx, what_: str, name: str, obj: Any, options: Any, lines: l # But we define this class here to keep compatibility (see #4538) class Options(dict): """A dict/attribute hybrid that returns None on nonexisting keys.""" + def copy(self) -> Options: return Options(super().copy()) @@ -299,6 +300,7 @@ class Documenter: in fact, it will be used to parse an auto directive's options that matches the Documenter. """ + #: name by which the directive is called (auto...) and the default #: generated directive name objtype = 'object' @@ -969,6 +971,7 @@ class ModuleDocumenter(Documenter): """ Specialized Documenter subclass for modules. """ + objtype = 'module' content_indent = '' _extra_indent = ' ' @@ -1131,6 +1134,7 @@ class ModuleLevelDocumenter(Documenter): Specialized Documenter subclass for objects on module level (functions, classes, data/constants). """ + def resolve_name(self, modname: str | None, parents: Any, path: str, base: str, ) -> tuple[str | None, list[str]]: if modname is not None: @@ -1154,6 +1158,7 @@ class ClassLevelDocumenter(Documenter): Specialized Documenter subclass for objects on class level (methods, attributes). """ + def resolve_name(self, modname: str | None, parents: Any, path: str, base: str, ) -> tuple[str | None, list[str]]: if modname is not None: @@ -1189,6 +1194,7 @@ class DocstringSignatureMixin: Mixin for FunctionDocumenter and MethodDocumenter to provide the feature of reading the signature from the docstring. """ + _new_docstrings: list[list[str]] | None = None _signatures: list[str] = [] @@ -1270,6 +1276,7 @@ class DocstringStripSignatureMixin(DocstringSignatureMixin): Mixin for AttributeDocumenter to provide the feature of stripping any function signature from the docstring. """ + def format_signature(self, **kwargs: Any) -> str: if ( self.args is None @@ -1290,6 +1297,7 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ """ Specialized Documenter subclass for functions. """ + objtype = 'function' member_order = 30 @@ -1419,6 +1427,7 @@ class DecoratorDocumenter(FunctionDocumenter): """ Specialized Documenter subclass for decorator functions. """ + objtype = 'decorator' # must be lower than FunctionDocumenter @@ -1450,6 +1459,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: """ Specialized Documenter subclass for classes. """ + objtype = 'class' member_order = 20 option_spec: OptionSpec = { @@ -1515,7 +1525,7 @@ def _get_signature(self) -> tuple[Any | None, str | None, Signature | None]: return None, None, None def get_user_defined_function_or_method(obj: Any, attr: str) -> Any: - """ Get the `attr` function or method from `obj`, if it is user-defined. """ + """Get the `attr` function or method from `obj`, if it is user-defined.""" if inspect.is_builtin_class_method(obj, attr): return None attr = self.get_attr(obj, attr, None) @@ -1910,6 +1920,7 @@ class ExceptionDocumenter(ClassDocumenter): """ Specialized ClassDocumenter subclass for exceptions. """ + objtype = 'exception' member_order = 10 @@ -2023,6 +2034,7 @@ class DataDocumenter(GenericAliasMixin, """ Specialized Documenter subclass for data items. """ + objtype = 'data' member_order = 40 priority = -10 @@ -2144,6 +2156,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: """ Specialized Documenter subclass for methods (normal, static and class). """ + objtype = 'method' directivetype = 'method' member_order = 50 @@ -2474,7 +2487,8 @@ def is_runtime_instance_attribute_not_commented(self, parent: Any) -> bool: def import_object(self, raiseerror: bool = False) -> bool: """Check the existence of runtime instance attribute after failing to import the - attribute.""" + attribute. + """ try: return super().import_object(raiseerror=True) # type: ignore[misc] except ImportError as exc: @@ -2527,7 +2541,8 @@ def is_uninitialized_instance_attribute(self, parent: Any) -> bool: def import_object(self, raiseerror: bool = False) -> bool: """Check the exisitence of uninitialized instance attribute when failed to import - the attribute.""" + the attribute. + """ try: return super().import_object(raiseerror=True) # type: ignore[misc] except ImportError as exc: @@ -2566,6 +2581,7 @@ class AttributeDocumenter(GenericAliasMixin, SlotsMixin, # type: ignore[misc] """ Specialized Documenter subclass for attributes. """ + objtype = 'attribute' member_order = 60 option_spec: OptionSpec = dict(ModuleLevelDocumenter.option_spec) @@ -2723,6 +2739,7 @@ class PropertyDocumenter(DocstringStripSignatureMixin, # type: ignore[misc] """ Specialized Documenter subclass for properties. """ + objtype = 'property' member_order = 60 @@ -2745,7 +2762,8 @@ def can_document_member( def import_object(self, raiseerror: bool = False) -> bool: """Check the exisitence of uninitialized instance attribute when failed to import - the attribute.""" + the attribute. + """ ret = super().import_object(raiseerror) if ret and not inspect.isproperty(self.object): __dict__ = safe_getattr(self.parent, '__dict__', {}) diff --git a/sphinx/ext/autodoc/directive.py b/sphinx/ext/autodoc/directive.py index 64cbc9b52cd..e168eb5a073 100644 --- a/sphinx/ext/autodoc/directive.py +++ b/sphinx/ext/autodoc/directive.py @@ -104,6 +104,7 @@ class AutodocDirective(SphinxDirective): It invokes a Documenter upon running. After the processing, it parses and returns the content generated by Documenter. """ + option_spec = DummyOptionSpec() has_content = True required_arguments = 1 diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index 3e36ff74182..cdc357a26c4 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -61,9 +61,7 @@ def unmangle(subject: Any, name: str) -> str | None: def import_module(modname: str, warningiserror: bool = False) -> Any: - """ - Call importlib.import_module(modname), convert exceptions to ImportError - """ + """Call importlib.import_module(modname), convert exceptions to ImportError.""" try: with logging.skip_warningiserror(not warningiserror): return importlib.import_module(modname) diff --git a/sphinx/ext/autodoc/mock.py b/sphinx/ext/autodoc/mock.py index 7034977c334..4036bd58826 100644 --- a/sphinx/ext/autodoc/mock.py +++ b/sphinx/ext/autodoc/mock.py @@ -80,6 +80,7 @@ def _make_subclass(name: str, module: str, superclass: Any = _MockObject, class _MockModule(ModuleType): """Used by autodoc_mock_imports.""" + __file__ = os.devnull __sphinx_mock__ = True @@ -97,6 +98,7 @@ def __repr__(self) -> str: class MockLoader(Loader): """A loader for mocking.""" + def __init__(self, finder: MockFinder) -> None: super().__init__() self.finder = finder @@ -138,9 +140,9 @@ def invalidate_caches(self) -> None: def mock(modnames: list[str]) -> Generator[None, None, None]: """Insert mock modules during context:: - with mock(['target.module.name']): - # mock modules are enabled here - ... + with mock(['target.module.name']): + # mock modules are enabled here + ... """ try: finder = MockFinder(modnames) diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index 2da8fd828b6..bac5cf1ef97 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -745,6 +745,7 @@ class AutoLink(SphinxRole): Expands to ':obj:`text`' if `text` is an object that can be imported; otherwise expands to '*text*'. """ + def run(self) -> tuple[list[Node], list[system_message]]: pyobj_role = self.env.get_domain('py').role('obj') assert pyobj_role is not None diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 2a769e47ab0..9ebb0cfb963 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -248,8 +248,8 @@ def scan(self, imported_members: bool) -> list[str]: def members_of(obj: Any, conf: Config) -> Sequence[str]: """Get the members of ``obj``, possibly ignoring the ``__all__`` module attribute - Follows the ``conf.autosummary_ignore_module_all`` setting.""" - + Follows the ``conf.autosummary_ignore_module_all`` setting. + """ if conf.autosummary_ignore_module_all: return dir(obj) else: diff --git a/sphinx/ext/coverage.py b/sphinx/ext/coverage.py index 67432ccfc84..91d8bba78a8 100644 --- a/sphinx/ext/coverage.py +++ b/sphinx/ext/coverage.py @@ -69,6 +69,7 @@ class CoverageBuilder(Builder): """ Evaluates coverage of code in the documentation. """ + name = 'coverage' epilog = __('Testing of coverage in the sources finished, look at the ' 'results in %(outdir)s' + path.sep + 'python.txt.') @@ -270,7 +271,7 @@ def build_py_coverage(self) -> None: self.py_documented[mod_name] = documented_objects def _write_py_statistics(self, op: TextIO) -> None: - """ Outputs the table of ``op``.""" + """Outputs the table of ``op``.""" all_modules = set(self.py_documented.keys()).union( set(self.py_undocumented.keys())) all_objects: set[str] = set() diff --git a/sphinx/ext/doctest.py b/sphinx/ext/doctest.py index 8e5198b5265..f60bd16d19a 100644 --- a/sphinx/ext/doctest.py +++ b/sphinx/ext/doctest.py @@ -276,6 +276,7 @@ class DocTestBuilder(Builder): """ Runs test snippets in the documentation. """ + name = 'doctest' epilog = __('Testing of doctests in the sources finished, look at the ' 'results in %(outdir)s/output.txt.') @@ -361,7 +362,8 @@ def write(self, build_docnames: Iterable[str] | None, updated_docnames: Sequence def get_filename_for_node(self, node: Node, docname: str) -> str: """Try to get the file which actually contains the doctest, not the - filename of the document it's included in.""" + filename of the document it's included in. + """ try: filename = relpath(node.source, self.env.srcdir)\ .rsplit(':docstring of ', maxsplit=1)[0] diff --git a/sphinx/ext/duration.py b/sphinx/ext/duration.py index 26e197f7465..22435797872 100644 --- a/sphinx/ext/duration.py +++ b/sphinx/ext/duration.py @@ -22,6 +22,7 @@ class DurationDomain(Domain): """A domain for durations of Sphinx processing.""" + name = 'duration' @property diff --git a/sphinx/ext/graphviz.py b/sphinx/ext/graphviz.py index 528bf30cbf6..7c2d750732c 100644 --- a/sphinx/ext/graphviz.py +++ b/sphinx/ext/graphviz.py @@ -47,6 +47,7 @@ class GraphvizError(SphinxError): class ClickableMapDefinition: """A manipulator for clickable map file of graphviz.""" + maptag_re = re.compile(' nodes.reference | None: """Attempt to resolve a missing reference via intersphinx references.""" - return resolve_reference_detect_inventory(env, node, contnode) diff --git a/sphinx/ext/napoleon/__init__.py b/sphinx/ext/napoleon/__init__.py index 777838cb6fd..6d1cf594945 100644 --- a/sphinx/ext/napoleon/__init__.py +++ b/sphinx/ext/napoleon/__init__.py @@ -264,7 +264,8 @@ def __unicode__(self): Use the type annotations of class attributes that are documented in the docstring but do not have a type in the docstring. - """ + """ # NoQA: D301 + _config_values: dict[str, tuple[Any, _ConfigRebuild]] = { 'napoleon_google_docstring': (True, 'env'), 'napoleon_numpy_docstring': (True, 'env'), diff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py index 6841e676f80..56176a871b8 100644 --- a/sphinx/ext/napoleon/docstring.py +++ b/sphinx/ext/napoleon/docstring.py @@ -1157,6 +1157,7 @@ class NumpyDocstring(GoogleDocstring): The lines of the docstring in a list. """ + def __init__( self, docstring: str | list[str], diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py index 56e31e692c4..0d66ad66ecc 100644 --- a/sphinx/ext/viewcode.py +++ b/sphinx/ext/viewcode.py @@ -185,6 +185,7 @@ def env_purge_doc(app: Sphinx, env: BuildEnvironment, docname: str) -> None: class ViewcodeAnchorTransform(SphinxPostTransform): """Convert or remove viewcode_anchor nodes depends on builder.""" + default_priority = 100 def run(self, **kwargs: Any) -> None: diff --git a/sphinx/io.py b/sphinx/io.py index 4874fdf3990..a78b4801a96 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -152,6 +152,7 @@ def SphinxDummySourceClass(source: Any, *args: Any, **kwargs: Any) -> Any: class SphinxFileInput(FileInput): """A basic FileInput for Sphinx.""" + def __init__(self, *args: Any, **kwargs: Any) -> None: kwargs['error_handler'] = 'sphinx' super().__init__(*args, **kwargs) diff --git a/sphinx/locale/__init__.py b/sphinx/locale/__init__.py index 7ea9f774e3d..b0d34b69810 100644 --- a/sphinx/locale/__init__.py +++ b/sphinx/locale/__init__.py @@ -17,6 +17,7 @@ class _TranslationProxy: The proxy implementation attempts to be as complete as possible, so that the lazy objects should mostly work as expected, for example for sorting. """ + __slots__ = '_catalogue', '_namespace', '_message' def __init__(self, catalogue: str, namespace: str, message: str) -> None: diff --git a/sphinx/project.py b/sphinx/project.py index 57813fafff6..3658002a85e 100644 --- a/sphinx/project.py +++ b/sphinx/project.py @@ -48,7 +48,6 @@ def discover(self, exclude_paths: Iterable[str] = (), """Find all document files in the source directory and put them in :attr:`docnames`. """ - self.docnames.clear() self._path_to_docname.clear() self._docname_to_path.clear() diff --git a/sphinx/testing/fixtures.py b/sphinx/testing/fixtures.py index 6140dfd2fdc..8949537f2be 100644 --- a/sphinx/testing/fixtures.py +++ b/sphinx/testing/fixtures.py @@ -66,7 +66,6 @@ def app_params(request: Any, test_params: dict, shared_result: SharedResult, Parameters that are specified by 'pytest.mark.sphinx' for sphinx.application.Sphinx initialization """ - # ##### process pytest.mark.sphinx pargs: dict[int, Any] = {} diff --git a/sphinx/testing/util.py b/sphinx/testing/util.py index a704afbea2d..eca82e58137 100644 --- a/sphinx/testing/util.py +++ b/sphinx/testing/util.py @@ -75,6 +75,7 @@ class SphinxTestApp(application.Sphinx): A subclass of :class:`Sphinx` that runs on the test root, with some better default values for the initialization parameters. """ + _status: StringIO _warning: StringIO @@ -148,10 +149,10 @@ def build(self, force_all: bool = False, filenames: list[str] | None = None) -> class SphinxTestAppWrapperForSkipBuilding: - """ - This class is a wrapper for SphinxTestApp to speed up the test by skipping - `app.build` process if it is already built and there is even one output - file. + """A wrapper for SphinxTestApp. + + This class is used to speed up the test by skipping ``app.build()`` + if it has already been built and there are any output files. """ def __init__(self, app_: SphinxTestApp) -> None: diff --git a/sphinx/theming.py b/sphinx/theming.py index a8ff7281249..49bf22eb2d1 100644 --- a/sphinx/theming.py +++ b/sphinx/theming.py @@ -52,7 +52,8 @@ def extract_zip(filename: str, targetdir: str) -> None: class Theme: """A Theme is a set of HTML templates and configurations. - This class supports both theme directory and theme archive (zipped theme).""" + This class supports both theme directory and theme archive (zipped theme). + """ def __init__(self, name: str, theme_path: str, factory: HTMLThemeFactory) -> None: self.name = name diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py index 8a806cd0390..d72e0697e45 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -98,6 +98,7 @@ class DefaultSubstitutions(SphinxTransform): """ Replace some substitutions if they aren't defined in the document. """ + # run before the default Substitutions default_priority = 210 @@ -139,6 +140,7 @@ class MoveModuleTargets(SphinxTransform): XXX Python specific """ + default_priority = 210 def apply(self, **kwargs: Any) -> None: @@ -161,6 +163,7 @@ class HandleCodeBlocks(SphinxTransform): """ Several code block related transformations. """ + default_priority = 210 def apply(self, **kwargs: Any) -> None: @@ -185,6 +188,7 @@ class AutoNumbering(SphinxTransform): """ Register IDs of tables, figures and literal_blocks to assign numbers. """ + default_priority = 210 def apply(self, **kwargs: Any) -> None: @@ -201,6 +205,7 @@ class SortIds(SphinxTransform): """ Sort section IDs so that the "id[0-9]+" one comes last. """ + default_priority = 261 def apply(self, **kwargs: Any) -> None: @@ -222,6 +227,7 @@ class ApplySourceWorkaround(SphinxTransform): """ Update source and rawsource attributes """ + default_priority = 10 def apply(self, **kwargs: Any) -> None: @@ -234,6 +240,7 @@ class AutoIndexUpgrader(SphinxTransform): """ Detect old style (4 column based indices) and automatically upgrade to new style. """ + default_priority = 210 def apply(self, **kwargs: Any) -> None: @@ -251,6 +258,7 @@ class ExtraTranslatableNodes(SphinxTransform): """ Make nodes translatable """ + default_priority = 10 def apply(self, **kwargs: Any) -> None: @@ -270,6 +278,7 @@ class UnreferencedFootnotesDetector(SphinxTransform): """ Detect unreferenced footnotes and emit warnings """ + default_priority = 200 def apply(self, **kwargs: Any) -> None: @@ -291,6 +300,7 @@ def apply(self, **kwargs: Any) -> None: class DoctestTransform(SphinxTransform): """Set "doctest" style to each doctest_block node""" + default_priority = 500 def apply(self, **kwargs: Any) -> None: @@ -300,6 +310,7 @@ def apply(self, **kwargs: Any) -> None: class FilterSystemMessages(SphinxTransform): """Filter system messages from a doctree.""" + default_priority = 999 def apply(self, **kwargs: Any) -> None: @@ -315,6 +326,7 @@ class SphinxContentsFilter(ContentsFilter): Used with BuildEnvironment.add_toc_from() to discard cross-file links within table-of-contents link nodes. """ + visit_pending_xref = ContentsFilter.ignore_node_but_process_children def visit_image(self, node: nodes.image) -> None: @@ -327,6 +339,7 @@ class SphinxSmartQuotes(SmartQuotes, SphinxTransform): refs: sphinx.parsers.RSTParser """ + default_priority = 750 def apply(self, **kwargs: Any) -> None: @@ -377,6 +390,7 @@ def get_tokens(self, txtnodes: list[Text]) -> Generator[tuple[str, str], None, N class DoctreeReadEvent(SphinxTransform): """Emit :event:`doctree-read` event.""" + default_priority = 880 def apply(self, **kwargs: Any) -> None: @@ -385,6 +399,7 @@ def apply(self, **kwargs: Any) -> None: class ManpageLink(SphinxTransform): """Find manpage section numbers and names""" + default_priority = 999 def apply(self, **kwargs: Any) -> None: @@ -403,6 +418,7 @@ def apply(self, **kwargs: Any) -> None: class GlossarySorter(SphinxTransform): """Sort glossaries that have the ``sorted`` flag.""" + # This must be done after i18n, therefore not right # away in the glossary directive. default_priority = 500 diff --git a/sphinx/transforms/compact_bullet_list.py b/sphinx/transforms/compact_bullet_list.py index 09b41b3ff45..ca34826a7b7 100644 --- a/sphinx/transforms/compact_bullet_list.py +++ b/sphinx/transforms/compact_bullet_list.py @@ -53,6 +53,7 @@ class RefOnlyBulletListTransform(SphinxTransform): Specifically implemented for 'Indices and Tables' section, which looks odd when html_compact_lists is false. """ + default_priority = 100 def apply(self, **kwargs: Any) -> None: diff --git a/sphinx/transforms/i18n.py b/sphinx/transforms/i18n.py index d26c2794800..d46e515599d 100644 --- a/sphinx/transforms/i18n.py +++ b/sphinx/transforms/i18n.py @@ -95,6 +95,7 @@ class PreserveTranslatableMessages(SphinxTransform): """ Preserve original translatable messages before translation """ + default_priority = 10 # this MUST be invoked before Locale transform def apply(self, **kwargs: Any) -> None: @@ -339,6 +340,7 @@ class Locale(SphinxTransform): """ Replace translatable nodes with their translated doctree. """ + default_priority = 20 def apply(self, **kwargs: Any) -> None: @@ -538,6 +540,7 @@ class TranslationProgressTotaliser(SphinxTransform): """ Calculate the number of translated and untranslated nodes. """ + default_priority = 25 # MUST happen after Locale def apply(self, **kwargs: Any) -> None: @@ -561,6 +564,7 @@ class AddTranslationClasses(SphinxTransform): """ Add ``translated`` or ``untranslated`` classes to indicate translation status. """ + default_priority = 950 def apply(self, **kwargs: Any) -> None: @@ -597,6 +601,7 @@ class RemoveTranslatableInline(SphinxTransform): """ Remove inline nodes used for translation as placeholders. """ + default_priority = 999 def apply(self, **kwargs: Any) -> None: diff --git a/sphinx/transforms/post_transforms/__init__.py b/sphinx/transforms/post_transforms/__init__.py index f699196babd..70c26d3a67a 100644 --- a/sphinx/transforms/post_transforms/__init__.py +++ b/sphinx/transforms/post_transforms/__init__.py @@ -33,6 +33,7 @@ class SphinxPostTransform(SphinxTransform): They resolve references, convert images, do special transformation for each output formats and so on. This class helps to implement these post transforms. """ + builders: tuple[str, ...] = () formats: tuple[str, ...] = () @@ -234,6 +235,7 @@ def run(self, **kwargs: Any) -> None: class SigElementFallbackTransform(SphinxPostTransform): """Fallback various desc_* nodes to inline if translator does not support them.""" + default_priority = 200 def run(self, **kwargs: Any) -> None: @@ -276,6 +278,7 @@ def fallback(self, node_type: Any) -> None: class PropagateDescDomain(SphinxPostTransform): """Add the domain name of the parent node as a class in each desc_signature node.""" + default_priority = 200 def run(self, **kwargs: Any) -> None: diff --git a/sphinx/transforms/post_transforms/code.py b/sphinx/transforms/post_transforms/code.py index cd8abcc670a..047766a1126 100644 --- a/sphinx/transforms/post_transforms/code.py +++ b/sphinx/transforms/post_transforms/code.py @@ -32,6 +32,7 @@ class HighlightLanguageTransform(SphinxTransform): :rst:dir:`highlight` directive. After processing, this transform removes ``highlightlang`` node from doctree. """ + default_priority = 400 def apply(self, **kwargs: Any) -> None: @@ -88,6 +89,7 @@ class TrimDoctestFlagsTransform(SphinxTransform): see :confval:`trim_doctest_flags` for more information. """ + default_priority = HighlightLanguageTransform.default_priority + 1 def apply(self, **kwargs: Any) -> None: diff --git a/sphinx/transforms/post_transforms/images.py b/sphinx/transforms/post_transforms/images.py index f98514f9c23..c70254b42a1 100644 --- a/sphinx/transforms/post_transforms/images.py +++ b/sphinx/transforms/post_transforms/images.py @@ -173,6 +173,7 @@ class ImageConverter(BaseImageConverter): 3. Register your image converter to Sphinx using :py:meth:`.Sphinx.add_post_transform` """ + default_priority = 200 #: The converter is available or not. Will be filled at the first call of diff --git a/sphinx/transforms/references.py b/sphinx/transforms/references.py index 5de3a9515b2..fdada70ffd0 100644 --- a/sphinx/transforms/references.py +++ b/sphinx/transforms/references.py @@ -29,6 +29,7 @@ def apply(self, **kwargs: Any) -> None: class SphinxDomains(SphinxTransform): """Collect objects to Sphinx domains for cross references.""" + default_priority = 850 def apply(self, **kwargs: Any) -> None: diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index ddb2dd79811..c627c028ba3 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -68,6 +68,7 @@ class FilenameUniqDict(dict): interpreted as filenames, and keeps track of a set of docnames they appear in. Used for images and downloadable files in the environment. """ + def __init__(self) -> None: self._existing: set[str] = set() @@ -178,6 +179,7 @@ class Tee: """ File-like object writing to two streams. """ + def __init__(self, stream1: IO, stream2: IO) -> None: self.stream1 = stream1 self.stream2 = stream2 diff --git a/sphinx/util/_io.py b/sphinx/util/_io.py index 1dc111c0cd7..e140cf12081 100644 --- a/sphinx/util/_io.py +++ b/sphinx/util/_io.py @@ -14,6 +14,7 @@ def write(self, text: str, /) -> int | None: class TeeStripANSI: """File-like object writing to two streams.""" + def __init__( self, stream_term: SupportsWrite, diff --git a/sphinx/util/build_phase.py b/sphinx/util/build_phase.py index 7f80aa576b0..76e94a9b0d2 100644 --- a/sphinx/util/build_phase.py +++ b/sphinx/util/build_phase.py @@ -5,6 +5,7 @@ class BuildPhase(IntEnum): """Build phase of Sphinx application.""" + INITIALIZATION = 1 READING = 2 CONSISTENCY_CHECK = 3 diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py index c48c3be0a47..8b4489fa591 100644 --- a/sphinx/util/docfields.py +++ b/sphinx/util/docfields.py @@ -52,6 +52,7 @@ class Field: :returns: description of the return value :rtype: description of the return type """ + is_grouped = False is_typed = False @@ -152,6 +153,7 @@ class GroupedField(Field): :raises ErrorClass: description when it is raised """ + is_grouped = True list_type = nodes.bullet_list @@ -208,6 +210,7 @@ class TypedField(GroupedField): :param SomeClass foo: description of parameter foo """ + is_typed = True def __init__( @@ -272,6 +275,7 @@ class DocFieldTransformer: Transforms field lists in "doc field" syntax into better-looking equivalents, using the field type definitions given on a domain. """ + typemap: dict[str, tuple[Field, bool]] def __init__(self, directive: ObjectDescription) -> None: diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index 01c0308daaf..165e349553a 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -290,6 +290,7 @@ class sphinx_domains(CustomReSTDispatcher): """Monkey-patch directive and role dispatch, so that domain-specific markup takes precedence. """ + def __init__(self, env: BuildEnvironment) -> None: self.env = env super().__init__() @@ -451,6 +452,7 @@ class SphinxRole: .. note:: The subclasses of this class might not work with docutils. This class is strongly coupled with Sphinx. """ + name: str #: The role name actually used in the document. rawtext: str #: A string containing the entire interpreted text input. text: str #: The interpreted text content. @@ -519,6 +521,7 @@ class ReferenceRole(SphinxRole): the role. The parsed result; link title and target will be stored to ``self.title`` and ``self.target``. """ + has_explicit_title: bool #: A boolean indicates the role has explicit title or not. disabled: bool #: A boolean indicates the reference is disabled. title: str #: The link title for the interpreted text. diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index 218f4abca21..d61d5f064f8 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -453,6 +453,7 @@ class TypeAliasForwardRef: This avoids the error on evaluating the type inside `get_type_hints()`. """ + def __init__(self, name: str) -> None: self.name = name diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py index 429018af7b3..baff073253c 100644 --- a/sphinx/util/logging.py +++ b/sphinx/util/logging.py @@ -85,6 +85,7 @@ def convert_serializable(records: list[logging.LogRecord]) -> None: class SphinxLogRecord(logging.LogRecord): """Log record class supporting location""" + prefix = '' location: Any = None @@ -101,11 +102,13 @@ def getMessage(self) -> str: class SphinxInfoLogRecord(SphinxLogRecord): """Info log record class supporting location""" + prefix = '' # do not show any prefix for INFO messages class SphinxWarningLogRecord(SphinxLogRecord): """Warning log record class supporting location""" + @property def prefix(self) -> str: # type: ignore[override] if self.levelno >= logging.CRITICAL: @@ -118,6 +121,7 @@ def prefix(self) -> str: # type: ignore[override] class SphinxLoggerAdapter(logging.LoggerAdapter): """LoggerAdapter allowing ``type`` and ``subtype`` keywords.""" + KEYWORDS = ['type', 'subtype', 'location', 'nonl', 'color', 'once'] def log( # type: ignore[override] @@ -146,6 +150,7 @@ def handle(self, record: logging.LogRecord) -> None: class WarningStreamHandler(logging.StreamHandler): """StreamHandler for warnings.""" + pass @@ -476,6 +481,7 @@ class SphinxLogRecordTranslator(logging.Filter): * Make a instance of SphinxLogRecord * docname to path if location given """ + LogRecordClass: type[logging.LogRecord] def __init__(self, app: Sphinx) -> None: @@ -507,11 +513,13 @@ def filter(self, record: SphinxWarningLogRecord) -> bool: # type: ignore[overri class InfoLogRecordTranslator(SphinxLogRecordTranslator): """LogRecordTranslator for INFO level log records.""" + LogRecordClass = SphinxInfoLogRecord class WarningLogRecordTranslator(SphinxLogRecordTranslator): """LogRecordTranslator for WARNING level log records.""" + LogRecordClass = SphinxWarningLogRecord @@ -543,6 +551,7 @@ def format(self, record: logging.LogRecord) -> str: class SafeEncodingWriter: """Stream writer which ignores UnicodeEncodeError silently""" + def __init__(self, stream: IO) -> None: self.stream = stream self.encoding = getattr(stream, 'encoding', 'ascii') or 'ascii' @@ -562,6 +571,7 @@ def flush(self) -> None: class LastMessagesWriter: """Stream writer storing last 10 messages in memory to save trackback""" + def __init__(self, app: Sphinx, stream: IO) -> None: self.app = app diff --git a/sphinx/util/matching.py b/sphinx/util/matching.py index dd91905d709..481ca12e144 100644 --- a/sphinx/util/matching.py +++ b/sphinx/util/matching.py @@ -91,7 +91,8 @@ def match(self, string: str) -> bool: def patmatch(name: str, pat: str) -> re.Match[str] | None: """Return if name matches the regular expression (pattern) - ``pat```. Adapted from fnmatch module.""" + ``pat```. Adapted from fnmatch module. + """ if pat not in _pat_cache: _pat_cache[pat] = re.compile(_translate_pattern(pat)) return _pat_cache[pat].match(name) diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py index f9ce975f91d..015bc8f5714 100644 --- a/sphinx/util/nodes.py +++ b/sphinx/util/nodes.py @@ -50,7 +50,7 @@ class NodeMatcher: following example searches ``reference`` node having ``refdomain`` attributes:: from __future__ import annotations -from typing import TYPE_CHECKING, Any + from typing import TYPE_CHECKING, Any matcher = NodeMatcher(nodes.reference, refdomain=Any) doctree.findall(matcher) # => [, , ...] diff --git a/sphinx/util/osutil.py b/sphinx/util/osutil.py index 84aee43594f..93fc625280b 100644 --- a/sphinx/util/osutil.py +++ b/sphinx/util/osutil.py @@ -37,7 +37,7 @@ def canon_path(native_path: str | os.PathLike[str], /) -> str: def path_stabilize(filepath: str | os.PathLike[str], /) -> str: - "Normalize path separator and unicode string" + """Normalize path separator and unicode string""" new_path = canon_path(filepath) return unicodedata.normalize('NFC', new_path) @@ -89,7 +89,8 @@ def copytimes(source: str | os.PathLike[str], dest: str | os.PathLike[str]) -> N def copyfile(source: str | os.PathLike[str], dest: str | os.PathLike[str]) -> None: """Copy a file and its modification times, if possible. - Note: ``copyfile`` skips copying if the file has not been changed""" + Note: ``copyfile`` skips copying if the file has not been changed + """ if not path.exists(dest) or not filecmp.cmp(source, dest): shutil.copyfile(source, dest) with contextlib.suppress(OSError): @@ -132,6 +133,7 @@ def relpath(path: str | os.PathLike[str], class _chdir: """Remove this fall-back once support for Python 3.10 is removed.""" + def __init__(self, target_dir: str, /) -> None: self.path = target_dir self._dirs: list[str] = [] @@ -170,6 +172,7 @@ class FileAvoidWrite: Objects can be used as context managers. """ + def __init__(self, path: str) -> None: self._path = path self._io: StringIO | None = None diff --git a/sphinx/util/requests.py b/sphinx/util/requests.py index ec3d8d2d5b8..4afbd37445e 100644 --- a/sphinx/util/requests.py +++ b/sphinx/util/requests.py @@ -30,17 +30,19 @@ def _get_tls_cacert(url: str, certs: str | dict[str, str] | None) -> str | bool: def get(url: str, **kwargs: Any) -> requests.Response: - """Sends a GET request like requests.get(). + """Sends a GET request like ``requests.get()``. - This sets up User-Agent header and TLS verification automatically.""" + This sets up User-Agent header and TLS verification automatically. + """ with _Session() as session: return session.get(url, **kwargs) def head(url: str, **kwargs: Any) -> requests.Response: - """Sends a HEAD request like requests.head(). + """Sends a HEAD request like ``requests.head()``. - This sets up User-Agent header and TLS verification automatically.""" + This sets up User-Agent header and TLS verification automatically. + """ with _Session() as session: return session.head(url, **kwargs) @@ -54,7 +56,8 @@ def request( # type: ignore[override] ) -> requests.Response: """Sends a request with an HTTP verb and url. - This sets up User-Agent header and TLS verification automatically.""" + This sets up User-Agent header and TLS verification automatically. + """ headers = kwargs.setdefault('headers', {}) headers.setdefault('User-Agent', _user_agent or _USER_AGENT) if _tls_info: diff --git a/sphinx/versioning.py b/sphinx/versioning.py index 0da3b1e2805..042b97d8955 100644 --- a/sphinx/versioning.py +++ b/sphinx/versioning.py @@ -144,6 +144,7 @@ def levenshtein_distance(a: str, b: str) -> int: class UIDTransform(SphinxTransform): """Add UIDs to doctree for versioning.""" + default_priority = 880 def apply(self, **kwargs: Any) -> None: diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index a0f64717e39..a3d694d4313 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -158,7 +158,7 @@ def get_table_type(self) -> str: return 'tabulary' def get_colspec(self) -> str: - """Returns a column spec of table. + r"""Returns a column spec of table. This is what LaTeX calls the 'preamble argument' of the used table environment. diff --git a/sphinx/writers/manpage.py b/sphinx/writers/manpage.py index 108eb5e57e5..e6103ac5af8 100644 --- a/sphinx/writers/manpage.py +++ b/sphinx/writers/manpage.py @@ -49,6 +49,7 @@ class NestedInlineTransform: foo=var &bar=2 """ + def __init__(self, document: nodes.document) -> None: self.document = document diff --git a/sphinx/writers/texinfo.py b/sphinx/writers/texinfo.py index fa77cbf1dda..64f0d122522 100644 --- a/sphinx/writers/texinfo.py +++ b/sphinx/writers/texinfo.py @@ -96,7 +96,8 @@ def find_subsections(section: Element) -> list[nodes.section]: def smart_capwords(s: str, sep: str | None = None) -> str: """Like string.capwords() but does not capitalize words that already - contain a capital letter.""" + contain a capital letter. + """ words = s.split(sep) for i, word in enumerate(words): if all(x.islower() for x in word): @@ -106,6 +107,7 @@ def smart_capwords(s: str, sep: str | None = None) -> str: class TexinfoWriter(writers.Writer): """Texinfo writer for generating Texinfo documents.""" + supported = ('texinfo', 'texi') settings_spec: tuple[str, Any, tuple[tuple[str, list[str], dict[str, str]], ...]] = ( @@ -255,7 +257,8 @@ def init_settings(self) -> None: def collect_node_names(self) -> None: """Generates a unique id for each section. - Assigns the attribute ``node_name`` to each section.""" + Assigns the attribute ``node_name`` to each section. + """ def add_node_name(name: str) -> str: node_id = self.escape_id(name) @@ -352,7 +355,8 @@ def escape(self, s: str) -> str: def escape_arg(self, s: str) -> str: """Return an escaped string suitable for use as an argument - to a Texinfo command.""" + to a Texinfo command. + """ s = self.escape(s) # commas are the argument delimiters s = s.replace(',', '@comma{}') diff --git a/sphinx/writers/text.py b/sphinx/writers/text.py index cea2114fcac..afc628fcca8 100644 --- a/sphinx/writers/text.py +++ b/sphinx/writers/text.py @@ -26,6 +26,7 @@ class Cell: """Represents a cell in a table. It can span multiple columns or multiple lines. """ + def __init__(self, text: str = "", rowspan: int = 1, colspan: int = 1) -> None: self.text = text self.wrapped: list[str] = [] @@ -93,6 +94,7 @@ class Table: +--------+--------+ """ + def __init__(self, colwidth: list[int] | None = None) -> None: self.lines: list[list[Cell]] = [] self.separator = 0 @@ -262,9 +264,8 @@ class TextWrapper(textwrap.TextWrapper): r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') # em-dash def _wrap_chunks(self, chunks: list[str]) -> list[str]: - """_wrap_chunks(chunks : [string]) -> [string] + """The original _wrap_chunks uses len() to calculate width. - The original _wrap_chunks uses len() to calculate width. This method respects wide/fullwidth characters for width adjustment. """ lines: list[str] = [] @@ -309,10 +310,7 @@ def _wrap_chunks(self, chunks: list[str]) -> list[str]: return lines def _break_word(self, word: str, space_left: int) -> tuple[str, str]: - """_break_word(word : string, space_left : int) -> (string, string) - - Break line by unicode width instead of len(word). - """ + """Break line by unicode width instead of len(word).""" total = 0 for i, c in enumerate(word): total += column_width(c) @@ -321,9 +319,8 @@ def _break_word(self, word: str, space_left: int) -> tuple[str, str]: return word, '' def _split(self, text: str) -> list[str]: - """_split(text : string) -> [string] + """Override original method that only split by 'wordsep_re'. - Override original method that only split by 'wordsep_re'. This '_split' splits wide-characters into chunks by one character. """ def split(t: str) -> list[str]: @@ -339,12 +336,7 @@ def split(t: str) -> list[str]: def _handle_long_word(self, reversed_chunks: list[str], cur_line: list[str], cur_len: int, width: int) -> None: - """_handle_long_word(chunks : [string], - cur_line : [string], - cur_len : int, width : int) - - Override original method for using self._break_word() instead of slice. - """ + """Override original method for using self._break_word() instead of slice.""" space_left = max(width - cur_len, 1) if self.break_long_words: l, r = self._break_word(reversed_chunks[-1], space_left) diff --git a/sphinx/writers/xml.py b/sphinx/writers/xml.py index 38aa7630c45..a4d1312a772 100644 --- a/sphinx/writers/xml.py +++ b/sphinx/writers/xml.py @@ -48,5 +48,5 @@ def translate(self) -> None: self.output = self.document.pformat() def supports(self, format: str) -> bool: - """This writer supports all format-specific elements.""" + """All format-specific elements are supported.""" return True diff --git a/tests/ext_napoleon_pep526_data_google.py b/tests/ext_napoleon_pep526_data_google.py index bb55b0fc2bd..d0692e0bab1 100644 --- a/tests/ext_napoleon_pep526_data_google.py +++ b/tests/ext_napoleon_pep526_data_google.py @@ -5,7 +5,7 @@ class PEP526GoogleClass: - """Sample class with PEP 526 annotations and google docstring + """Sample class with PEP 526 annotations and google docstring. Attributes: attr1: Attr1 description. diff --git a/tests/ext_napoleon_pep526_data_numpy.py b/tests/ext_napoleon_pep526_data_numpy.py index b3093a7f440..eff7746ebf2 100644 --- a/tests/ext_napoleon_pep526_data_numpy.py +++ b/tests/ext_napoleon_pep526_data_numpy.py @@ -16,5 +16,6 @@ class PEP526NumpyClass: attr2: Attr2 description """ + attr1: int attr2: str diff --git a/tests/test_addnodes.py b/tests/test_addnodes.py index 184a6960b45..f90953af09c 100644 --- a/tests/test_addnodes.py +++ b/tests/test_addnodes.py @@ -17,7 +17,6 @@ def sig_elements() -> set[type[addnodes.desc_sig_element]]: def test_desc_sig_element_nodes(sig_elements): """Test the registration of ``desc_sig_element`` subclasses.""" - # expected desc_sig_* node classes (must be declared *after* reloading # the module since otherwise the objects are not the correct ones) EXPECTED_SIG_ELEMENTS = { diff --git a/tests/test_build_epub.py b/tests/test_build_epub.py index faf278eb3d8..c17730ac3d7 100644 --- a/tests/test_build_epub.py +++ b/tests/test_build_epub.py @@ -22,6 +22,7 @@ def runnable(command): class EPUBElementTree: """Test helper for content.opf and toc.ncx""" + namespaces = { 'idpf': 'http://www.idpf.org/2007/opf', 'dc': 'http://purl.org/dc/elements/1.1/', diff --git a/tests/test_config.py b/tests/test_config.py index 4b2b3af647a..ba0b82e2457 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -432,7 +432,6 @@ def test_nitpick_ignore_regex_fullmatch(app, status, warning): def test_conf_py_language_none(tmp_path): """Regression test for #10474.""" - # Given a conf.py file with language = None (tmp_path / 'conf.py').write_text("language = None", encoding='utf-8') @@ -446,7 +445,6 @@ def test_conf_py_language_none(tmp_path): @mock.patch("sphinx.config.logger") def test_conf_py_language_none_warning(logger, tmp_path): """Regression test for #10474.""" - # Given a conf.py file with language = None (tmp_path / 'conf.py').write_text("language = None", encoding='utf-8') @@ -463,7 +461,6 @@ def test_conf_py_language_none_warning(logger, tmp_path): def test_conf_py_no_language(tmp_path): """Regression test for #10474.""" - # Given a conf.py file with no language attribute (tmp_path / 'conf.py').write_text("", encoding='utf-8') @@ -476,7 +473,6 @@ def test_conf_py_no_language(tmp_path): def test_conf_py_nitpick_ignore_list(tmp_path): """Regression test for #11355.""" - # Given a conf.py file with no language attribute (tmp_path / 'conf.py').write_text("", encoding='utf-8') diff --git a/tests/test_ext_apidoc.py b/tests/test_ext_apidoc.py index d4d4804a4d1..89c5400c034 100644 --- a/tests/test_ext_apidoc.py +++ b/tests/test_ext_apidoc.py @@ -301,9 +301,9 @@ def test_extension_parsed(make_app, apidoc): ) def test_toc_all_references_should_exist_pep420_enabled(make_app, apidoc): """All references in toc should exist. This test doesn't say if - directories with empty __init__.py and and nothing else should be - skipped, just ensures consistency between what's referenced in the toc - and what is created. This is the variant with pep420 enabled. + directories with empty __init__.py and and nothing else should be + skipped, just ensures consistency between what's referenced in the toc + and what is created. This is the variant with pep420 enabled. """ outdir = apidoc.outdir assert (outdir / 'conf.py').is_file() @@ -331,9 +331,9 @@ def test_toc_all_references_should_exist_pep420_enabled(make_app, apidoc): ) def test_toc_all_references_should_exist_pep420_disabled(make_app, apidoc): """All references in toc should exist. This test doesn't say if - directories with empty __init__.py and and nothing else should be - skipped, just ensures consistency between what's referenced in the toc - and what is created. This is the variant with pep420 disabled. + directories with empty __init__.py and and nothing else should be + skipped, just ensures consistency between what's referenced in the toc + and what is created. This is the variant with pep420 disabled. """ outdir = apidoc.outdir assert (outdir / 'conf.py').is_file() @@ -378,7 +378,7 @@ def extract_toc(path): ) def test_subpackage_in_toc(make_app, apidoc): """Make sure that empty subpackages with non-empty subpackages in them - are not skipped (issue #4520) + are not skipped (issue #4520) """ outdir = apidoc.outdir assert (outdir / 'conf.py').is_file() @@ -642,7 +642,6 @@ def test_no_duplicates(rootdir, tmp_path): We can't use pytest.mark.apidoc here as we use a different set of arguments to apidoc_main """ - original_suffixes = sphinx.ext.apidoc.PY_SUFFIXES try: # Ensure test works on Windows diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py index 9ffc272ff5a..6947bdfff03 100644 --- a/tests/test_ext_autodoc.py +++ b/tests/test_ext_autodoc.py @@ -228,6 +228,7 @@ class ExceptionSubclass(Exception): class F2: """some docstring for F2.""" + def __init__(self, *args, **kw): """ __init__(a1, a2, kw1=True, kw2=False) diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py index b25e68c73f6..2f3092d2d48 100644 --- a/tests/test_ext_intersphinx.py +++ b/tests/test_ext_intersphinx.py @@ -429,23 +429,25 @@ def test_load_mappings_fallback(tmp_path, app, status, warning): class TestStripBasicAuth: """Tests for sphinx.ext.intersphinx._strip_basic_auth()""" + def test_auth_stripped(self): - """basic auth creds stripped from URL containing creds""" + """Basic auth creds stripped from URL containing creds""" url = 'https://user:12345@domain.com/project/objects.inv' expected = 'https://domain.com/project/objects.inv' actual = _strip_basic_auth(url) assert expected == actual def test_no_auth(self): - """url unchanged if param doesn't contain basic auth creds""" + """Url unchanged if param doesn't contain basic auth creds""" url = 'https://domain.com/project/objects.inv' expected = 'https://domain.com/project/objects.inv' actual = _strip_basic_auth(url) assert expected == actual def test_having_port(self): - """basic auth creds correctly stripped from URL containing creds even if URL - contains port""" + """Basic auth creds correctly stripped from URL containing creds even if URL + contains port + """ url = 'https://user:12345@domain.com:8080/project/objects.inv' expected = 'https://domain.com:8080/project/objects.inv' actual = _strip_basic_auth(url) diff --git a/tests/test_ext_napoleon.py b/tests/test_ext_napoleon.py index 00b7ac1c980..466bd49ba74 100644 --- a/tests/test_ext_napoleon.py +++ b/tests/test_ext_napoleon.py @@ -55,7 +55,7 @@ def __special_undoc__(self): @simple_decorator def __decorated_func__(self): - """doc""" + """Doc""" pass diff --git a/tests/test_ext_napoleon_docstring.py b/tests/test_ext_napoleon_docstring.py index 87fad61e3f7..fc25e32189f 100644 --- a/tests/test_ext_napoleon_docstring.py +++ b/tests/test_ext_napoleon_docstring.py @@ -36,6 +36,7 @@ class NamedtupleSubclass(namedtuple('NamedtupleSubclass', ('attr1', 'attr2'))): Adds a newline after the type """ + # To avoid creating a dict, as a namedtuple doesn't have it: __slots__ = () @@ -1186,7 +1187,7 @@ def test_pep526_annotations(self): actual = str(GoogleDocstring(cleandoc(PEP526GoogleClass.__doc__), config, app=None, what="class", obj=PEP526GoogleClass)) expected = """\ -Sample class with PEP 526 annotations and google docstring +Sample class with PEP 526 annotations and google docstring. .. attribute:: attr1 diff --git a/tests/test_ext_todo.py b/tests/test_ext_todo.py index 7d39495e72b..666bded8412 100644 --- a/tests/test_ext_todo.py +++ b/tests/test_ext_todo.py @@ -86,7 +86,6 @@ def test_todo_valid_link(app, status, warning): that exists in the LaTeX output. The target was previously incorrectly omitted (GitHub issue #1020). """ - # Ensure the LaTeX output is built. app.builder.build_all() diff --git a/tests/test_transforms_post_transforms.py b/tests/test_transforms_post_transforms.py index dab5a5a53e2..c4e699ba0c8 100644 --- a/tests/test_transforms_post_transforms.py +++ b/tests/test_transforms_post_transforms.py @@ -79,6 +79,7 @@ def test_keyboard_hyphen_spaces(app): class TestSigElementFallbackTransform: """Integration test for :class:`sphinx.transforms.post_transforms.SigElementFallbackTransform`.""" + # safe copy of the "built-in" desc_sig_* nodes (during the test, instances of such nodes # will be created sequentially, so we fix a possible order at the beginning using a tuple) _builtin_sig_elements: tuple[type[addnodes.desc_sig_element], ...] = tuple(SIG_ELEMENTS) diff --git a/tests/test_util_nodes.py b/tests/test_util_nodes.py index 92e4dc1e62a..ddd5974568d 100644 --- a/tests/test_util_nodes.py +++ b/tests/test_util_nodes.py @@ -237,8 +237,8 @@ def test_split_explicit_target(title, expected): def test_apply_source_workaround_literal_block_no_source(): """Regression test for #11091. - Test that apply_source_workaround doesn't raise. - """ + Test that apply_source_workaround doesn't raise. + """ literal_block = nodes.literal_block('', '') list_item = nodes.list_item('', literal_block) bullet_list = nodes.bullet_list('', list_item) diff --git a/utils/babel_runner.py b/utils/babel_runner.py index 306e6348a59..d26139f9add 100644 --- a/utils/babel_runner.py +++ b/utils/babel_runner.py @@ -117,7 +117,6 @@ def run_extract() -> None: def run_update() -> None: """Catalog merging command.""" - log = _get_logger() domain = 'sphinx' @@ -160,7 +159,6 @@ def run_compile() -> None: Unfortunately, babel's setup command isn't built very extensible, so most of the run() code is duplicated here. """ - log = _get_logger() directory = os.path.join('sphinx', 'locale')