mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2026-10-25 14:40:22 -05:00
Enable 11 more categories in Ruff
* flake8-builtins ('A')
* flake8-blind-except ('BLE')
* flake8-copyright ('CPY')
* eradicate ('ERA')
* flake8-boolean-trap ('FBT')
* flake8-fixme ('FIX')
* flake8-implicit-str-concat ('ISC')
* pep8-naming ('N')
* flake8-use-pathlib ('PTH')
* flake8-self ('SLF')
* tryceratops ('TRY')
This commit is contained in:
1 parent
3521cb60cf
commit
c66d3e85d1
45 files changed
+154
-106
No files matched your search
+66
-19
@@ -16,6 +16,10 @@ quote-style = "single"
|
||||
[lint]
|
||||
preview = true
|
||||
ignore = [
|
||||
# flake8-builtins
|
||||
"A001", # Variable `{name}` is shadowing a Python builtin
|
||||
"A002", # Function argument `{name}` is shadowing a Python builtin
|
||||
"A005", # Module `{name}` is shadowing a Python builtin module
|
||||
# flake8-annotations
|
||||
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed in `{name}`
|
||||
# flake8-unused-arguments ('ARG')
|
||||
@@ -23,23 +27,44 @@ ignore = [
|
||||
"ARG002", # Unused method argument: `{name}`
|
||||
"ARG003", # Unused class method argument: `{name}`
|
||||
"ARG005", # Unused lambda argument: `{name}`
|
||||
# flake8-commas ('COM')
|
||||
# flake8-blind-except
|
||||
"BLE001", # Do not catch blind exception: `{name}`
|
||||
# flake8-commas
|
||||
"COM812", # Trailing comma missing
|
||||
# flake8-copyright
|
||||
"CPY001", # Missing copyright notice at top of file
|
||||
# pycodestyle
|
||||
"E741", # Ambiguous variable name: `{name}`
|
||||
# eradicate
|
||||
"ERA001", # Found commented-out code
|
||||
# pyflakes
|
||||
"F841", # Local variable `{name}` is assigned to but never used
|
||||
# flake8-boolean-trap
|
||||
"FBT001", # Boolean-typed positional argument in function definition
|
||||
"FBT002", # Boolean default positional argument in function definition
|
||||
"FBT003", # Boolean positional value in function call
|
||||
# flake8-fixme
|
||||
"FIX001", # Line contains FIXME, consider resolving the issue
|
||||
"FIX002", # Line contains TODO, consider resolving the issue
|
||||
"FIX003", # Line contains XXX, consider resolving the issue
|
||||
"FIX004", # Line contains HACK, consider resolving the issue
|
||||
# refurb
|
||||
"FURB101", # `open` and `read` should be replaced by `Path(...).read_text(...)`
|
||||
"FURB103", # `open` and `write` should be replaced by `Path(...).write_text(...)`
|
||||
# flake8-implicit-str-concat
|
||||
# pep8-naming
|
||||
"N801", # Class name `{name}` should use CapWords convention
|
||||
"N802", # Function name `{name}` should be lowercase
|
||||
"N803", # Argument name `{name}` should be lowercase
|
||||
"N806", # Variable `{name}` in function should be lowercase
|
||||
"N818", # Exception name `{name}` should be named with an Error suffix
|
||||
# perflint
|
||||
"PERF203", # `try`-`except` within a loop incurs performance overhead
|
||||
# flake8-pie ('PIE')
|
||||
# flake8-pie
|
||||
"PIE790", # Unnecessary `pass` statement
|
||||
# pylint ('PLC')
|
||||
# pylint
|
||||
"PLC0415", # `import` should be at the top-level of a file
|
||||
"PLC2701", # Private name import `{name}` from external module `{module}`
|
||||
# pylint ('PLR')
|
||||
"PLR0904", # Too many public methods ({methods} > {max_methods})
|
||||
"PLR0911", # Too many return statements ({returns} > {max_returns})
|
||||
"PLR0912", # Too many branches ({branches} > {max_branches})
|
||||
@@ -53,8 +78,16 @@ ignore = [
|
||||
"PLR5501", # Use `elif` instead of `else` then `if`, to reduce indentation
|
||||
"PLR6104", # Use `{operator}` to perform an augmented assignment directly
|
||||
"PLR6301", # Method `{method_name}` could be a function, class method, or static method
|
||||
# pylint ('PLW')
|
||||
"PLW2901", # Outer {outer_kind} variable `{name}` overwritten by inner {inner_kind} target
|
||||
# flake8-use-pathlib
|
||||
"PTH100", # `os.path.abspath()` should be replaced by `Path.resolve()`
|
||||
"PTH110", # `os.path.exists()` should be replaced by `Path.exists()`
|
||||
"PTH113", # `os.path.isfile()` should be replaced by `Path.is_file()`
|
||||
"PTH118", # `os.{module}.join()` should be replaced by `Path` with `/` operator
|
||||
"PTH119", # `os.path.basename()` should be replaced by `Path.name`
|
||||
"PTH120", # `os.path.dirname()` should be replaced by `Path.parent`
|
||||
"PTH122", # `os.path.splitext()` should be replaced by `Path.suffix`, `Path.stem`, and `Path.parent`
|
||||
"PTH123", # `open()` should be replaced by `Path.open()`
|
||||
# flake8-pyi ('PYI')
|
||||
"PYI025", # Use `from collections.abc import Set as AbstractSet` to avoid confusion with the `set` builtin
|
||||
# flake8-bandit ('S')
|
||||
@@ -66,11 +99,16 @@ ignore = [
|
||||
# flake8-simplify
|
||||
"SIM102", # Use a single `if` statement instead of nested `if` statements
|
||||
"SIM108", # Use ternary operator `{contents}` instead of `if`-`else`-block
|
||||
# flake8-self
|
||||
"SLF001", # Private member accessed: `{access}`
|
||||
# flake8-todos ('TD')
|
||||
"TD001", # Invalid TODO tag: `{tag}`
|
||||
"TD002", # Missing author in TODO; try: `# TODO(<author_name>): ...` or `# TODO @<author_name>: ...`
|
||||
"TD003", # Missing issue link on the line following this TODO
|
||||
"TD004", # Missing colon in TODO
|
||||
# tryceratops
|
||||
"TRY002", # Create your own exception
|
||||
"TRY300", # Consider moving this statement to an `else` block
|
||||
# pyupgrade
|
||||
"UP031", # Use format specifiers instead of percent format
|
||||
"UP032", # Use f-string instead of `format` call
|
||||
@@ -88,7 +126,7 @@ external = [ # Whitelist for RUF100 unknown code warnings
|
||||
]
|
||||
select = [
|
||||
# flake8-builtins ('A')
|
||||
# NOT YET USED
|
||||
"A",
|
||||
# airflow ('AIR')
|
||||
# Airflow is not used in Sphinx
|
||||
# flake8-annotations ('ANN')
|
||||
@@ -100,7 +138,7 @@ select = [
|
||||
# flake8-bugbear ('B')
|
||||
"B",
|
||||
# flake8-blind-except ('BLE')
|
||||
# NOT YET USED
|
||||
"BLE",
|
||||
# flake8-comprehensions ('C4')
|
||||
"C4",
|
||||
# mccabe ('C90')
|
||||
@@ -108,7 +146,7 @@ select = [
|
||||
# flake8-commas ('COM')
|
||||
"COM", # Trailing comma prohibited
|
||||
# flake8-copyright ('CPY')
|
||||
# NOT YET USED
|
||||
"CPY",
|
||||
# pydocstyle ('D')
|
||||
# "D100", # Missing docstring in public module
|
||||
# "D101", # Missing docstring in public class
|
||||
@@ -164,7 +202,7 @@ select = [
|
||||
# flake8-errmsg ('EM')
|
||||
"EM",
|
||||
# eradicate ('ERA')
|
||||
# NOT YET USED
|
||||
"ERA",
|
||||
# flake8-executable ('EXE')
|
||||
"EXE",
|
||||
# pyflakes ('F')
|
||||
@@ -174,9 +212,9 @@ select = [
|
||||
# flake8-fastapi ('FAST')
|
||||
# FastAPI is not used in Sphinx
|
||||
# flake8-boolean-trap ('FBT')
|
||||
# NOT YET USED
|
||||
"FBT",
|
||||
# flake8-fixme ('FIX')
|
||||
# NOT YET USED
|
||||
"FIX",
|
||||
# flynt ('FLY')
|
||||
"FLY",
|
||||
# refurb ('FURB')
|
||||
@@ -186,17 +224,17 @@ select = [
|
||||
# isort ('I')
|
||||
"I",
|
||||
# flake8-import-conventions ('ICN')
|
||||
"ICN", # flake8-import-conventions
|
||||
"ICN",
|
||||
# flake8-no-pep420 ('INP')
|
||||
"INP",
|
||||
# flake8-gettext ('INT')
|
||||
"INT",
|
||||
# flake8-implicit-str-concat ('ISC')
|
||||
# NOT YET USED
|
||||
"ISC",
|
||||
# flake8-logging ('LOG')
|
||||
"LOG",
|
||||
# pep8-naming ('N')
|
||||
# NOT YET USED
|
||||
"N",
|
||||
# numpy-specific rules ('NPY')
|
||||
# Numpy is not used in Sphinx
|
||||
# pandas-vet ('PD')
|
||||
@@ -212,9 +250,9 @@ select = [
|
||||
# flake8-pytest-style ('PT')
|
||||
"PT",
|
||||
# flake8-use-pathlib ('PTH')
|
||||
# NOT YET USED
|
||||
"PTH",
|
||||
# flake8-pyi ('PYI')
|
||||
"PYI",
|
||||
# Stub files are not used in Sphinx
|
||||
# flake8-quotes ('Q')
|
||||
"Q",
|
||||
# flake8-return ('RET')
|
||||
@@ -235,7 +273,7 @@ select = [
|
||||
# flake8-simplify ('SIM')
|
||||
"SIM", # flake8-simplify
|
||||
# flake8-self ('SLF')
|
||||
# NOT YET USED
|
||||
"SLF",
|
||||
# flake8-slots ('SLOT')
|
||||
"SLOT",
|
||||
# flake8-debugger ('T10')
|
||||
@@ -251,7 +289,7 @@ select = [
|
||||
# flake8-trio ('TRIO')
|
||||
# Trio is not used in Sphinx
|
||||
# tryceratops ('TRY')
|
||||
# NOT YET USED
|
||||
"TRY",
|
||||
# pyupgrade ('UP')
|
||||
"UP",
|
||||
# pycodestyle ('W')
|
||||
@@ -299,7 +337,10 @@ logger-objects = [
|
||||
# whitelist ``print`` for stdout messages
|
||||
"sphinx/cmd/build.py" = ["T201"]
|
||||
"sphinx/cmd/make_mode.py" = ["T201"]
|
||||
"sphinx/cmd/quickstart.py" = ["T201"]
|
||||
"sphinx/cmd/quickstart.py" = [
|
||||
"PTH",
|
||||
"T201",
|
||||
]
|
||||
|
||||
"sphinx/environment/collectors/toctree.py" = ["B026"]
|
||||
"sphinx/environment/adapters/toctree.py" = ["B026"]
|
||||
@@ -315,9 +356,15 @@ logger-objects = [
|
||||
# whitelist ``print`` for stdout messages
|
||||
"sphinx/testing/fixtures.py" = ["T201"]
|
||||
|
||||
# whitelist ``os.path`` for deprecated ``sphinx.testing.path``
|
||||
"sphinx/testing/path.py" = ["PTH"]
|
||||
|
||||
# whitelist ``token`` in date format parsing
|
||||
"sphinx/util/i18n.py" = ["S105"]
|
||||
|
||||
# whitelist ``os.path`` for ``sphinx.util.osutil``
|
||||
"sphinx/util/osutil.py" = ["PTH"]
|
||||
|
||||
# whitelist ``token`` in literal parsing
|
||||
"sphinx/writers/html5.py" = ["S105"]
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ Gracefully adapted from the TextPress system by Armin.
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import pickle
|
||||
import sys
|
||||
from collections import deque
|
||||
@@ -36,6 +35,7 @@ from sphinx.util.osutil import ensuredir, relpath
|
||||
from sphinx.util.tags import Tags
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import os
|
||||
from collections.abc import Callable, Collection, Iterable, Sequence, Set
|
||||
from pathlib import Path
|
||||
from typing import IO, Any, Final, Literal
|
||||
@@ -424,7 +424,7 @@ class Sphinx:
|
||||
# delete the saved env to force a fresh build next time
|
||||
envfile = self.doctreedir / ENV_PICKLE_FILENAME
|
||||
if envfile.is_file():
|
||||
os.unlink(envfile)
|
||||
envfile.unlink()
|
||||
self.events.emit('build-finished', err)
|
||||
raise
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import codecs
|
||||
import operator
|
||||
import time
|
||||
from codecs import open
|
||||
from collections import defaultdict
|
||||
from os import getenv, path, walk
|
||||
from pathlib import Path
|
||||
@@ -216,7 +216,7 @@ def should_write(filepath: str, new_content: str) -> bool:
|
||||
if not path.exists(filepath):
|
||||
return True
|
||||
try:
|
||||
with open(filepath, encoding='utf-8') as oldpot:
|
||||
with codecs.open(filepath, encoding='utf-8') as oldpot:
|
||||
old_content = oldpot.read()
|
||||
old_header_index = old_content.index('"POT-Creation-Date:')
|
||||
new_header_index = new_content.index('"POT-Creation-Date:')
|
||||
@@ -277,7 +277,7 @@ class MessageCatalogBuilder(I18nBuilder):
|
||||
files, __('reading templates... '), 'purple', len(files), self.app.verbosity
|
||||
):
|
||||
try:
|
||||
with open(template, encoding='utf-8') as f:
|
||||
with codecs.open(template, encoding='utf-8') as f:
|
||||
context = f.read()
|
||||
for line, _meth, msg in extract_translations(context):
|
||||
origin = MsgOrigin(source=template, line=line)
|
||||
@@ -328,7 +328,7 @@ class MessageCatalogBuilder(I18nBuilder):
|
||||
|
||||
pofn = path.join(self.outdir, textdomain + '.pot')
|
||||
if should_write(pofn, content):
|
||||
with open(pofn, 'w', encoding='utf-8') as pofile:
|
||||
with codecs.open(pofn, 'w', encoding='utf-8') as pofile:
|
||||
pofile.write(content)
|
||||
|
||||
|
||||
|
||||
@@ -1274,7 +1274,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
else:
|
||||
with open(search_index_tmp, 'wb') as fb:
|
||||
self.indexer.dump(fb, self.indexer_format)
|
||||
os.replace(search_index_tmp, search_index_path)
|
||||
Path(search_index_tmp).replace(search_index_path)
|
||||
|
||||
|
||||
def convert_html_css_files(app: Sphinx, config: Config) -> None:
|
||||
|
||||
@@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
import os
|
||||
import os.path
|
||||
import warnings
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from docutils.frontend import OptionParser
|
||||
@@ -446,8 +447,8 @@ class LaTeXBuilder(Builder):
|
||||
'xindy_cyrillic': xindy_cyrillic,
|
||||
}
|
||||
staticdirname = os.path.join(package_dir, 'texinputs')
|
||||
for filename in os.listdir(staticdirname):
|
||||
if not filename.startswith('.'):
|
||||
for filename in Path(staticdirname).iterdir():
|
||||
if not filename.name.startswith('.'):
|
||||
copy_asset_file(
|
||||
os.path.join(staticdirname, filename),
|
||||
self.outdir,
|
||||
|
||||
@@ -16,7 +16,12 @@ from typing import TYPE_CHECKING, NamedTuple, cast
|
||||
from urllib.parse import quote, unquote, urlparse, urlsplit, urlunparse
|
||||
|
||||
from docutils import nodes
|
||||
from requests.exceptions import ConnectionError, HTTPError, SSLError, TooManyRedirects
|
||||
from requests.exceptions import (
|
||||
ConnectionError, # NoQA: A004
|
||||
HTTPError,
|
||||
SSLError,
|
||||
TooManyRedirects,
|
||||
)
|
||||
from requests.exceptions import Timeout as RequestTimeout
|
||||
|
||||
from sphinx.builders.dummy import DummyBuilder
|
||||
|
||||
@@ -15,7 +15,7 @@ try:
|
||||
import readline
|
||||
|
||||
if TYPE_CHECKING and sys.platform == 'win32': # always false, for type checking
|
||||
raise ImportError
|
||||
raise ImportError # NoQA: TRY301
|
||||
READLINE_AVAILABLE = True
|
||||
if readline.__doc__ and 'libedit' in readline.__doc__:
|
||||
readline.parse_and_bind('bind ^I rl_complete')
|
||||
|
||||
+1
-1
@@ -388,7 +388,7 @@ class Config:
|
||||
# given falsy string from a command line option
|
||||
return value not in {'0', ''}
|
||||
if isinstance(default, dict):
|
||||
raise ValueError(
|
||||
raise ValueError( # NoQA: TRY004
|
||||
__(
|
||||
'cannot override dictionary config setting %r, '
|
||||
'ignoring (use %r to set individual elements)'
|
||||
|
||||
@@ -86,7 +86,7 @@ def container_wrapper(
|
||||
node = parsed[0]
|
||||
if isinstance(node, nodes.system_message):
|
||||
msg = __('Invalid caption: %s') % node.astext()
|
||||
raise ValueError(msg)
|
||||
raise ValueError(msg) # NoQA: TRY004
|
||||
if isinstance(node, nodes.Element):
|
||||
caption_node = nodes.caption(node.rawsource, '', *node.children)
|
||||
caption_node.source = literal_node.source
|
||||
|
||||
@@ -2052,7 +2052,7 @@ class DefinitionParser(BaseParser):
|
||||
if object_type == 'member' and len(templates) == 0:
|
||||
return ASTTemplateDeclarationPrefix(None)
|
||||
else:
|
||||
raise e
|
||||
raise
|
||||
if object_type == 'concept' and params.requiresClause is not None:
|
||||
self.fail('requires-clause not allowed for concept')
|
||||
else:
|
||||
|
||||
@@ -562,7 +562,7 @@ def _pseudo_parse_arglist(
|
||||
stack.pop()
|
||||
ends_close -= 1
|
||||
if len(stack) != 1:
|
||||
raise IndexError
|
||||
raise IndexError # NoQA: TRY301
|
||||
except IndexError:
|
||||
# if there are too few or too many elements on the stack, just give up
|
||||
# and treat the whole argument list as one argument, discarding the
|
||||
|
||||
@@ -515,7 +515,7 @@ def _toctree_copy(
|
||||
copy.append(sub_node_copy)
|
||||
else:
|
||||
msg = f'Unexpected node type {subnode.__class__.__name__!r}!'
|
||||
raise ValueError(msg)
|
||||
raise ValueError(msg) # NoQA: TRY004
|
||||
return copy
|
||||
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ class ImageCollector(EnvironmentCollector):
|
||||
node: Node,
|
||||
) -> None:
|
||||
globbed: dict[str, list[str]] = {}
|
||||
for filename in glob(imgpath):
|
||||
for filename in glob(imgpath): # NoQA: PTH207
|
||||
new_imgpath = _relative_path(Path(filename), srcdir)
|
||||
try:
|
||||
mimetype = guess_mimetype(filename)
|
||||
|
||||
@@ -15,7 +15,7 @@ from sphinx.util.template import ReSTRenderer
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import re
|
||||
from collections.abc import Iterator, Sequence
|
||||
from collections.abc import Iterable, Iterator, Sequence
|
||||
|
||||
from sphinx.ext.apidoc._shared import ApidocOptions
|
||||
|
||||
@@ -50,13 +50,15 @@ def module_join(*modnames: str | None) -> str:
|
||||
return '.'.join(filter(None, modnames))
|
||||
|
||||
|
||||
def is_packagedir(dirname: str | None = None, files: list[str] | None = None) -> bool:
|
||||
def is_packagedir(
|
||||
dirname: str | None = None, files: Iterable[str | Path] | None = None
|
||||
) -> bool:
|
||||
"""Check given *files* contains __init__ file."""
|
||||
if files is None and dirname is None:
|
||||
return False
|
||||
|
||||
if files is None:
|
||||
files = os.listdir(dirname)
|
||||
files = Path(dirname or '.').iterdir()
|
||||
return any(f for f in files if is_initpy(f))
|
||||
|
||||
|
||||
@@ -208,7 +210,7 @@ def is_skipped_package(
|
||||
if not Path(dirname).is_dir():
|
||||
return False
|
||||
|
||||
files = glob.glob(str(Path(dirname, '*.py')))
|
||||
files = glob.glob(str(Path(dirname, '*.py'))) # NoQA: PTH207
|
||||
regular_package = any(f for f in files if is_initpy(f))
|
||||
if not regular_package and not opts.implicit_namespaces:
|
||||
# *dirname* is not both a regular package and an implicit namespace package
|
||||
|
||||
@@ -157,7 +157,7 @@ class AutodocDirective(SphinxDirective):
|
||||
)
|
||||
except (KeyError, ValueError, TypeError) as exc:
|
||||
# an option is either unknown or has a wrong type
|
||||
logger.error(
|
||||
logger.error( # NoQA: TRY400
|
||||
'An option to %s is either unknown or has an invalid value: %s',
|
||||
self.name,
|
||||
exc,
|
||||
|
||||
@@ -131,7 +131,7 @@ class AutosummaryRenderer:
|
||||
def __init__(self, app: Sphinx) -> None:
|
||||
if isinstance(app, Builder):
|
||||
msg = 'Expected a Sphinx application object!'
|
||||
raise ValueError(msg)
|
||||
raise TypeError(msg)
|
||||
|
||||
system_templates_path = [
|
||||
os.path.join(package_dir, 'ext', 'autosummary', 'templates')
|
||||
|
||||
@@ -179,7 +179,7 @@ class CoverageBuilder(Builder):
|
||||
self.c_sourcefiles: list[str] = []
|
||||
for pattern in self.config.coverage_c_path:
|
||||
pattern = os.path.join(self.srcdir, pattern)
|
||||
self.c_sourcefiles.extend(glob.glob(pattern))
|
||||
self.c_sourcefiles.extend(glob.glob(pattern)) # NoQA: PTH207
|
||||
|
||||
self.c_regexes: list[tuple[str, re.Pattern[str]]] = []
|
||||
for name, exp in self.config.coverage_c_regexes.items():
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import urllib.parse
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
@@ -39,7 +37,7 @@ def create_nojekyll_and_cname(app: Sphinx, env: BuildEnvironment) -> None:
|
||||
return
|
||||
|
||||
app.builder.outdir.joinpath('.nojekyll').touch()
|
||||
cname_path = os.path.join(app.builder.outdir, 'CNAME')
|
||||
cname_path = app.builder.outdir / 'CNAME'
|
||||
|
||||
domain = _get_domain_from_url(app.config.html_baseurl)
|
||||
# Filter out GitHub Pages domains, as they do not require CNAME files.
|
||||
@@ -49,8 +47,7 @@ def create_nojekyll_and_cname(app: Sphinx, env: BuildEnvironment) -> None:
|
||||
# auto-generated by the GitHub UI doesn't have one.
|
||||
f.write(domain)
|
||||
else:
|
||||
with contextlib.suppress(FileNotFoundError):
|
||||
os.unlink(cname_path)
|
||||
cname_path.unlink(missing_ok=True)
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> ExtensionMetadata:
|
||||
|
||||
@@ -366,12 +366,12 @@ def render_dot_html(
|
||||
filename: str | None = None,
|
||||
) -> tuple[str, str]:
|
||||
format = self.builder.config.graphviz_output_format
|
||||
if format not in {'png', 'svg'}:
|
||||
logger.warning(
|
||||
__("graphviz_output_format must be either 'png' or 'svg', but is %r"),
|
||||
format,
|
||||
)
|
||||
try:
|
||||
if format not in {'png', 'svg'}:
|
||||
raise GraphvizError(
|
||||
__("graphviz_output_format must be one of 'png', 'svg', but is %r")
|
||||
% format
|
||||
)
|
||||
fname, outfn = render_dot(self, code, options, format, prefix, filename)
|
||||
except GraphvizError as exc:
|
||||
logger.warning(__('dot code %r: %s'), code, exc)
|
||||
|
||||
@@ -32,7 +32,7 @@ def inspect_main(argv: list[str], /) -> int:
|
||||
target_uri='',
|
||||
inv_location=filename,
|
||||
config=config,
|
||||
srcdir=Path(''),
|
||||
srcdir=Path(),
|
||||
)
|
||||
for key in sorted(inv_data or {}):
|
||||
print(key)
|
||||
|
||||
@@ -81,7 +81,7 @@ def validate_intersphinx_mapping(app: Sphinx, config: Config) -> None:
|
||||
'Invalid value `%r` in intersphinx_mapping[%r]. '
|
||||
'Values must be a (target URI, inventory locations) pair.'
|
||||
)
|
||||
LOGGER.error(msg, value, name)
|
||||
LOGGER.error(msg, value, name) # NoQA: TRY400
|
||||
del config.intersphinx_mapping[name]
|
||||
continue
|
||||
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ class Todo(BaseAdmonition, SphinxDirective):
|
||||
self.state.document.note_explicit_target(todo)
|
||||
return [todo]
|
||||
else:
|
||||
raise RuntimeError # never reached here
|
||||
raise TypeError # never reached here
|
||||
|
||||
|
||||
class TodoDomain(Domain):
|
||||
|
||||
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import os
|
||||
import os.path
|
||||
from pathlib import Path
|
||||
from pprint import pformat
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
@@ -226,7 +227,7 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
|
||||
|
||||
def _newest_template_mtime_name(self) -> tuple[float, str]:
|
||||
return max(
|
||||
(os.stat(os.path.join(root, sfile)).st_mtime_ns / 10**9, sfile)
|
||||
(Path(root, sfile).stat().st_mtime_ns / 10**9, sfile)
|
||||
for dirname in self.pathchain
|
||||
for root, _dirs, files in os.walk(dirname)
|
||||
for sfile in files
|
||||
|
||||
@@ -4,8 +4,6 @@ from __future__ import annotations
|
||||
|
||||
__all__ = ('SphinxTestApp', 'SphinxTestAppWrapperForSkipBuilding')
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import sys
|
||||
from io import StringIO
|
||||
from types import MappingProxyType
|
||||
@@ -21,6 +19,7 @@ from sphinx.util.console import strip_colors
|
||||
from sphinx.util.docutils import additional_nodes
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import os
|
||||
from collections.abc import Mapping, Sequence
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
@@ -224,8 +223,7 @@ class SphinxTestApp(sphinx.application.Sphinx):
|
||||
def cleanup(self, doctrees: bool = False) -> None:
|
||||
sys.path[:] = self._saved_path
|
||||
_clean_up_global_state()
|
||||
with contextlib.suppress(FileNotFoundError):
|
||||
os.remove(self.docutils_conf_path)
|
||||
self.docutils_conf_path.unlink(missing_ok=True)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'<{self.__class__.__name__} buildername={self._builder_name!r}>'
|
||||
@@ -247,7 +245,7 @@ class SphinxTestAppWrapperForSkipBuilding(SphinxTestApp):
|
||||
def build(
|
||||
self, force_all: bool = False, filenames: list[str] | None = None
|
||||
) -> None:
|
||||
if not os.listdir(self.outdir):
|
||||
if not list(self.outdir.iterdir()):
|
||||
# if listdir is empty, do build.
|
||||
super().build(force_all, filenames)
|
||||
# otherwise, we can use built cache
|
||||
|
||||
@@ -115,7 +115,7 @@ class ImageDownloader(BaseImageConverter):
|
||||
# append a suffix if URI does not contain suffix
|
||||
ext = get_image_extension(mimetype) or ''
|
||||
with_ext = path.with_name(path.name + ext)
|
||||
os.replace(path, with_ext)
|
||||
path.replace(with_ext)
|
||||
self.env.original_image_uri.pop(str_path)
|
||||
self.env.original_image_uri[_StrPath(with_ext)] = node['uri']
|
||||
path = with_ext
|
||||
|
||||
@@ -77,7 +77,7 @@ def __getattr__(name: str) -> Any:
|
||||
return obj
|
||||
|
||||
if name == 'ExtensionError':
|
||||
from sphinx.errors import ExtensionError as obj
|
||||
from sphinx.errors import ExtensionError as obj # NoQA: N813
|
||||
|
||||
canonical_name = f'{obj.__module__}.{obj.__qualname__}'
|
||||
_deprecation_warning(__name__, name, canonical_name, remove=(9, 0))
|
||||
|
||||
@@ -11,17 +11,17 @@ def parse_line_num_spec(spec: str, total: int) -> list[int]:
|
||||
try:
|
||||
begend = part.strip().split('-')
|
||||
if begend == ['', '']:
|
||||
raise ValueError
|
||||
raise ValueError # NoQA: TRY301
|
||||
if len(begend) == 1:
|
||||
items.append(int(begend[0]) - 1)
|
||||
elif len(begend) == 2:
|
||||
start = int(begend[0] or 1) # left half open (cf. -10)
|
||||
end = int(begend[1] or max(start, total)) # right half open (cf. 10-)
|
||||
if start > end: # invalid range (cf. 10-1)
|
||||
raise ValueError
|
||||
raise ValueError # NoQA: TRY301
|
||||
items.extend(range(start - 1, end))
|
||||
else:
|
||||
raise ValueError
|
||||
raise ValueError # NoQA: TRY301
|
||||
except ValueError as exc:
|
||||
msg = f'invalid line number spec: {spec!r}'
|
||||
raise ValueError(msg) from exc
|
||||
|
||||
+1
-1
@@ -112,4 +112,4 @@ class Tags:
|
||||
return node.name in self._tags
|
||||
else:
|
||||
msg = 'invalid node, check parsing'
|
||||
raise ValueError(msg)
|
||||
raise TypeError(msg)
|
||||
@@ -1,3 +1,4 @@
|
||||
# NoQA: N999
|
||||
from __future__ import annotations
|
||||
|
||||
from gettext import NullTranslations # NoQA: TC003
|
||||
|
||||
@@ -42,13 +42,13 @@ class Baz:
|
||||
|
||||
class Qux:
|
||||
@deco1
|
||||
def __new__(self, name=None, age=None):
|
||||
def __new__(cls, name=None, age=None):
|
||||
pass
|
||||
|
||||
|
||||
class _Metaclass(type):
|
||||
@deco1
|
||||
def __call__(self, name=None, age=None):
|
||||
def __call__(cls, name=None, age=None):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@@ -57,12 +57,12 @@ class Bar:
|
||||
"""docstring"""
|
||||
|
||||
@overload
|
||||
def __init__(cls, x: int, y: int) -> None: ...
|
||||
def __init__(self, x: int, y: int) -> None: ...
|
||||
|
||||
@overload
|
||||
def __init__(cls, x: str, y: str) -> None: ...
|
||||
def __init__(self, x: str, y: str) -> None: ...
|
||||
|
||||
def __init__(cls, x, y):
|
||||
def __init__(self, x, y):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ class Foo:
|
||||
|
||||
@classmethod
|
||||
@property
|
||||
def prop2(self) -> int:
|
||||
def prop2(cls) -> int:
|
||||
"""docstring"""
|
||||
|
||||
@property
|
||||
@@ -17,6 +17,6 @@ class Foo:
|
||||
|
||||
@classmethod
|
||||
@property
|
||||
def prop2_with_type_comment(self):
|
||||
def prop2_with_type_comment(cls):
|
||||
# type: () -> int
|
||||
"""docstring"""
|
||||
@@ -6,7 +6,7 @@ module with trailing underscores everywhere
|
||||
class class_:
|
||||
"""Class"""
|
||||
|
||||
def method_(_arg):
|
||||
def method_(_arg): # NoQA: N805
|
||||
"""Method"""
|
||||
pass
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
submodule
|
||||
"""
|
||||
|
||||
raise RuntimeError('This module should not get imported') # NoQA: EM101
|
||||
raise RuntimeError('This module should not get imported') # NoQA: EM101,TRY003
|
||||
|
||||
|
||||
def decorator(f):
|
||||
|
||||
@@ -71,7 +71,7 @@ def test_build_all(requests_head, make_app, nonascii_srcdir, buildername):
|
||||
|
||||
def test_root_doc_not_found(tmp_path, make_app):
|
||||
(tmp_path / 'conf.py').touch()
|
||||
assert os.listdir(tmp_path) == ['conf.py']
|
||||
assert [p.name for p in tmp_path.iterdir()] == ['conf.py']
|
||||
|
||||
app = make_app('dummy', srcdir=tmp_path)
|
||||
with pytest.raises(SphinxError):
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
import pytest
|
||||
@@ -309,7 +308,7 @@ def test_numfig_without_numbered_toctree(
|
||||
index = re.sub(':numbered:.*', '', index)
|
||||
(app.srcdir / 'index.rst').write_text(index, encoding='utf8')
|
||||
|
||||
if not os.listdir(app.outdir):
|
||||
if not list(app.outdir.iterdir()):
|
||||
app.build()
|
||||
check_xpath(cached_etree_parse(app.outdir / fname), fname, path, check, be_found)
|
||||
|
||||
|
||||
@@ -2141,10 +2141,7 @@ def test_latex_code_role(app):
|
||||
r'\PYG{k}{pass}'
|
||||
)
|
||||
assert (
|
||||
r'Inline \sphinxcode{\sphinxupquote{%'
|
||||
+ '\n'
|
||||
+ common_content
|
||||
+ '%\n}} code block'
|
||||
'Inline \\sphinxcode{\\sphinxupquote{%\n' + common_content + '%\n}} code block'
|
||||
) in content
|
||||
assert (
|
||||
r'\begin{sphinxVerbatim}[commandchars=\\\{\}]'
|
||||
|
||||
@@ -260,7 +260,7 @@ def test_format_signature(app):
|
||||
def foo1(self, b, *c):
|
||||
pass
|
||||
|
||||
def foo2(b, *c):
|
||||
def foo2(b, *c): # NoQA: N805
|
||||
pass
|
||||
|
||||
def foo3(self, d='\n'):
|
||||
|
||||
@@ -33,12 +33,12 @@ def _private_undoc():
|
||||
pass
|
||||
|
||||
|
||||
def __special_doc__():
|
||||
def __special_doc__(): # NoQA: N807
|
||||
"""module.__special_doc__.DOCSTRING"""
|
||||
pass
|
||||
|
||||
|
||||
def __special_undoc__():
|
||||
def __special_undoc__(): # NoQA: N807
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ from sphinx.util.nodes import NodeMatcher
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from io import StringIO
|
||||
from pathlib import Path
|
||||
|
||||
_CATALOG_LOCALE = 'xx'
|
||||
|
||||
@@ -47,9 +48,9 @@ def write_mo(pathname, po):
|
||||
return mofile.write_mo(f, po)
|
||||
|
||||
|
||||
def _set_mtime_ns(target: str | os.PathLike[str], value: int) -> int:
|
||||
def _set_mtime_ns(target: Path, value: int) -> int:
|
||||
os.utime(target, ns=(value, value))
|
||||
return os.stat(target).st_mtime_ns
|
||||
return target.stat().st_mtime_ns
|
||||
|
||||
|
||||
def _get_bom_intl_path(app):
|
||||
|
||||
@@ -85,7 +85,7 @@ def test_progress_message(app):
|
||||
|
||||
# skipping case
|
||||
with progress_message('testing'):
|
||||
raise SkipProgressMessage('Reason: %s', 'error') # NoQA: EM101
|
||||
raise SkipProgressMessage('Reason: %s', 'error') # NoQA: EM101,TRY003
|
||||
|
||||
output = strip_colors(app.status.getvalue())
|
||||
assert 'testing... skipped\nReason: error\n' in output
|
||||
@@ -93,7 +93,7 @@ def test_progress_message(app):
|
||||
# error case
|
||||
try:
|
||||
with progress_message('testing'):
|
||||
raise RuntimeError
|
||||
raise RuntimeError # NoQA: TRY301
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
@@ -40,32 +40,32 @@ def test_register_node():
|
||||
assert not hasattr(nodes.SparseNodeVisitor, 'depart_custom_node')
|
||||
|
||||
|
||||
def test_SphinxFileOutput(tmpdir):
|
||||
def test_SphinxFileOutput(tmp_path):
|
||||
content = 'Hello Sphinx World'
|
||||
|
||||
# write test.txt at first
|
||||
filename = str(tmpdir / 'test.txt')
|
||||
output = SphinxFileOutput(destination_path=filename)
|
||||
filename = tmp_path / 'test.txt'
|
||||
output = SphinxFileOutput(destination_path=str(filename))
|
||||
output.write(content)
|
||||
os.utime(filename, ns=(0, 0))
|
||||
|
||||
# overwrite it again
|
||||
output.write(content)
|
||||
assert os.stat(filename).st_mtime_ns != 0 # updated
|
||||
assert filename.stat().st_mtime_ns != 0 # updated
|
||||
|
||||
# write test2.txt at first
|
||||
filename = str(tmpdir / 'test2.txt')
|
||||
output = SphinxFileOutput(destination_path=filename, overwrite_if_changed=True)
|
||||
filename = tmp_path / 'test2.txt'
|
||||
output = SphinxFileOutput(destination_path=str(filename), overwrite_if_changed=True)
|
||||
output.write(content)
|
||||
os.utime(filename, ns=(0, 0))
|
||||
|
||||
# overwrite it again
|
||||
output.write(content)
|
||||
assert os.stat(filename).st_mtime_ns == 0 # not updated
|
||||
assert filename.stat().st_mtime_ns == 0 # not updated
|
||||
|
||||
# overwrite it again (content changed)
|
||||
output.write(content + '; content change')
|
||||
assert os.stat(filename).st_mtime_ns != 0 # updated
|
||||
assert filename.stat().st_mtime_ns != 0 # updated
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='root')
|
||||
|
||||
@@ -39,7 +39,7 @@ def test_catalog_outdated(tmp_path):
|
||||
mo_file.write_text('#', encoding='utf8')
|
||||
assert not cat.is_outdated() # if mo is exist and newer than po
|
||||
|
||||
new_mtime = os.stat(mo_file).st_mtime_ns - 10_000_000_000
|
||||
new_mtime = mo_file.stat().st_mtime_ns - 10_000_000_000
|
||||
os.utime(mo_file, ns=(new_mtime, new_mtime)) # to be outdated
|
||||
assert cat.is_outdated() # if mo is exist and older than po
|
||||
|
||||
@@ -98,7 +98,7 @@ def test_format_date():
|
||||
def test_format_date_timezone():
|
||||
dt = datetime.datetime(2016, 8, 7, 5, 11, 17, 0, tzinfo=datetime.UTC)
|
||||
if time.localtime(dt.timestamp()).tm_gmtoff == 0:
|
||||
raise pytest.skip('Local time zone is GMT') # NoQA: EM101
|
||||
raise pytest.skip('Local time zone is GMT') # NoQA: EM101,TRY003
|
||||
|
||||
fmt = '%Y-%m-%d %H:%M:%S'
|
||||
|
||||
|
||||
@@ -942,7 +942,7 @@ def test_unpartial():
|
||||
def test_getdoc_inherited_classmethod():
|
||||
class Foo:
|
||||
@classmethod
|
||||
def meth(self):
|
||||
def meth(cls):
|
||||
"""
|
||||
Docstring
|
||||
indented text
|
||||
@@ -950,7 +950,7 @@ def test_getdoc_inherited_classmethod():
|
||||
|
||||
class Bar(Foo):
|
||||
@classmethod
|
||||
def meth(self):
|
||||
def meth(cls):
|
||||
# inherited classmethod
|
||||
pass
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import pytest
|
||||
@@ -94,10 +93,10 @@ def test_ambiguous_definition_warning(app):
|
||||
|
||||
def _write_appconfig(dir: Path, language: str, prefix: str | None = None) -> Path:
|
||||
prefix = prefix or language
|
||||
os.makedirs(dir / prefix, exist_ok=True)
|
||||
(dir / prefix).mkdir(parents=True, exist_ok=True)
|
||||
(dir / prefix / 'conf.py').write_text(f'language = "{language}"', encoding='utf8')
|
||||
(dir / prefix / 'index.rst').write_text('index.rst', encoding='utf8')
|
||||
assert sorted(os.listdir(dir / prefix)) == ['conf.py', 'index.rst']
|
||||
assert sorted(p.name for p in (dir / prefix).iterdir()) == ['conf.py', 'index.rst']
|
||||
assert (dir / prefix / 'index.rst').exists()
|
||||
return dir / prefix
|
||||
|
||||
|
||||
Reference in new issue
Block a user