Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ dev = [
"sentry-cli>=2.16.0",
"sentry-covdefaults-disable-branch-coverage>=1.0.2",
"sentry-devenv>=1.22.0",
"sentry-forked-django-stubs>=5.2.2.post1",
"sentry-forked-django-stubs>=5.2.2.post2",
"sentry-forked-djangorestframework-stubs>=3.16.2.post1",
"time-machine>=2.16.0",
"types-beautifulsoup4>=4.11.6",
Expand Down
40 changes: 40 additions & 0 deletions tests/tools/mypy_helpers/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,3 +270,43 @@ def f(self) -> int:

ret, out = call_mypy(src)
assert ret == 0


def test_base_cache_adjusted_version_type() -> None:
src = """\
from django.core.cache import cache

cache.set(key='123', value='456', version='deadbeef')
"""

expected = """\
<string>:3: error: Argument "version" to "set" of "BaseCache" has incompatible type "str"; expected "int | None" [arg-type]
Found 1 error in 1 file (checked 1 source file)
"""

ret, out = call_mypy(src, plugins=[])
assert ret
assert out == expected

ret, out = call_mypy(src)
assert ret == 0


def test_base_cache_incr_decr_version_removed() -> None:
src = """\
from django.core.cache import cache

cache.incr_version('123')
"""

expected = """\
<string>:3: error: removed method [misc]
Found 1 error in 1 file (checked 1 source file)
"""

ret, out = call_mypy(src, plugins=[])
assert ret == 0

ret, out = call_mypy(src)
assert ret
assert out == expected
35 changes: 35 additions & 0 deletions tools/mypy_helpers/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
AttributeContext,
ClassDefContext,
FunctionSigContext,
MethodContext,
MethodSigContext,
Plugin,
SemanticAnalyzerPluginInterface,
)
Expand Down Expand Up @@ -70,6 +72,20 @@ def replace_transaction_atomic_sig_callback(ctx: FunctionSigContext) -> Callable
}


def _modify_base_cache_version_type(ctx: MethodSigContext) -> FunctionLike:
if "version" not in ctx.default_signature.arg_names:
return ctx.default_signature

types = list(ctx.default_signature.arg_types)
types[ctx.default_signature.arg_names.index("version")] = AnyType(TypeOfAny.explicit)
return ctx.default_signature.copy_modified(types)


def _remove_base_cache_decr_incr(ctx: MethodContext) -> Type:
ctx.api.fail("removed method", ctx.context)
return ctx.default_return_type


_AUTH_TOKEN_TP = "sentry.auth.services.auth.model.AuthenticatedToken"


Expand Down Expand Up @@ -168,6 +184,25 @@ def get_function_signature_hook(
) -> Callable[[FunctionSigContext], FunctionLike] | None:
return _FUNCTION_SIGNATURE_HOOKS.get(fullname)

def get_method_signature_hook(
self, fullname: str
) -> Callable[[MethodSigContext], FunctionLike] | None:
if fullname.startswith("django.core.cache.backends.base.BaseCache."):
return _modify_base_cache_version_type
else:
return None

def get_method_hook(self, fullname: str) -> Callable[[MethodContext], Type] | None:
if fullname in (
"django.core.cache.backends.base.BaseCache.adecr_version",
"django.core.cache.backends.base.BaseCache.aincr_version",
"django.core.cache.backends.base.BaseCache.decr_version",
"django.core.cache.backends.base.BaseCache.incr_version",
):
return _remove_base_cache_decr_incr
else:
return None

def get_customize_class_mro_hook(
self, fullname: str
) -> Callable[[ClassDefContext], None] | None:
Expand Down
6 changes: 3 additions & 3 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading