Просмотр исходного кода

ref: fix some mypy issues in __init__.py files (#57242)

<!-- Describe your PR here. -->
anthony sottile 1 год назад
Родитель
Сommit
49b80adaaa

+ 0 - 6
pyproject.toml

@@ -314,7 +314,6 @@ module = [
     "sentry.api.issue_search",
     "sentry.api.paginator",
     "sentry.api.permissions",
-    "sentry.api.serializers.models",
     "sentry.api.serializers.models.alert_rule",
     "sentry.api.serializers.models.auth_provider",
     "sentry.api.serializers.models.authenticator",
@@ -392,7 +391,6 @@ module = [
     "sentry.grouping.strategies.hierarchical",
     "sentry.grouping.strategies.legacy",
     "sentry.grouping.strategies.newstyle",
-    "sentry.identity",
     "sentry.identity.bitbucket.provider",
     "sentry.identity.github_enterprise.provider",
     "sentry.identity.gitlab.provider",
@@ -547,7 +545,6 @@ module = [
     "sentry.notifications.notifications.activity.release",
     "sentry.notifications.notifications.integration_nudge",
     "sentry.notifications.notifications.rules",
-    "sentry.notifications.utils",
     "sentry.notifications.utils.avatar",
     "sentry.onboarding_tasks.backends.organization_onboarding_task",
     "sentry.onboarding_tasks.base",
@@ -575,7 +572,6 @@ module = [
     "sentry.projectoptions.defaults",
     "sentry.queue.command",
     "sentry.quotas.redis",
-    "sentry.receivers.outbox",
     "sentry.receivers.outbox.control",
     "sentry.receivers.releases",
     "sentry.receivers.sentry_apps",
@@ -587,7 +583,6 @@ module = [
     "sentry.replays.lib.query",
     "sentry.replays.query",
     "sentry.reprocessing2",
-    "sentry.roles",
     "sentry.rules.actions.integrations.base",
     "sentry.rules.actions.integrations.create_ticket.form",
     "sentry.rules.actions.integrations.create_ticket.utils",
@@ -641,7 +636,6 @@ module = [
     "sentry.similarity.features",
     "sentry.snuba.discover",
     "sentry.snuba.issue_platform",
-    "sentry.snuba.metrics",
     "sentry.snuba.metrics.datasource",
     "sentry.snuba.metrics.fields.base",
     "sentry.snuba.metrics.query_builder",

+ 1 - 1
src/sentry/api/serializers/models/__init__.py

@@ -28,7 +28,7 @@ from .external_actor import *  # noqa: F401,F403
 from .filechange import *  # noqa: F401,F403
 from .group import *  # noqa: F401,F403
 from .group_stream import *  # noqa: F401,F403
-from .grouprelease import *  # noqa: F401,F403
+from .grouprelease import GroupReleaseSerializer, GroupReleaseWithStatsSerializer  # noqa: F401,F403
 from .groupseen import *  # noqa: F401,F403
 from .grouptombstone import *  # noqa: F401,F403
 from .identity import *  # noqa: F401,F403

+ 3 - 2
src/sentry/conf/server.py

@@ -16,6 +16,7 @@ from urllib.parse import urlparse
 
 import sentry
 from sentry.conf.types.consumer_definition import ConsumerDefinition
+from sentry.conf.types.role_dict import RoleDict
 from sentry.conf.types.topic_definition import TopicDefinition
 from sentry.utils import json  # NOQA (used in getsentry config)
 from sentry.utils.celery import crontab_with_minute_jitter
@@ -2327,7 +2328,7 @@ SENTRY_DEFAULT_ROLE = "member"
 # they're presented in the UI. This is primarily important in that a member
 # that is earlier in the chain cannot manage the settings of a member later
 # in the chain (they still require the appropriate scope).
-SENTRY_ROLES = (
+SENTRY_ROLES: tuple[RoleDict, ...] = (
     {
         "id": "member",
         "name": "Member",
@@ -2438,7 +2439,7 @@ SENTRY_ROLES = (
     },
 )
 
-SENTRY_TEAM_ROLES = (
+SENTRY_TEAM_ROLES: tuple[RoleDict, ...] = (
     {
         "id": "contributor",
         "name": "Contributor",

+ 13 - 0
src/sentry/conf/types/role_dict.py

@@ -0,0 +1,13 @@
+from __future__ import annotations
+
+from typing_extensions import NotRequired, TypedDict
+
+
+class RoleDict(TypedDict):
+    id: str
+    name: str
+    desc: str
+    scopes: set[str]
+    is_retired: NotRequired[bool]
+    is_global: NotRequired[bool]
+    is_minimum_role_for: NotRequired[str]

+ 3 - 3
src/sentry/identity/__init__.py

@@ -1,15 +1,15 @@
 from .base import *  # NOQA
 from .bitbucket import *  # NOQA
 from .discord import *  # NOQA
-from .github import *  # NOQA
-from .github_enterprise import *  # NOQA
+from .github import GitHubIdentityProvider
+from .github_enterprise import GitHubEnterpriseIdentityProvider
 from .gitlab import *  # NOQA
 from .google import *  # NOQA
 from .manager import IdentityManager
 from .oauth2 import *  # NOQA
 from .slack import *  # NOQA
 from .vercel import *  # NOQA
-from .vsts import *  # NOQA
+from .vsts import VSTSIdentityProvider
 from .vsts_extension import *  # NOQA
 
 default_manager = IdentityManager()

+ 18 - 28
src/sentry/notifications/utils/__init__.py

@@ -55,7 +55,7 @@ from sentry.services.hybrid_cloud.user import RpcUser
 from sentry.services.hybrid_cloud.util import region_silo_function
 from sentry.utils.committers import get_serialized_event_file_committers
 from sentry.utils.performance_issues.base import get_url_from_span
-from sentry.utils.performance_issues.performance_detection import PerformanceProblem
+from sentry.utils.performance_issues.performance_problem import PerformanceProblem
 from sentry.web.helpers import render_to_string
 
 if TYPE_CHECKING:
@@ -191,7 +191,7 @@ def get_group_settings_link(
     notification_uuid: str | None = None,
     **kwargs: Any,
 ) -> str:
-    alert_rule_id: int | None = rule_details[0].id if rule_details and rule_details[0].id else None
+    alert_rule_id = rule_details[0].id if rule_details and rule_details[0].id else None
     extra_params = ""
     if alert_rule_id:
         extra_params = get_email_link_extra_params(
@@ -284,7 +284,7 @@ def has_integrations(organization: Organization, project: Project) -> bool:
     return bool(project_plugins or organization_integrations)
 
 
-def is_alert_rule_integration(provider: IntegrationProvider) -> bool:
+def is_alert_rule_integration(provider: type[IntegrationProvider]) -> bool:
     return any(
         feature == (IntegrationFeatures.ALERT_RULE or IntegrationFeatures.ENTERPRISE_ALERT_RULE)
         for feature in provider.features
@@ -296,9 +296,7 @@ def has_alert_integration(project: Project) -> bool:
 
     # check integrations
     provider_keys = [
-        cast(str, provider.key)
-        for provider in integrations.all()
-        if is_alert_rule_integration(provider)
+        provider.key for provider in integrations.all() if is_alert_rule_integration(provider)
     ]
     if integration_service.get_integrations(organization_id=org.id, providers=provider_keys):
         return True
@@ -364,7 +362,7 @@ def get_parent_and_repeating_spans(
     return (parent_span, repeating_spans)
 
 
-def occurrence_perf_to_email_html(context: Any) -> Any:
+def occurrence_perf_to_email_html(context: Any) -> str:
     """Generate the email HTML for an occurrence-backed performance issue alert"""
     return render_to_string("sentry/emails/transactions.html", context)
 
@@ -385,50 +383,42 @@ def get_spans(
     return spans
 
 
-def get_transaction_data(event: Event) -> Any:
+def get_transaction_data(event: GroupEvent) -> str:
     """Get data about a transaction to populate alert emails."""
-    evidence_data = event.occurrence.evidence_data
-    if not evidence_data:
+    if event.occurrence is None or not event.occurrence.evidence_data:
         return ""
-
-    context = evidence_data
-    return occurrence_perf_to_email_html(context)
+    return occurrence_perf_to_email_html(event.occurrence.evidence_data)
 
 
 def get_generic_data(event: GroupEvent) -> Any:
     """Get data about a generic issue type to populate alert emails."""
-    generic_evidence = event.occurrence.evidence_display
-
-    if not generic_evidence:
+    if event.occurrence is None or not event.occurrence.evidence_display:
         return ""
 
-    context = {}
-    for row in generic_evidence:
-        context[row.name] = row.value
-
+    context = {row.name: row.value for row in event.occurrence.evidence_display}
     return generic_email_html(context)
 
 
-def generic_email_html(context: Any) -> Any:
+def generic_email_html(context: Any) -> str:
     """Format issue evidence into a (stringified) HTML table for emails"""
     return render_to_string("sentry/emails/generic_table.html", {"data": context})
 
 
-def get_performance_issue_alert_subtitle(event: Event) -> str:
+def get_performance_issue_alert_subtitle(event: GroupEvent) -> str:
     """Generate the issue alert subtitle for performance issues"""
-    return cast(
-        str, event.occurrence.evidence_data.get("repeating_spans_compact", "").replace("`", '"')
-    )
+    if event.occurrence is None:
+        return ""
+    return event.occurrence.evidence_data.get("repeating_spans_compact", "").replace("`", '"')
 
 
 def get_notification_group_title(
     group: Group, event: Event | GroupEvent, max_length: int = 255, **kwargs: str
 ) -> str:
     if isinstance(event, GroupEvent) and event.occurrence is not None:
-        issue_title: str = event.occurrence.issue_title
+        issue_title = event.occurrence.issue_title
         return issue_title
     else:
-        event_title: str = event.title
+        event_title = event.title
         return event_title
 
 
@@ -637,7 +627,7 @@ class ConsecutiveDBQueriesProblemContext(PerformanceProblemContext):
         this is where thresholds come in
         """
         independent_spans = [self._find_span_by_id(id) for id in self.problem.offender_span_ids]
-        consecutive_spans = [self._find_span_by_id(id) for id in self.problem.cause_span_ids]
+        consecutive_spans = [self._find_span_by_id(id) for id in self.problem.cause_span_ids or ()]
         total_duration = self._sum_span_duration(consecutive_spans)
 
         max_independent_span_duration = max(

+ 5 - 8
src/sentry/receivers/outbox/__init__.py

@@ -49,7 +49,9 @@ See https://www.notion.so/sentry/Async-cross-region-updates-outbox-9330293c8d2f4
 """
 from __future__ import annotations
 
-from typing import Any, Protocol, Type, TypeVar
+from typing import TypeVar
+
+from django.db import models
 
 from sentry.services.hybrid_cloud.tombstone import (
     RpcTombstone,
@@ -58,16 +60,11 @@ from sentry.services.hybrid_cloud.tombstone import (
 )
 from sentry.silo import SiloMode
 
-
-class ModelLike(Protocol):
-    objects: Any
-
-
-T = TypeVar("T", bound=ModelLike)
+T = TypeVar("T", bound=models.Model)
 
 
 def maybe_process_tombstone(
-    model: Type[T], object_identifier: int, region_name: str | None = None
+    model: type[T], object_identifier: int, region_name: str | None = None
 ) -> T | None:
     if instance := model.objects.filter(id=object_identifier).last():
         return instance

+ 1 - 2
src/sentry/snuba/metrics/query.py

@@ -125,8 +125,7 @@ class MetricConditionField:
     rhs: Union[int, float, str]
 
 
-Tag = str
-Groupable = Union[Tag, Literal["project_id"]]
+Groupable = Union[str, Literal["project_id"]]
 
 
 class MetricsQueryValidationRunner:

+ 2 - 2
src/sentry/snuba/metrics/query_builder.py

@@ -69,7 +69,7 @@ from sentry.snuba.metrics.query import (
 )
 from sentry.snuba.metrics.query import MetricOrderByField
 from sentry.snuba.metrics.query import MetricOrderByField as MetricsOrderBy
-from sentry.snuba.metrics.query import MetricsQuery, Tag
+from sentry.snuba.metrics.query import MetricsQuery
 from sentry.snuba.metrics.utils import (
     DATASET_COLUMNS,
     FIELD_ALIAS_MAPPINGS,
@@ -805,7 +805,7 @@ class SnubaQueryBuilder:
                 # The support for tags in the order by is disabled for now because there is no need to have it. If the
                 # need arise, we will implement it.
                 if is_group_by:
-                    assert isinstance(metric_action_by_field.field, Tag)
+                    assert isinstance(metric_action_by_field.field, str)
                     column_name = resolve_tag_key(use_case_id, org_id, metric_action_by_field.field)
                 else:
                     raise NotImplementedError(