Skip to content

Commit

Permalink
Extend linter/formatter rules (#427)
Browse files Browse the repository at this point in the history
  • Loading branch information
gaborbernat committed Feb 13, 2024
1 parent 124fde4 commit 252ed89
Show file tree
Hide file tree
Showing 9 changed files with 64 additions and 61 deletions.
34 changes: 22 additions & 12 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,27 +71,37 @@ line-length = 120
line-length = 120
target-version = "py37"
lint.select = ["ALL"]
lint.isort = {known-first-party = ["sphinx_autodoc_typehints", "tests"], required-imports = ["from __future__ import annotations"]}
lint.isort = { known-first-party = [
"sphinx_autodoc_typehints",
"tests",
], required-imports = [
"from __future__ import annotations",
] }
lint.ignore = [
"ANN101", # no type annotation for self
"ANN401", # allow Any as type annotation
"D203", # `one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible
"D212", # `multi-line-summary-first-line` (D212) and `multi-line-summary-second-line` (D213) are incompatible
"S104", # Possible binding to all interface
"ANN101", # no type annotation for self
"ANN401", # allow Any as type annotation
"D203", # `one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible
"D212", # `multi-line-summary-first-line` (D212) and `multi-line-summary-second-line` (D213) are incompatible
"S104", # Possible binding to all interface
"COM812", # Conflict with formatter
"ISC001", # Conflict with formatter
"CPY", # No copyright statements
]
lint.preview = true
format.preview = true
format.docstring-code-format = true
format.docstring-code-line-length = 100
[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = [
"S101", # asserts allowed in tests...
"FBT", # don"t care about booleans as positional arguments in tests
"INP001", # no implicit namespace
"D", # don't care about documentation in tests
"S603", # `subprocess` call: check for execution of untrusted input
"PLR2004", # Magic value used in comparison, consider replacing with a constant variable
"S101", # asserts allowed in tests...
"FBT", # don"t care about booleans as positional arguments in tests
"INP001", # no implicit namespace
"D", # don't care about documentation in tests
"S603", # `subprocess` call: check for execution of untrusted input
"PLR2004", # Magic value used in comparison, consider replacing with a constant variable
"PLR0913", # any number of arguments in tests
"PLR0917", # any number of arguments in tests
"PLC2701", # private imports
]

[tool.codespell]
Expand Down
30 changes: 15 additions & 15 deletions src/sphinx_autodoc_typehints/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def get_annotation_module(annotation: Any) -> str:
if (
is_new_type
or isinstance(annotation, TypeVar)
or type(annotation).__name__ in ("ParamSpec", "ParamSpecArgs", "ParamSpecKwargs")
or type(annotation).__name__ in {"ParamSpec", "ParamSpecArgs", "ParamSpecKwargs"}
):
return "typing"
if hasattr(annotation, "__module__"):
Expand Down Expand Up @@ -107,7 +107,7 @@ def get_annotation_class_name(annotation: Any, module: str) -> str: # noqa: C90
return annotation.__qualname__ # type: ignore[no-any-return]
if getattr(annotation, "_name", None): # Required for generic aliases on Python 3.7+
return annotation._name # type: ignore[no-any-return] # noqa: SLF001
if module in ("typing", "typing_extensions") and isinstance(getattr(annotation, "name", None), str):
if module in {"typing", "typing_extensions"} and isinstance(getattr(annotation, "name", None), str):
# Required for at least Pattern and Match
return annotation.name # type: ignore[no-any-return]

Expand Down Expand Up @@ -140,7 +140,7 @@ def get_annotation_args(annotation: Any, module: str, class_name: str) -> tuple[
return () # This is the original, not parametrized type

# Special cases
if class_name in ("Pattern", "Match") and hasattr(annotation, "type_var"): # Python < 3.7
if class_name in {"Pattern", "Match"} and hasattr(annotation, "type_var"): # Python < 3.7
return (annotation.type_var,)
if class_name == "ClassVar" and hasattr(annotation, "__type__"): # ClassVar on Python < 3.7
return (annotation.__type__,)
Expand Down Expand Up @@ -169,7 +169,7 @@ def format_internal_tuple(t: tuple[Any, ...], config: Config) -> str:
return f"({', '.join(fmt)})"


def format_annotation(annotation: Any, config: Config) -> str: # noqa: C901, PLR0911, PLR0912, PLR0915
def format_annotation(annotation: Any, config: Config) -> str: # noqa: C901, PLR0911, PLR0912, PLR0915, PLR0914
"""
Format the annotation.
Expand Down Expand Up @@ -238,7 +238,7 @@ def format_annotation(annotation: Any, config: Config) -> str: # noqa: C901, PL
formatted_args = None if args else args_format
elif full_name == "typing.Optional":
args = tuple(x for x in args if x is not type(None))
elif full_name in ("typing.Union", "types.UnionType") and type(None) in args:
elif full_name in {"typing.Union", "types.UnionType"} and type(None) in args:
if len(args) == 2: # noqa: PLR2004
full_name = "typing.Optional"
role = "data"
Expand All @@ -250,7 +250,7 @@ def format_annotation(annotation: Any, config: Config) -> str: # noqa: C901, PL
role = "data"
args_format = f"\\[:py:data:`{prefix}typing.Union`\\[{{}}]]"
args = tuple(x for x in args if x is not type(None))
elif full_name in ("typing.Callable", "collections.abc.Callable") and args and args[0] is not ...:
elif full_name in {"typing.Callable", "collections.abc.Callable"} and args and args[0] is not ...:
fmt = [format_annotation(arg, config) for arg in args]
formatted_args = f"\\[\\[{', '.join(fmt[:-1])}], {fmt[-1]}]"
elif full_name == "typing.Literal":
Expand Down Expand Up @@ -316,7 +316,7 @@ def remove_prefix(text: str, prefix: str) -> str:
return "\n".join(aligned_prefix + aligned_suffix)


def process_signature( # noqa: C901, PLR0913
def process_signature( # noqa: C901, PLR0913, PLR0917
app: Sphinx,
what: str,
name: str,
Expand Down Expand Up @@ -541,7 +541,7 @@ def _one_child(module: Module) -> stmt | None:
comment_args = split_type_comment_args(comment_args_str)
is_inline = len(comment_args) == 1 and comment_args[0] == "..."
if not is_inline:
if args and args[0].arg in ("self", "cls") and len(comment_args) != len(args):
if args and args[0].arg in {"self", "cls"} and len(comment_args) != len(args):
comment_args.insert(0, None) # self/cls may be omitted in type comments, insert blank

if len(args) != len(comment_args):
Expand Down Expand Up @@ -590,9 +590,9 @@ def add(val: str) -> None:

brackets, start_arg_at, at = 0, 0, 0
for at, char in enumerate(comment):
if char in ("[", "("):
if char in {"[", "("}:
brackets += 1
elif char in ("]", ")"):
elif char in {"]", ")"}:
brackets -= 1
elif char == "," and brackets == 0:
add(comment[start_arg_at:at])
Expand All @@ -616,7 +616,7 @@ def format_default(app: Sphinx, default: Any, is_annotated: bool) -> str | None:
return f"default: ``{formatted}``"


def process_docstring( # noqa: PLR0913
def process_docstring( # noqa: PLR0913, PLR0917, PLR0917
app: Sphinx,
what: str,
name: str,
Expand Down Expand Up @@ -695,7 +695,7 @@ def _line_is_param_line_for_arg(line: str, arg_name: str) -> bool:
return any(doc_name == prefix + arg_name for prefix in ("", "\\*", "\\**", "\\*\\*"))


def _inject_types_to_docstring( # noqa: PLR0913
def _inject_types_to_docstring( # noqa: PLR0913, PLR0917
type_hints: dict[str, Any],
signature: inspect.Signature | None,
original_obj: Any,
Expand Down Expand Up @@ -826,7 +826,7 @@ def get_insert_index(app: Sphinx, lines: list[str]) -> InsertIndexInfo | None:

# 4. Insert before examples
for child in doc.children:
if tag_name(child) in ["literal_block", "paragraph", "field_list"]:
if tag_name(child) in {"literal_block", "paragraph", "field_list"}:
continue
line_no = node_line_no(child)
at = line_no - 2 if line_no else len(lines)
Expand All @@ -836,7 +836,7 @@ def get_insert_index(app: Sphinx, lines: list[str]) -> InsertIndexInfo | None:
return InsertIndexInfo(insert_index=len(lines))


def _inject_rtype( # noqa: PLR0913
def _inject_rtype( # noqa: PLR0913, PLR0917
type_hints: dict[str, Any],
original_obj: Any,
app: Sphinx,
Expand Down Expand Up @@ -950,12 +950,12 @@ def setup(app: Sphinx) -> dict[str, bool]:

__all__ = [
"__version__",
"backfill_type_hints",
"format_annotation",
"get_annotation_args",
"get_annotation_class_name",
"get_annotation_module",
"normalize_source_lines",
"process_docstring",
"process_signature",
"backfill_type_hints",
]
2 changes: 1 addition & 1 deletion src/sphinx_autodoc_typehints/attributes_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
def _stringify_annotation(app: Sphinx, annotation: Any, mode: str = "") -> str: # noqa: ARG001
# Format the annotation with sphinx-autodoc-typehints and inject our magic prefix to tell our patched
# PyAttribute.handle_signature to treat it as rst.
from . import format_annotation
from . import format_annotation # noqa: PLC0415

return TYPE_IS_RST_LABEL + format_annotation(annotation, app.config)

Expand Down
8 changes: 4 additions & 4 deletions src/sphinx_autodoc_typehints/patches.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ def fix_autodoc_typehints_for_overloaded_methods() -> None:
See https://github.com/tox-dev/sphinx-autodoc-typehints/issues/296
"""
from sphinx.ext.autodoc import FunctionDocumenter, MethodDocumenter
from sphinx.ext.autodoc import FunctionDocumenter, MethodDocumenter # noqa: PLC0415

del FunctionDocumenter.format_signature
del MethodDocumenter.format_signature


def napoleon_numpy_docstring_return_type_processor( # noqa: PLR0913
def napoleon_numpy_docstring_return_type_processor( # noqa: PLR0913, PLR0917
app: Sphinx,
what: str,
name: str, # noqa: ARG001
Expand All @@ -43,7 +43,7 @@ def napoleon_numpy_docstring_return_type_processor( # noqa: PLR0913
lines: list[str],
) -> None:
"""Insert a : under Returns: to tell napoleon not to look for a return type."""
if what not in ["function", "method"]:
if what not in {"function", "method"}:
return
if not getattr(app.config, "napoleon_numpy_docstring", False):
return
Expand All @@ -52,7 +52,7 @@ def napoleon_numpy_docstring_return_type_processor( # noqa: PLR0913
# Returns:
# --------
for pos, line in enumerate(lines[:-2]):
if line.lower().strip(":") not in ["return", "returns"]:
if line.lower().strip(":") not in {"return", "returns"}:
continue
# Underline detection.
chars = set(lines[pos + 1].strip())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class SomeClass:
"""Date to handle"""

@classmethod
def from_str(cls, input_value: str) -> SomeClass: # noqa: ANN102
def from_str(cls, input_value: str) -> SomeClass:
"""
Initialize from string
Expand All @@ -25,7 +25,7 @@ def from_str(cls, input_value: str) -> SomeClass: # noqa: ANN102
return cls(input_value)

@classmethod
def from_date(cls, input_value: datetime.date) -> SomeClass: # noqa: ANN102
def from_date(cls, input_value: datetime.date) -> SomeClass:
"""
Initialize from date
Expand All @@ -35,7 +35,7 @@ def from_date(cls, input_value: datetime.date) -> SomeClass: # noqa: ANN102
return cls(input_value)

@classmethod
def from_time(cls, input_value: datetime.time) -> SomeClass: # noqa: ANN102
def from_time(cls, input_value: datetime.time) -> SomeClass:
"""
Initialize from time
Expand All @@ -44,7 +44,7 @@ def from_time(cls, input_value: datetime.time) -> SomeClass: # noqa: ANN102
"""
return cls(input_value)

def calculate_thing(self, number: float) -> datetime.timedelta:
def calculate_thing(self, number: float) -> datetime.timedelta: # noqa: PLR6301
"""
Calculate a thing
Expand Down
9 changes: 4 additions & 5 deletions tests/roots/test-resolve-typing-guard/demo_typing_guard.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,13 @@ def guarded(self, item: Decimal) -> None:
"""


def func(_x: Literal) -> None:
...
def func(_x: Literal) -> None: ...


__all__ = [
"a",
"AnotherClass",
"SomeClass",
"ValueError",
"a",
"cmp_to_key",
"SomeClass",
"AnotherClass",
]
18 changes: 8 additions & 10 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,15 +175,15 @@ def __dunder_method(self, x: str) -> str:
:param x: foo
"""

def __magic_custom_method__(self, x: str) -> str:
def __magic_custom_method__(self, x: str) -> str: # noqa: PLW3201
"""
Magic dunder method docstring.
:param x: foo
"""

@classmethod
def a_classmethod(cls, x: bool, y: int, z: Optional[str] = None) -> str: # noqa: ANN102, UP007
def a_classmethod(cls, x: bool, y: int, z: Optional[str] = None) -> str: # noqa: UP007
"""
Classmethod docstring.
Expand Down Expand Up @@ -415,7 +415,7 @@ def __init__(
# type: (...) -> None
pass

def foo( # noqa: ANN201
def foo( # noqa: ANN201, PLR6301
self,
x, # type: str # noqa: ANN001, ARG002
):
Expand All @@ -427,7 +427,7 @@ def foo( # noqa: ANN201
"""
return 42

def method_without_typehint(self, x): # noqa: ANN001, ANN201, ARG002
def method_without_typehint(self, x): # noqa: ANN001, ANN201, ARG002, PLR6301
"""
Method docstring.
"""
Expand Down Expand Up @@ -510,7 +510,7 @@ class ClassWithTypehintsNotInline:
def __init__(self, x=None) -> None: # type: (Optional[Callable[[int, bytes], int]]) -> None # noqa: ANN001
pass

def foo(self, x=1): # type: (Callable[[int, bytes], int]) -> int # noqa: ANN001, ANN201
def foo(self, x=1): # type: (Callable[[int, bytes], int]) -> int # noqa: ANN001, ANN201, PLR6301
"""
Method docstring.
Expand All @@ -520,7 +520,7 @@ def foo(self, x=1): # type: (Callable[[int, bytes], int]) -> int # noqa: ANN00

@classmethod
def mk( # noqa: ANN206
cls, # noqa: ANN102
cls,
x=None, # noqa: ANN001
): # type: (Optional[Callable[[int, bytes], int]]) -> ClassWithTypehintsNotInline
"""
Expand Down Expand Up @@ -625,13 +625,11 @@ def func_with_examples() -> int:


@overload
def func_with_overload(a: int, b: int) -> None:
...
def func_with_overload(a: int, b: int) -> None: ...


@overload
def func_with_overload(a: str, b: str) -> None:
...
def func_with_overload(a: str, b: str) -> None: ...


@expected(
Expand Down
14 changes: 5 additions & 9 deletions tests/test_sphinx_autodoc_typehints.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,20 +81,17 @@ class A:
def get_type(self) -> type:
return type(self)

class Inner:
...
class Inner: ...


class B(Generic[T]):
name = "Foo" # This is set to make sure the correct class name ("B") is picked up


class C(B[str]):
...
class C(B[str]): ...


class D(typing_extensions.Protocol):
...
class D(typing_extensions.Protocol): ...


class E(typing_extensions.Protocol[T]): # type: ignore[misc]
Expand All @@ -105,8 +102,7 @@ class Slotted:
__slots__ = ()


class Metaclass(type):
...
class Metaclass(type): ...


class HintedMethods:
Expand Down Expand Up @@ -843,7 +839,7 @@ def test_resolve_typing_guard_attrs_imports(app: SphinxTestApp, status: StringIO


def test_no_source_code_type_guard() -> None:
from csv import Error
from csv import Error # noqa: PLC0415

_resolve_type_guarded_imports([], Error)

Expand Down

0 comments on commit 252ed89

Please sign in to comment.