Browse Source

ref: upgrade drf-spectacular (#53438)

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

+ 0 - 1
pyproject.toml

@@ -1002,7 +1002,6 @@ module = [
     "tests.sentry.api.test_event_search",
     "tests.sentry.api.test_invite_helper",
     "tests.sentry.api.test_issue_search",
-    "tests.sentry.apidocs.test_extensions",
     "tests.sentry.auth.test_access",
     "tests.sentry.digests.test_notifications",
     "tests.sentry.eventstore.test_base",

+ 1 - 1
requirements-base.txt

@@ -15,7 +15,7 @@ django-csp>=3.7
 django-pg-zero-downtime-migrations>=0.13
 Django>=3.2.20,<4
 djangorestframework>=3.12.4
-drf-spectacular>=0.22.1
+drf-spectacular>=0.26.3
 email-reply-parser>=0.5.12
 google-api-core>=2.10.1
 google-auth>=2.4.0

+ 1 - 1
requirements-dev-frozen.txt

@@ -49,7 +49,7 @@ djangorestframework==3.12.4
 djangorestframework-stubs==3.14.0
 docker==3.7.0
 docker-pycreds==0.4.0
-drf-spectacular==0.22.1
+drf-spectacular==0.26.3
 email-reply-parser==0.5.12
 exceptiongroup==1.0.0rc9
 execnet==1.9.0

+ 1 - 1
requirements-frozen.txt

@@ -37,7 +37,7 @@ django-crispy-forms==1.14.0
 django-csp==3.7
 django-pg-zero-downtime-migrations==0.13
 djangorestframework==3.12.4
-drf-spectacular==0.22.1
+drf-spectacular==0.26.3
 email-reply-parser==0.5.12
 fastjsonschema==2.16.2
 fido2==0.9.2

+ 5 - 7
src/sentry/apidocs/extensions.py

@@ -4,7 +4,7 @@ from drf_spectacular.extensions import OpenApiAuthenticationExtension, OpenApiSe
 from drf_spectacular.openapi import AutoSchema
 from drf_spectacular.utils import Direction
 
-from sentry.apidocs.spectacular_ports import resolve_type_hint  # type: ignore
+from sentry.apidocs.spectacular_ports import resolve_type_hint
 
 
 class TokenAuthExtension(OpenApiAuthenticationExtension):
@@ -43,9 +43,8 @@ class SentryResponseSerializerExtension(OpenApiSerializerExtension):
     target_class = "sentry.api.serializers.base.Serializer"
     match_subclasses = True
 
-    def get_name(self) -> Optional[str]:
-        name: str = self.target.__name__
-        return name
+    def get_name(self, auto_schema: AutoSchema, direction: Direction) -> Optional[str]:
+        return self.target.__name__
 
     def map_serializer(self, auto_schema: AutoSchema, direction: Direction) -> Any:
         type_hints = get_type_hints(self.target.serialize)
@@ -65,9 +64,8 @@ class SentryInlineResponseSerializerExtension(OpenApiSerializerExtension):
     target_class = "sentry.apidocs.utils._RawSchema"
     match_subclasses = True
 
-    def get_name(self) -> Optional[str]:
-        name: str = self.target.__name__
-        return name
+    def get_name(self, auto_schema: AutoSchema, direction: Direction) -> Optional[str]:
+        return self.target.__name__
 
     def map_serializer(self, auto_schema: AutoSchema, direction: Direction) -> Any:
         return resolve_type_hint(self.target.typeSchema)

+ 3 - 6
src/sentry/apidocs/spectacular_ports.py

@@ -28,9 +28,6 @@
 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-
-# type: ignore
-
 import collections
 import inspect
 import typing
@@ -48,7 +45,7 @@ from drf_spectacular.plumbing import (
     is_basic_type,
 )
 from drf_spectacular.types import OpenApiTypes
-from typing_extensions import _TypedDictMeta
+from typing_extensions import _TypedDictMeta  # type: ignore[attr-defined]
 
 from sentry.apidocs.utils import reload_module_with_type_checking_enabled
 
@@ -103,7 +100,7 @@ def resolve_type_hint(hint) -> Any:
         if get_type_hints(hint):
             properties = {k: resolve_type_hint(v) for k, v in get_type_hints(hint).items()}
         else:
-            properties = {k: build_basic_type(OpenApiTypes.ANY) for k in hint._fields}
+            properties = {k: build_basic_type(OpenApiTypes.ANY) for k in hint._fields}  # type: ignore[attr-defined]
         return build_object_type(properties=properties, required=properties.keys())
     elif origin is list or hint is list:
         return build_array_type(
@@ -158,7 +155,7 @@ def resolve_type_hint(hint) -> Any:
         return schema
     elif origin is collections.abc.Iterable:
         return build_array_type(resolve_type_hint(args[0]))
-    elif isinstance(hint, typing._TypedDictMeta):
+    elif isinstance(hint, typing._TypedDictMeta):  # type: ignore[attr-defined]
         raise UnableToProceedError("Wrong TypedDict class, please use typing_extensions.TypedDict")
     else:
         raise UnableToProceedError(hint)

+ 16 - 11
tests/sentry/apidocs/test_extensions.py

@@ -1,8 +1,9 @@
 from __future__ import annotations
 
-from typing import List, Literal, Optional, Union
+from typing import Any, List, Literal, Mapping, Optional, Union
 
 import pytest
+from drf_spectacular.openapi import AutoSchema
 from drf_spectacular.plumbing import UnableToProceedError
 from drf_spectacular.utils import extend_schema_serializer
 from typing_extensions import TypedDict
@@ -40,23 +41,27 @@ class SerializerWithUnsupportedTypeDict(TypedDict):
 
 
 class BasicSerializer(Serializer):
-    def serialize() -> BasicSerializerResponse:
-        return {"a": 1, "b": "test", "c": True, "d": [1], "e": {"zz": "test"}}
+    def serialize(
+        self, obj: Any, attrs: Mapping[Any, Any], user: Any, **kwargs: Any
+    ) -> BasicSerializerResponse:
+        raise NotImplementedError
 
 
 class FailSerializer(Serializer):
-    def serialize():
-        return {"a": 1, "b": "test", "c": True, "d": [1], "e": {"zz": "test"}}
+    def serialize(self, obj: Any, attrs: Mapping[Any, Any], user: Any, **kwargs: Any):
+        raise NotImplementedError
 
 
 class SerializerWithUnsupportedType(Serializer):
-    def serialize() -> SerializerWithUnsupportedTypeDict:
-        return {"a": [3]}
+    def serialize(
+        self, obj: Any, attrs: Mapping[Any, Any], user: Any, **kwargs: Any
+    ) -> SerializerWithUnsupportedTypeDict:
+        raise NotImplementedError
 
 
 def test_sentry_response_serializer_extension():
     seralizer_extension = SentryResponseSerializerExtension(BasicSerializer)
-    schema = seralizer_extension.map_serializer(None, None)
+    schema = seralizer_extension.map_serializer(AutoSchema(), "response")
     assert schema == {
         "type": "object",
         "properties": {
@@ -78,7 +83,7 @@ def test_sentry_inline_response_serializer_extension():
         "BasicStuff", List[BasicSerializerResponse]
     )
     seralizer_extension = SentryInlineResponseSerializerExtension(inline_serializer)
-    schema = seralizer_extension.map_serializer(None, None)
+    schema = seralizer_extension.map_serializer(AutoSchema(), "response")
 
     assert schema == {
         "type": "array",
@@ -106,10 +111,10 @@ def test_sentry_inline_response_serializer_extension():
 def test_sentry_fails_when_serializer_not_typed():
     seralizer_extension = SentryResponseSerializerExtension(FailSerializer)
     with pytest.raises(TypeError):
-        seralizer_extension.map_serializer(None, None)
+        seralizer_extension.map_serializer(AutoSchema(), "response")
 
 
 def test_sentry_fails_when_serializer_unsupported_type():
     seralizer_extension = SentryResponseSerializerExtension(SerializerWithUnsupportedType)
     with pytest.raises(UnableToProceedError):
-        seralizer_extension.map_serializer(None, None)
+        seralizer_extension.map_serializer(AutoSchema(), "response")