From 5b6a2e5e30d61d10f3a4b1b1fe6fd3abe669602d Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Wed, 20 May 2026 07:51:28 +0100 Subject: [PATCH] Ban dynamic builtins and typing.cast in lint config. Align pylint and ruff with literalizer: forbid bare filter, getattr, hasattr, map, and setattr via pylint, and ban typing.cast via ruff. Fix or exempt existing violations. Co-authored-by: Cursor --- pyproject.toml | 12 ++++++++++++ src/mock_vws/_requests_mock_server/decorators.py | 10 ++++++++-- src/mock_vws/_respx_mock_server/decorators.py | 5 ++++- tests/mock_vws/test_target_validators.py | 2 +- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2f3697500..91e753b2b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -198,6 +198,7 @@ lint.per-file-ignores."tests/**" = [ lint.unfixable = [ "ERA001", ] +lint.flake8-tidy-imports.banned-api."typing.cast".msg = "typing.cast is banned: use explicit type narrowing or a typed variable instead." lint.pydocstyle.convention = "google" [tool.pylint] @@ -242,6 +243,17 @@ MASTER.per-file-ignores = [ "docs/source/doccmd_*.py:invalid-name", "doccmd_README_rst_*.py:invalid-name", ] +DEPRECATED_BUILTINS.bad-functions = [ + # Use Pylint until Ruff can ban bare builtin calls, or until custom rules + # make this removable: + # https://github.com/astral-sh/ruff/issues/10079 + # https://github.com/astral-sh/ruff/issues/970 + "filter", + "getattr", + "hasattr", + "map", + "setattr", +] # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time (only on the command line, not in the configuration file where diff --git a/src/mock_vws/_requests_mock_server/decorators.py b/src/mock_vws/_requests_mock_server/decorators.py index ae699a3a1..5b0244c81 100644 --- a/src/mock_vws/_requests_mock_server/decorators.py +++ b/src/mock_vws/_requests_mock_server/decorators.py @@ -160,7 +160,10 @@ def wrapped( # req_kwargs is added dynamically by the responses # library onto PreparedRequest objects - it is not # in the requests type stubs. - req_kwargs: dict[str, Any] = getattr(request, "req_kwargs", {}) + req_kwargs: dict[str, Any] = request.__dict__.get( + "req_kwargs", + {}, + ) timeout: tuple[float, float] | float | int | None = req_kwargs.get( "timeout" ) @@ -221,7 +224,10 @@ def __enter__(self) -> Self: compiled_url_pattern = re.compile(pattern=url_pattern) for http_method in route.http_methods: - original_callback = getattr(api, route.route_name) + original_callback = object.__getattribute__( + api, + route.route_name, + ) mock.add_callback( method=http_method, url=compiled_url_pattern, diff --git a/src/mock_vws/_respx_mock_server/decorators.py b/src/mock_vws/_respx_mock_server/decorators.py index 090695d0a..92ed0c9e0 100644 --- a/src/mock_vws/_respx_mock_server/decorators.py +++ b/src/mock_vws/_respx_mock_server/decorators.py @@ -161,7 +161,10 @@ def start_respx_router( compiled_url_pattern = re.compile(pattern=url_pattern) for http_method in route.http_methods: - original_callback = getattr(api, route.route_name) + original_callback = object.__getattribute__( + api, + route.route_name, + ) router.route( method=http_method, url=compiled_url_pattern, diff --git a/tests/mock_vws/test_target_validators.py b/tests/mock_vws/test_target_validators.py index 0fc74601c..0dff2f865 100644 --- a/tests/mock_vws/test_target_validators.py +++ b/tests/mock_vws/test_target_validators.py @@ -71,7 +71,7 @@ def test_validate_target_id_exists_uses_correct_path_segment( """ database = _database_with_target(target_id=target_id) - monkeypatch.setattr( + monkeypatch.setattr( # pylint: disable=bad-builtin target=target_validators, name="get_database_matching_server_keys", value=partial(_always_match_database, database=database),