Skip to content

Commit

Permalink
ci: Enable more Ruff rules
Browse files Browse the repository at this point in the history
  • Loading branch information
pawamoy committed Aug 20, 2024
1 parent 21b3780 commit 97f3613
Show file tree
Hide file tree
Showing 26 changed files with 128 additions and 126 deletions.
34 changes: 12 additions & 22 deletions config/ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,7 @@ line-length = 120
exclude = [
"tests/fixtures/*.py",
]
select = [
"A", "ANN", "ARG",
"B", "BLE",
"C", "C4",
"COM",
"D", "DTZ",
"E", "ERA", "EXE",
"F", "FBT",
"G",
"I", "ICN", "INP", "ISC",
"N",
"PGH", "PIE", "PL", "PLC", "PLE", "PLR", "PLW", "PT", "PYI",
"Q",
"RUF", "RSE", "RET",
"S", "SIM", "SLF",
"T", "T10", "T20", "TCH", "TID", "TRY",
"UP",
"W",
"YTT",
]
select = ["ALL"]
ignore = [
"A001", # Variable is shadowing a Python builtin
"ANN101", # Missing type annotation for self
Expand All @@ -36,16 +17,25 @@ ignore = [
"D105", # Missing docstring in magic method
"D417", # Missing argument description in the docstring
"E501", # Line too long
"EM", # Raw strings in exceptions
"FIX001", # Line contains FIXME
"FIX002", # Line contains TODO
"ERA001", # Commented out code
"G004", # Logging statement uses f-string
"PD", # Pandas-related
"PERF203", # Try-except block in for loop (zero-cost with Python 3.11+)
"PLR0911", # Too many return statements
"PLR0912", # Too many branches
"PLR0913", # Too many arguments to function call
"PLR0915", # Too many statements
"SLF001", # Private member accessed
"SLF001", # Private member accessed
"TD001", # Invalid TODO tag: FIXME
"TD002", # Missing author in TODO
"TD003", # Missing issue link on the line following this TODO
"TRY003", # Avoid specifying long messages outside the exception class
]

logger-objects = ["_griffe.logger.logger"]

[lint.per-file-ignores]
"src/*/__main__.py" = [
"D100", # Missing module docstring
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/users/extending.md
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ logger = griffe.get_logger(__name__)

class MyExtension(griffe.Extension):
def on_module_members(self, mod: griffe.Module, **kwargs) -> None:
logger.info(f"Doing some work on module {mod.path} and its members")
logger.info("Doing some work on module %s and its members", mod.path)
```

### Full example
Expand Down
9 changes: 5 additions & 4 deletions scripts/gen_credits.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,11 @@ def _set_license(metadata: PackageMetadata) -> None:
license_name = license_field if isinstance(license_field, str) else " + ".join(license_field)
check_classifiers = license_name in ("UNKNOWN", "Dual License", "") or license_name.count("\n")
if check_classifiers:
license_names = []
for classifier in metadata["classifier"]:
if classifier.startswith("License ::"):
license_names.append(classifier.rsplit("::", 1)[1].strip())
license_names = [
classifier.rsplit("::", 1)[1].strip()
for classifier in metadata["classifier"]
if classifier.startswith("License ::")
]
license_name = " + ".join(license_names)
metadata["license"] = license_name or "?"

Expand Down
2 changes: 1 addition & 1 deletion scripts/gen_structure_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def _render_call_graph(module: Path) -> None:
# The subprocess dies with SIGSEGV in GHA...
return
if 'class="node"' not in svg:
print("")
print()
else:
print(f'<div class="interactiveSVG code2flow">{svg}</div>')

Expand Down
2 changes: 1 addition & 1 deletion scripts/insiders.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def render(self, rel_base: str = "..") -> None: # noqa: D102
if self.features:
for feature in self.features:
feature.render(rel_base)
print("")
print()
else:
print("There are no features in this goal for this project. ")
print(
Expand Down
2 changes: 1 addition & 1 deletion scripts/make.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ def clean() -> None:
_shell(f"rm -rf {path}")

cache_dirs = [".cache", ".pytest_cache", ".mypy_cache", ".ruff_cache", "__pycache__"]
for dirpath in Path(".").rglob("*"):
for dirpath in Path().rglob("*"):
if any(dirpath.match(pattern) for pattern in cache_dirs) and not (
dirpath.match(".venv") or dirpath.match(".venvs")
):
Expand Down
2 changes: 1 addition & 1 deletion src/_griffe/agents/inspector.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ def generic_inspect(self, node: ObjectNode) -> None:
# so we skip it here (no member, no alias, just skip it).
if child.is_module and target_path == f"{self.current.path}.{child.name}":
if not hasattr(child.obj, "__file__"):
logger.debug(f"Module {target_path} is not discoverable on disk, inspecting right now")
logger.debug("Module %s is not discoverable on disk, inspecting right now", target_path)
inspector = Inspector(
child.name,
filepath=None,
Expand Down
2 changes: 1 addition & 1 deletion src/_griffe/agents/nodes/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __init__(self, obj: Any, name: str, parent: ObjectNode | None = None) -> Non
# which triggers the __getattr__ method of the object, which in
# turn can raise various exceptions. Probably not just __getattr__.
# See https://github.com/pawamoy/pytkdocs/issues/45
logger.debug(f"Could not unwrap {name}: {error!r}")
logger.debug("Could not unwrap %s: %r", name, error)

# Unwrap cached properties (`inspect.unwrap` doesn't do that).
if isinstance(obj, cached_property):
Expand Down
2 changes: 1 addition & 1 deletion src/_griffe/agents/nodes/values.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def safe_get_value(node: ast.AST | None, filepath: str | Path | None = None) ->
"""
try:
return get_value(node)
except Exception as error: # noqa: BLE001
except Exception as error:
message = f"Failed to represent node {node}"
if filepath:
message += f" at {filepath}:{node.lineno}" # type: ignore[union-attr]
Expand Down
21 changes: 9 additions & 12 deletions src/_griffe/agents/visitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,25 +253,22 @@ def visit_classdef(self, node: ast.ClassDef) -> None:
self.extensions.call("on_class_node", node=node, agent=self)

# handle decorators
decorators = []
decorators: list[Decorator] = []
if node.decorator_list:
lineno = node.decorator_list[0].lineno
for decorator_node in node.decorator_list:
decorators.append(
Decorator(
safe_get_expression(decorator_node, parent=self.current, parse_strings=False), # type: ignore[arg-type]
lineno=decorator_node.lineno,
endlineno=decorator_node.end_lineno,
),
decorators.extend(
Decorator(
safe_get_expression(decorator_node, parent=self.current, parse_strings=False), # type: ignore[arg-type]
lineno=decorator_node.lineno,
endlineno=decorator_node.end_lineno,
)
for decorator_node in node.decorator_list
)
else:
lineno = node.lineno

# handle base classes
bases = []
if node.bases:
for base in node.bases:
bases.append(safe_get_base_class(base, parent=self.current))
bases = [safe_get_base_class(base, parent=self.current) for base in node.bases]

class_ = Class(
name=node.name,
Expand Down
22 changes: 11 additions & 11 deletions src/_griffe/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def __call__(self, *args: Any, **kwargs: Any) -> None: # noqa: ARG002

def _print_data(data: str, output_file: str | IO | None) -> None:
if isinstance(output_file, str):
with open(output_file, "w") as fd:
with open(output_file, "w") as fd: # noqa: PTH123
print(data, file=fd)
else:
if output_file is None:
Expand Down Expand Up @@ -94,23 +94,23 @@ def _load_packages(
if not package:
logger.debug("Empty package name, continuing")
continue
logger.info(f"Loading package {package}")
logger.info("Loading package %s", package)
try:
loader.load(package, try_relative_path=True, find_stubs_package=find_stubs_package)
except ModuleNotFoundError as error:
logger.error(f"Could not find package {package}: {error}")
except ImportError as error:
logger.exception(f"Tried but could not import package {package}: {error}")
logger.error("Could not find package %s: %s", package, error) # noqa: TRY400
except ImportError:
logger.exception("Tried but could not import package %s", package)
logger.info("Finished loading packages")

# Resolve aliases.
if resolve_aliases:
logger.info("Starting alias resolution")
unresolved, iterations = loader.resolve_aliases(implicit=resolve_implicit, external=resolve_external)
if unresolved:
logger.info(f"{len(unresolved)} aliases were still unresolved after {iterations} iterations")
logger.info("%s aliases were still unresolved after %s iterations", len(unresolved), iterations)
else:
logger.info(f"All aliases were resolved after {iterations} iterations")
logger.info("All aliases were resolved after %s iterations", iterations)
return loader


Expand Down Expand Up @@ -379,8 +379,8 @@ def dump(

try:
loaded_extensions = load_extensions(*(extensions or ()))
except ExtensionError as error:
logger.exception(str(error))
except ExtensionError:
logger.exception("Could not load extensions")
return 1

# Load packages.
Expand Down Expand Up @@ -467,8 +467,8 @@ def check(

try:
loaded_extensions = load_extensions(*(extensions or ()))
except ExtensionError as error:
logger.exception(str(error))
except ExtensionError:
logger.exception("Could not load extensions")
return 1

# Load old and new version of the package.
Expand Down
6 changes: 3 additions & 3 deletions src/_griffe/diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ def _alias_incompatibilities(
old_member = old_obj.target if old_obj.is_alias else old_obj # type: ignore[union-attr]
new_member = new_obj.target if new_obj.is_alias else new_obj # type: ignore[union-attr]
except AliasResolutionError:
logger.debug(f"API check: {old_obj.path} | {new_obj.path}: skip alias with unknown target")
logger.debug("API check: %s | %s: skip alias with unknown target", old_obj.path, new_obj.path)
return

yield from _type_based_yield(old_member, new_member, seen_paths=seen_paths)
Expand All @@ -468,9 +468,9 @@ def _member_incompatibilities(
seen_paths = set() if seen_paths is None else seen_paths
for name, old_member in old_obj.all_members.items():
if not old_member.is_public:
logger.debug(f"API check: {old_obj.path}.{name}: skip non-public object")
logger.debug("API check: %s.%s: skip non-public object", old_obj.path, name)
continue
logger.debug(f"API check: {old_obj.path}.{name}")
logger.debug("API check: %s.%s", old_obj.path, name)
try:
new_member = new_obj.all_members[name]
except KeyError:
Expand Down
2 changes: 1 addition & 1 deletion src/_griffe/docstrings/google.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
_BlockItems = List[_BlockItem]
_ItemsBlock = Tuple[_BlockItems, int]

_RE_ADMONITION: Pattern = re.compile(r"^(?P<type>[\w][\s\w-]*):(\s+(?P<title>[^\s].*))?\s*$", re.I)
_RE_ADMONITION: Pattern = re.compile(r"^(?P<type>[\w][\s\w-]*):(\s+(?P<title>[^\s].*))?\s*$", re.IGNORECASE)
_RE_NAME_ANNOTATION_DESCRIPTION: Pattern = re.compile(r"^(?:(?P<name>\w+)?\s*(?:\((?P<type>.+)\))?:\s*)?(?P<desc>.*)$")
_RE_DOCTEST_BLANKLINE: Pattern = re.compile(r"^\s*<BLANKLINE>\s*$")
_RE_DOCTEST_FLAGS: Pattern = re.compile(r"(\s*#\s*doctest:.+)$")
Expand Down
7 changes: 4 additions & 3 deletions src/_griffe/docstrings/numpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ def _read_parameters(
warn_unknown_params: bool = True,
**options: Any,
) -> tuple[list[DocstringParameter], int]:
parameters = []
parameters: list[DocstringParameter] = []
annotation: str | Expr | None

items, new_offset = _read_block_items(docstring, offset=offset, **options)
Expand Down Expand Up @@ -274,8 +274,9 @@ def _read_parameters(
break
docstring_warning(docstring, new_offset, message)

for name in names:
parameters.append(DocstringParameter(name, value=default, annotation=annotation, description=description))
parameters.extend(
DocstringParameter(name, value=default, annotation=annotation, description=description) for name in names
)

return parameters, new_offset

Expand Down
3 changes: 2 additions & 1 deletion src/_griffe/expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -970,9 +970,10 @@ def _build_constant(
)
except SyntaxError:
logger.debug(
f"Tried and failed to parse {node.value!r} as Python code, "
"Tried and failed to parse %r as Python code, "
"falling back to using it as a string literal "
"(postponed annotations might help: https://peps.python.org/pep-0563/)",
node.value,
)
else:
return _build(parsed.body, parent, **kwargs) # type: ignore[attr-defined]
Expand Down
11 changes: 5 additions & 6 deletions src/_griffe/extensions/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ def call(self, event: str, **kwargs: Any) -> None:


def _load_extension_path(path: str) -> ModuleType:
module_name = os.path.basename(path).rsplit(".", 1)[0]
module_name = os.path.basename(path).rsplit(".", 1)[0] # noqa: PTH119
spec = spec_from_file_location(module_name, path)
if not spec:
raise ExtensionNotLoadedError(f"Could not import module from path '{path}'")
Expand Down Expand Up @@ -383,7 +383,7 @@ def _load_extension(
if import_path in builtin_extensions:
import_path = f"_griffe.extensions.{import_path}"
# If the import path is a path to an existing file, load it.
elif os.path.exists(import_path):
elif os.path.exists(import_path): # noqa: PTH110
try:
ext_object = _load_extension_path(import_path)
except ImportError as error:
Expand Down Expand Up @@ -415,10 +415,9 @@ def _load_extension(

# No class name was specified so we search all extension classes in the module,
# instantiate each with the same options, and return them.
extensions = []
for obj in vars(ext_object).values():
if isclass(obj) and issubclass(obj, Extension) and obj is not Extension:
extensions.append(obj)
extensions = [
obj for obj in vars(ext_object).values() if isclass(obj) and issubclass(obj, Extension) and obj is not Extension
]
return [ext(**options) for ext in extensions]


Expand Down
3 changes: 3 additions & 0 deletions src/_griffe/extensions/dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
ExprDict,
)
from _griffe.extensions.base import Extension
from _griffe.logger import logger
from _griffe.models import Attribute, Class, Decorator, Function, Module, Parameter, Parameters


Expand Down Expand Up @@ -171,6 +172,8 @@ def _set_dataclass_init(class_: Class) -> None:
if not _dataclass_decorator(class_.decorators):
return

logger.debug("Handling dataclass: %s", class_.path)

# Add current class parameters.
parameters.extend(_dataclass_parameters(class_))

Expand Down
6 changes: 3 additions & 3 deletions src/_griffe/finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ def iter_submodules(
for subpath in self._filter_py_modules(path):
rel_subpath = subpath.relative_to(path)
if rel_subpath.parent in skip:
logger.debug(f"Skip {subpath}, another module took precedence")
logger.debug("Skip %s, another module took precedence", subpath)
continue
py_file = rel_subpath.suffix == ".py"
stem = rel_subpath.stem
Expand Down Expand Up @@ -397,7 +397,7 @@ def _filter_py_modules(self, path: Path) -> Iterator[Path]:
# Optimization: modify dirs in-place to exclude `__pycache__` directories.
dirs[:] = [dir for dir in dirs if dir != "__pycache__"]
for relfile in files:
if os.path.splitext(relfile)[1] in self.extensions_set:
if os.path.splitext(relfile)[1] in self.extensions_set: # noqa: PTH122
yield Path(root, relfile)

def _top_module_name(self, path: Path) -> str:
Expand Down Expand Up @@ -464,7 +464,7 @@ def _handle_pth_file(path: Path) -> list[_SP]:
editable_module = path.parent / f"{line[len('import'):].lstrip()}.py"
with suppress(UnhandledEditableModuleError):
return _handle_editable_module(editable_module)
if line and not line.startswith("#") and os.path.exists(line):
if line and not line.startswith("#") and os.path.exists(line): # noqa: PTH110
directories.append(_SP(Path(line)))
return directories

Expand Down
2 changes: 1 addition & 1 deletion src/_griffe/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def tmp_worktree(repo: str | Path = ".", ref: str = "HEAD") -> Iterator[Path]:
repo_name = Path(repo).resolve().name
with TemporaryDirectory(prefix=f"{_WORKTREE_PREFIX}{repo_name}-{ref}-") as tmp_dir:
branch = f"griffe_{ref}"
location = os.path.join(tmp_dir, branch)
location = os.path.join(tmp_dir, branch) # noqa: PTH118
process = subprocess.run(
["git", "-C", repo, "worktree", "add", "-b", branch, location, ref],
capture_output=True,
Expand Down
Loading

0 comments on commit 97f3613

Please sign in to comment.