Skip to content

Commit

Permalink
Enable ruff preview rules (#441)
Browse files Browse the repository at this point in the history
  • Loading branch information
ssbarnea authored Jan 7, 2025
1 parent 18696a6 commit 415bdbb
Show file tree
Hide file tree
Showing 12 changed files with 403 additions and 58 deletions.
304 changes: 304 additions & 0 deletions .config/pydoclint-baseline.txt

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ ci:
# format compatible with commitlint
autoupdate_commit_msg: "chore: pre-commit autoupdate"
autoupdate_schedule: monthly
autofix_commit_msg: |
chore: auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
autofix_commit_msg: "chore: auto fixes from pre-commit.com hooks"
skip:
# https://github.com/pre-commit-ci/issues/issues/55
- ccv
Expand Down Expand Up @@ -51,7 +48,7 @@ repos:
examples/playbooks/example.yml
)$
- id: mixed-line-ending
- id: check-byte-order-marker
- id: fix-byte-order-marker
- id: check-executables-have-shebangs
- id: check-merge-conflict
- id: debug-statements
Expand All @@ -60,6 +57,10 @@ repos:
rev: v2.3.0
hooks:
- id: codespell
- repo: https://github.com/jsh9/pydoclint
rev: 0.5.9
hooks:
- id: pydoclint
- repo: https://github.com/adrienverge/yamllint.git
rev: v1.35.1
hooks:
Expand Down
41 changes: 32 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[build-system]
requires = [
"setuptools >= 65.3.0", # required by pyproject+setuptools_scm integration and editable installs
"setuptools_scm[toml] >= 7.0.5", # required for "no-local-version" scheme
"setuptools_scm[toml] >= 7.0.5" # required for "no-local-version" scheme
]
build-backend = "setuptools.build_meta"

Expand Down Expand Up @@ -34,7 +34,7 @@ classifiers = [
"Topic :: Software Development :: Bug Tracking",
"Topic :: Software Development :: Quality Assurance",
"Topic :: Software Development :: Testing",
"Topic :: Utilities",
"Topic :: Utilities"
]
keywords = ["ansible"]

Expand Down Expand Up @@ -83,6 +83,19 @@ ignore_missing_imports = true
module = "ansible_compat._version"
ignore_errors = true

[tool.pydoclint]
allow-init-docstring = true
arg-type-hints-in-docstring = false
baseline = ".config/pydoclint-baseline.txt"
check-return-types = false
check-yield-types = false
exclude = '\.cache|\.git|\.tox|build|out|venv'
quiet = true # no need to print out the files being checked
should-document-private-class-attributes = true
show-filenames-in-every-violation-message = true
skip-checking-short-docstrings = false
style = "google"

[tool.pylint.BASIC]
good-names = [
"f", # filename
Expand All @@ -92,7 +105,7 @@ good-names = [
"ns", # namespace
"ex",
"Run",
"_",
"_"
]

[tool.pylint.IMPORTS]
Expand Down Expand Up @@ -210,6 +223,7 @@ disable = [
"R0914", # too-many-locals / ruff PLR0914
"R0915", # too-many-statements / ruff PLR0915
"R0916", # too-many-boolean-expressions / ruff PLR0916
"R0917", # too-many-positional-arguments / ruff PLR0917
"R1260", # too-complex / ruff C901
"R1701", # consider-merging-isinstance / ruff PLR1701
"R1702", # too-many-nested-blocks / ruff PLR1702
Expand Down Expand Up @@ -333,26 +347,28 @@ disable = [
"too-many-arguments", # PLR0913
"raise-missing-from",
# Temporary disable duplicate detection we remove old code from prerun
"duplicate-code",
"duplicate-code"
]

[tool.pytest.ini_options]
addopts = "-p no:pytest_cov --durations=10 --durations-min=1.0 --failed-first"
# ensure we treat warnings as error
filterwarnings = [
"error",
# py312 ansible-core
# https://github.com/ansible/ansible/issues/81906
"ignore:'importlib.abc.TraversableResources' is deprecated and slated for removal in Python 3.14:DeprecationWarning",
"ignore:'importlib.abc.TraversableResources' is deprecated and slated for removal in Python 3.14:DeprecationWarning"
]
testpaths = ["test"]

[tool.ruff]
preview = true
extend-include = ["src/ansible_compat/_version.py"]
target-version = "py39"
lint.select = ["ALL"]
lint.ignore = [
# Disabled on purpose:
"ANN101", # Missing type annotation for `self` in method
"CPY001",
"D203", # incompatible with D211
"D211",
"D213", # incompatible with D212
Expand All @@ -364,8 +380,14 @@ lint.ignore = [
"PLR0913", # Bug https://github.com/charliermarsh/ruff/issues/4244
"RUF012",
"PERF203",
"DOC201", # preview
"PLC0415",
"DOC501" # preview
]

[tool.ruff.format]
docstring-code-format = true

[tool.ruff.lint.flake8-pytest-style]
parametrize-values-type = "tuple"

Expand All @@ -374,10 +396,11 @@ known-first-party = ["ansible_compat"]
known-third-party = ["packaging"]

[tool.ruff.lint.per-file-ignores]
"test/**/*.py" = ["SLF001", "S101", "FBT001"]
"test/**/*.py" = ["DOC402", "DOC501", "SLF001", "S101", "S404", "FBT001", "PLC2701"]

[tool.ruff.lint.pydocstyle]
convention = "pep257"
convention = "google"


[tool.setuptools.dynamic]
dependencies = { file = [".config/requirements.in"] }
Expand All @@ -396,7 +419,7 @@ git_describe_command = [
"--tags",
"--long",
"--match",
"v*.*",
"v*.*"
]

[tool.uv.pip]
Expand Down
8 changes: 4 additions & 4 deletions src/ansible_compat/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import copy
import os
import re
import subprocess
import subprocess # noqa: S404
from collections import UserDict
from typing import TYPE_CHECKING, Literal

Expand Down Expand Up @@ -446,9 +446,9 @@ def __init__(

def __getattribute__(self, attr_name: str) -> object:
"""Allow access of config options as attributes."""
_dict = super().__dict__ # pylint: disable=no-member
if attr_name in _dict:
return _dict[attr_name]
parent_dict = super().__dict__ # pylint: disable=no-member
if attr_name in parent_dict:
return parent_dict[attr_name]

data = super().__getattribute__("data")
if attr_name == "data": # pragma: no cover
Expand Down
2 changes: 1 addition & 1 deletion src/ansible_compat/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from ansible_compat.constants import ANSIBLE_MISSING_RC, INVALID_PREREQUISITES_RC

if TYPE_CHECKING: # pragma: no cover
from subprocess import CompletedProcess
from subprocess import CompletedProcess # noqa: S404


class AnsibleCompatError(RuntimeError):
Expand Down
39 changes: 22 additions & 17 deletions src/ansible_compat/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import os
import re
import shutil
import subprocess
import subprocess # noqa: S404
import sys
import warnings
from collections import OrderedDict
Expand Down Expand Up @@ -243,7 +243,7 @@ def warning(
# Monkey patch ansible warning in order to use warnings module.
Display.warning = warning

def initialize_logger(self, level: int = 0) -> None:
def initialize_logger(self, level: int = 0) -> None: # noqa: PLR6301
"""Set up the global logging level based on the verbosity number."""
verbosity_map = {
-2: logging.CRITICAL,
Expand Down Expand Up @@ -312,7 +312,7 @@ def load_collections(self) -> None:

if collection in self.collections:
msg = f"Another version of '{collection}' {collection_info['version']} was found installed in {path}, only the first one will be used, {self.collections[collection].version} ({self.collections[collection].path})."
logging.warning(msg)
_logger.warning(msg)
else:
self.collections[collection] = Collection(
name=collection,
Expand Down Expand Up @@ -343,7 +343,7 @@ def _ensure_module_available(self) -> None:
col_path = [f"{self.cache_dir}/collections"]
# noinspection PyProtectedMember
from ansible.utils.collection_loader._collection_finder import ( # pylint: disable=import-outside-toplevel
_AnsibleCollectionFinder,
_AnsibleCollectionFinder, # noqa: PLC2701
)

if self.version >= Version("2.15.0.dev0"):
Expand Down Expand Up @@ -472,7 +472,7 @@ def has_playbook(self, playbook: str, *, basedir: Path | None = None) -> bool:
if not basedir:
basedir = Path()
msg = f"has_playbook returned false for '{basedir / playbook}' due to syntax check returning {proc.returncode}"
logging.debug(msg)
_logger.debug(msg)

# cache the result
self._has_playbook_cache[playbook, basedir] = result
Expand Down Expand Up @@ -565,7 +565,7 @@ def install_requirements( # noqa: C901

if isinstance(reqs_yaml, dict):
for key in reqs_yaml:
if key not in ("roles", "collections"):
if key not in {"roles", "collections"}:
msg = f"{requirement} file is not a valid Ansible requirements file. Only 'roles' and 'collections' keys are allowed at root level. Recognized valid locations are: {', '.join(REQUIREMENT_LOCATIONS)}"
raise InvalidPrerequisiteError(msg)

Expand Down Expand Up @@ -741,10 +741,13 @@ def require_collection(
In the future this method may attempt to install a missing or outdated
collection before failing.
:param name: collection name
:param version: minimal version required
:param install: if True, attempt to install a missing collection
:returns: tuple of (found_version, collection_path)
Args:
name: collection name
version: minimal version required
install: if True, attempt to install a missing collection
Returns:
tuple of (found_version, collection_path)
"""
try:
ns, coll = name.split(".", 1)
Expand Down Expand Up @@ -861,14 +864,16 @@ def _install_galaxy_role(
) -> None:
"""Detect standalone galaxy role and installs it.
:param: role_name_check: logic to used to check role name
0: exit with error if name is not compliant (default)
1: warn if name is not compliant
2: bypass any name checking
Args:
project_dir: path to the role
role_name_check: logic to used to check role name
0: exit with error if name is not compliant (default)
1: warn if name is not compliant
2: bypass any name checking
:param: ignore_errors: if True, bypass installing invalid roles.
ignore_errors: if True, bypass installing invalid roles.
Our implementation aims to match ansible-galaxy's behaviour for installing
Our implementation aims to match ansible-galaxy's behavior for installing
roles from a tarball or scm. For example ansible-galaxy will install a role
that has both galaxy.yml and meta/main.yml present but empty. Also missing
galaxy.yml is accepted but missing meta/main.yml is not.
Expand All @@ -892,7 +897,7 @@ def _install_galaxy_role(

fqrn = _get_role_fqrn(galaxy_info, project_dir)

if role_name_check in [0, 1]:
if role_name_check in {0, 1}:
if not re.match(r"[a-z0-9][a-z0-9_-]+\.[a-z][a-z0-9_]+$", fqrn):
msg = MSG_INVALID_FQRL.format(fqrn)
if role_name_check == 1:
Expand Down
28 changes: 20 additions & 8 deletions src/ansible_compat/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,23 @@
def to_path(schema_path: Sequence[str | int]) -> str:
"""Flatten a path to a dot delimited string.
:param schema_path: The schema path
:returns: The dot delimited path
Args:
schema_path: The schema path
Returns:
The dot delimited path
"""
return ".".join(str(index) for index in schema_path)


def json_path(absolute_path: Sequence[str | int]) -> str:
"""Flatten a data path to a dot delimited string.
:param absolute_path: The path
:returns: The dot delimited string
Args:
absolute_path: The path
Returns:
The dot delimited string
"""
path = "$"
for elem in absolute_path:
Expand Down Expand Up @@ -56,7 +62,7 @@ class JsonSchemaError:
def to_friendly(self) -> str:
"""Provide a friendly explanation of the error.
:returns: The error message
Return: The error message
"""
return f"In '{self.data_path}': {self.message}."

Expand All @@ -67,9 +73,15 @@ def validate(
) -> list[JsonSchemaError]:
"""Validate some data against a JSON schema.
:param schema: the JSON schema to use for validation
:param data: The data to validate
:returns: Any errors encountered
Args:
schema: the JSON schema to use for validation
data: The data to validate
Returns:
Any errors encountered
Raises:
SchemaError if the schema is invalid
"""
errors: list[JsonSchemaError] = []

Expand Down
2 changes: 1 addition & 1 deletion src/ansible_compat/types.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Custom types."""
"""Custom types.""" # noqa: A005

from __future__ import annotations

Expand Down
6 changes: 3 additions & 3 deletions test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,6 @@ def venv_module(tmp_path_factory: pytest.TempPathFactory) -> VirtualEnvironment:
:return: VirtualEnvironment instance
"""
test_project = tmp_path_factory.mktemp(basename="test_project-", numbered=True)
_venv = VirtualEnvironment(test_project)
_venv.create()
return _venv
venv_ = VirtualEnvironment(test_project)
venv_.create()
return venv_
2 changes: 1 addition & 1 deletion test/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def test_ansible_version_missing(monkeypatch: MonkeyPatch) -> None:
)
with pytest.raises(
MissingAnsibleError,
match="Unable to find a working copy of ansible executable.",
match=r"Unable to find a working copy of ansible executable.",
):
# bypassing lru cache
ansible_version.__wrapped__()
Expand Down
Loading

0 comments on commit 415bdbb

Please sign in to comment.