Browse Source

ref: move our descriptor hack to our django-stubs fork (#59725)

<!-- Describe your PR here. -->
anthony sottile 1 year ago
parent
commit
ac5f8a893d

+ 1 - 1
requirements-dev-frozen.txt

@@ -170,7 +170,7 @@ s3transfer==0.6.1
 selenium==4.3.0
 selenium==4.3.0
 sentry-arroyo==2.14.19
 sentry-arroyo==2.14.19
 sentry-cli==2.16.0
 sentry-cli==2.16.0
-sentry-forked-django-stubs==4.2.6.post2
+sentry-forked-django-stubs==4.2.6.post3
 sentry-forked-djangorestframework-stubs==3.14.4.post2
 sentry-forked-djangorestframework-stubs==3.14.4.post2
 sentry-kafka-schemas==0.1.34
 sentry-kafka-schemas==0.1.34
 sentry-redis-tools==0.1.7
 sentry-redis-tools==0.1.7

+ 1 - 1
requirements-dev.txt

@@ -31,7 +31,7 @@ pip-tools>=6.7.0
 packaging>=21.3
 packaging>=21.3
 
 
 # for type checking
 # for type checking
-sentry-forked-django-stubs>=4.2.6.post2
+sentry-forked-django-stubs>=4.2.6.post3
 sentry-forked-djangorestframework-stubs>=3.14.4.post2
 sentry-forked-djangorestframework-stubs>=3.14.4.post2
 lxml-stubs
 lxml-stubs
 msgpack-types>=0.2.0
 msgpack-types>=0.2.0

+ 0 - 44
tests/tools/mypy_helpers/test_plugin.py

@@ -142,50 +142,6 @@ transaction.set_rollback(True, "default")
     assert ret == 0
     assert ret == 0
 
 
 
 
-def test_field_descriptor_hack():
-    code = """\
-from __future__ import annotations
-
-from django.db import models
-
-class M1(models.Model):
-    f: models.Field[int, int] = models.IntegerField()
-
-class C:
-    f: int
-
-def f(inst: C | M1 | M2) -> int:
-    return inst.f
-
-# should also work with field subclasses
-class F(models.Field[int, int]):
-    pass
-
-class M2(models.Model):
-    f = F()
-
-def g(inst: C | M2) -> int:
-    return inst.f
-"""
-
-    # should be an error with default plugins
-    # mypy may fix this at some point hopefully: python/mypy#5570
-    ret, out = call_mypy(code, plugins=[])
-    assert ret
-    assert (
-        out
-        == """\
-<string>:12: error: Incompatible return value type (got "Union[int, Field[int, int]]", expected "int")  [return-value]
-<string>:22: error: Incompatible return value type (got "Union[int, F]", expected "int")  [return-value]
-Found 2 errors in 1 file (checked 1 source file)
-"""
-    )
-
-    # should be fixed with our special plugin
-    ret, _ = call_mypy(code)
-    assert ret == 0
-
-
 @pytest.mark.parametrize(
 @pytest.mark.parametrize(
     "attr",
     "attr",
     (
     (

+ 2 - 36
tools/mypy_helpers/plugin.py

@@ -2,8 +2,8 @@ from __future__ import annotations
 
 
 from typing import Callable
 from typing import Callable
 
 
-from mypy.nodes import ARG_POS, TypeInfo
-from mypy.plugin import ClassDefContext, FunctionSigContext, MethodSigContext, Plugin
+from mypy.nodes import ARG_POS
+from mypy.plugin import ClassDefContext, FunctionSigContext, Plugin
 from mypy.plugins.common import add_attribute_to_class
 from mypy.plugins.common import add_attribute_to_class
 from mypy.types import AnyType, CallableType, FunctionLike, Instance, NoneType, TypeOfAny, UnionType
 from mypy.types import AnyType, CallableType, FunctionLike, Instance, NoneType, TypeOfAny, UnionType
 
 
@@ -49,17 +49,6 @@ _FUNCTION_SIGNATURE_HOOKS = {
 }
 }
 
 
 
 
-def field_descriptor_no_overloads(ctx: MethodSigContext) -> FunctionLike:
-    # ignore the class / non-model instance descriptor overloads
-    signature = ctx.default_signature
-    # replace `def __get__(self, inst: Model, owner: Any) -> _GT:`
-    # with `def __get__(self, inst: Any, owner: Any) -> _GT:`
-    if str(signature.arg_types[0]) == "django.db.models.base.Model":
-        return signature.copy_modified(arg_types=[signature.arg_types[1]] * 2)
-    else:
-        return signature
-
-
 def _adjust_http_request_members(ctx: ClassDefContext) -> None:
 def _adjust_http_request_members(ctx: ClassDefContext) -> None:
     if ctx.cls.name == "HttpRequest":
     if ctx.cls.name == "HttpRequest":
         # added by sentry.api.base and sentry.web.frontend.base
         # added by sentry.api.base and sentry.web.frontend.base
@@ -95,29 +84,6 @@ class SentryMypyPlugin(Plugin):
     ) -> Callable[[FunctionSigContext], FunctionLike] | None:
     ) -> Callable[[FunctionSigContext], FunctionLike] | None:
         return _FUNCTION_SIGNATURE_HOOKS.get(fullname)
         return _FUNCTION_SIGNATURE_HOOKS.get(fullname)
 
 
-    def get_method_signature_hook(
-        self, fullname: str
-    ) -> Callable[[MethodSigContext], FunctionLike] | None:
-        if fullname == "django.db.models.fields.Field":
-            return field_descriptor_no_overloads
-
-        clsname, _, methodname = fullname.rpartition(".")
-        if methodname != "__get__":
-            return None
-
-        clsinfo = self.lookup_fully_qualified(clsname)
-        if clsinfo is None or not isinstance(clsinfo.node, TypeInfo):
-            return None
-
-        fieldinfo = self.lookup_fully_qualified("django.db.models.fields.Field")
-        if fieldinfo is None:
-            return None
-
-        if fieldinfo.node in clsinfo.node.mro:
-            return field_descriptor_no_overloads
-        else:
-            return None
-
     def get_base_class_hook(self, fullname: str) -> Callable[[ClassDefContext], None] | None:
     def get_base_class_hook(self, fullname: str) -> Callable[[ClassDefContext], None] | None:
         # XXX: this is a hack -- I don't know if there's a better callback to modify a class
         # XXX: this is a hack -- I don't know if there's a better callback to modify a class
         if fullname == "io.BytesIO":
         if fullname == "io.BytesIO":