Browse Source

feat(apidocs): type team serializer response (#32029)

Josh Ferge 3 years ago
parent
commit
49b62fb667

+ 2 - 1
mypy.ini

@@ -84,7 +84,8 @@ files = src/sentry/analytics/,
         tests/sentry/utils/appleconnect/,
         src/sentry/apidocs/,
         src/sentry/api/serializers/models/user.py,
-        src/sentry/api/serializers/models/organization.py
+        src/sentry/api/serializers/models/organization.py,
+        src/sentry/api/serializers/types.py
 
 ; Enable all options used with --strict
 warn_unused_configs=True

+ 4 - 2
src/sentry/api/serializers/models/organization.py

@@ -11,6 +11,8 @@ from typing_extensions import TypedDict
 from sentry import features, roles
 from sentry.api.serializers import Serializer, register, serialize
 from sentry.api.serializers.models import UserSerializer
+from sentry.api.serializers.models.project import ProjectSerializerResponse
+from sentry.api.serializers.models.team import TeamSerializerResponse
 from sentry.app import quotas
 from sentry.auth.access import Access
 from sentry.constants import (
@@ -403,8 +405,8 @@ class DetailedOrganizationSerializer(OrganizationSerializer):
 class DetailedOrganizationSerializerWithProjectsAndTeamsResponse(
     DetailedOrganizationSerializerResponse
 ):
-    teams: Any  # TODO replace with team type
-    projects: Any  # TODO replace with project type
+    teams: list[TeamSerializerResponse]
+    projects: list[ProjectSerializerResponse]
 
 
 class DetailedOrganizationSerializerWithProjectsAndTeams(DetailedOrganizationSerializer):

+ 1 - 4
src/sentry/api/serializers/models/organization_member.py

@@ -7,6 +7,7 @@ from sentry import roles
 from sentry.api.serializers import Serializer, register, serialize
 from sentry.api.serializers.models.external_actor import ExternalActorResponse
 from sentry.api.serializers.models.user import UserSerializerResponse
+from sentry.api.serializers.types import SCIMMeta
 from sentry.models import (
     ExternalActor,
     OrganizationMember,
@@ -241,10 +242,6 @@ class SCIMEmail(TypedDict):
     type: str
 
 
-class SCIMMeta(TypedDict):
-    resourceType: str
-
-
 class OrganizationMemberSCIMSerializerOptional(TypedDict, total=False):
     """Sentry doesn't use this field but is expected by SCIM"""
 

+ 33 - 5
src/sentry/api/serializers/models/team.py

@@ -1,5 +1,8 @@
+from __future__ import annotations
+
 from collections import defaultdict
 from typing import (
+    TYPE_CHECKING,
     AbstractSet,
     Any,
     Iterable,
@@ -17,7 +20,7 @@ from typing_extensions import TypedDict
 
 from sentry import roles
 from sentry.api.serializers import Serializer, register, serialize
-from sentry.api.serializers.models.organization_member import SCIMMeta
+from sentry.api.serializers.types import SCIMMeta, SerializedAvatarFields
 from sentry.app import env
 from sentry.auth.superuser import is_active_superuser
 from sentry.models import (
@@ -31,9 +34,16 @@ from sentry.models import (
     TeamAvatar,
     User,
 )
+
+if TYPE_CHECKING:
+    from sentry.api.serializers import (
+        ExternalActorResponse,
+        OrganizationSerializerResponse,
+        ProjectSerializerResponse,
+    )
+
 from sentry.scim.endpoints.constants import SCIM_SCHEMA_GROUP
 from sentry.utils.compat import zip
-from sentry.utils.json import JSONData
 from sentry.utils.query import RangeQuerySetWrapper
 
 
@@ -88,6 +98,24 @@ def get_access_requests(item_list: Sequence[Team], user: User) -> AbstractSet[Te
     return frozenset()
 
 
+class _TeamSerializerResponseOptional(TypedDict, total=False):
+    externalTeams: list[ExternalActorResponse]
+    organization: OrganizationSerializerResponse
+    projects: ProjectSerializerResponse
+
+
+class TeamSerializerResponse(_TeamSerializerResponseOptional):
+    id: str
+    slug: str
+    name: str
+    dateCreated: str
+    isMember: bool
+    hasAccess: bool
+    isPending: bool
+    memberCount: int
+    avatar: SerializedAvatarFields
+
+
 @register(Team)
 class TeamSerializer(Serializer):  # type: ignore
     def __init__(
@@ -176,16 +204,16 @@ class TeamSerializer(Serializer):  # type: ignore
 
     def serialize(
         self, obj: Team, attrs: Mapping[str, Any], user: Any, **kwargs: Any
-    ) -> MutableMapping[str, JSONData]:
+    ) -> TeamSerializerResponse:
         if attrs.get("avatar"):
-            avatar = {
+            avatar: SerializedAvatarFields = {
                 "avatarType": attrs["avatar"].get_avatar_type_display(),
                 "avatarUuid": attrs["avatar"].ident if attrs["avatar"].file_id else None,
             }
         else:
             avatar = {"avatarType": "letter_avatar", "avatarUuid": None}
 
-        result = {
+        result: TeamSerializerResponse = {
             "id": str(obj.id),
             "slug": obj.slug,
             "name": obj.name,

+ 3 - 7
src/sentry/api/serializers/models/user.py

@@ -7,6 +7,7 @@ from typing_extensions import TypedDict
 
 from sentry import experiments
 from sentry.api.serializers import Serializer, register
+from sentry.api.serializers.types import SerializedAvatarFields
 from sentry.app import env
 from sentry.auth.superuser import is_active_superuser
 from sentry.models import (
@@ -59,11 +60,6 @@ class _Identity(TypedDict):
     dateSynced: str
 
 
-class _UserSerializerAvatar(TypedDict):
-    avatarType: str
-    avatarUuid: Optional[str]
-
-
 class _UserOptions(TypedDict):
     theme: str  # TODO: enum/literal for theme options
     language: str
@@ -74,7 +70,7 @@ class _UserOptions(TypedDict):
 
 class UserSerializerResponseOptional(TypedDict, total=False):
     identities: List[_Identity]
-    avatar: _UserSerializerAvatar
+    avatar: SerializedAvatarFields
 
 
 class UserSerializerResponse(UserSerializerResponseOptional):
@@ -180,7 +176,7 @@ class UserSerializer(Serializer):  # type: ignore
             d["flags"] = {"newsletter_consent_prompt": bool(obj.flags.newsletter_consent_prompt)}
 
         if attrs.get("avatar"):
-            avatar: _UserSerializerAvatar = {
+            avatar: SerializedAvatarFields = {
                 "avatarType": attrs["avatar"].get_avatar_type_display(),
                 "avatarUuid": attrs["avatar"].ident if attrs["avatar"].file_id else None,
             }

+ 12 - 0
src/sentry/api/serializers/types.py

@@ -0,0 +1,12 @@
+from typing import Optional
+
+from typing_extensions import TypedDict
+
+
+class SerializedAvatarFields(TypedDict):
+    avatarType: str
+    avatarUuid: Optional[str]
+
+
+class SCIMMeta(TypedDict):
+    resourceType: str