python: Annotate type aliases with TypeAlias.

This is not strictly necessary but it’s clearer and improves mypy’s
error messages.

https://docs.python.org/3/library/typing.html#typing.TypeAlias
https://mypy.readthedocs.io/en/stable/kinds_of_types.html#type-aliases

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2023-08-02 14:53:10 -07:00 committed by Tim Abbott
parent f55711dae3
commit c2c96eb0cf
24 changed files with 81 additions and 52 deletions

View File

@ -8,6 +8,7 @@ from django.conf import settings
from django.db import connection, models from django.db import connection, models
from django.db.models import F from django.db.models import F
from psycopg2.sql import SQL, Composable, Identifier, Literal from psycopg2.sql import SQL, Composable, Identifier, Literal
from typing_extensions import TypeAlias
from analytics.models import ( from analytics.models import (
BaseCount, BaseCount,
@ -346,7 +347,7 @@ def do_drop_single_stat(property: str) -> None:
## DataCollector-level operations ## ## DataCollector-level operations ##
QueryFn = Callable[[Dict[str, Composable]], Composable] QueryFn: TypeAlias = Callable[[Dict[str, Composable]], Composable]
def do_pull_by_sql_query( def do_pull_by_sql_query(

View File

@ -5,6 +5,7 @@ from typing import Any, Dict, List, Mapping, Type, Union
from django.core.files.uploadedfile import UploadedFile from django.core.files.uploadedfile import UploadedFile
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.utils.timezone import now as timezone_now from django.utils.timezone import now as timezone_now
from typing_extensions import TypeAlias
from analytics.lib.counts import COUNT_STATS, CountStat, do_drop_all_analytics_tables from analytics.lib.counts import COUNT_STATS, CountStat, do_drop_all_analytics_tables
from analytics.lib.fixtures import generate_time_series_data from analytics.lib.fixtures import generate_time_series_data
@ -147,7 +148,7 @@ class Command(BaseCommand):
with open(IMAGE_FILE_PATH, "rb") as fp: with open(IMAGE_FILE_PATH, "rb") as fp:
upload_message_attachment_from_request(UploadedFile(fp), shylock, file_size) upload_message_attachment_from_request(UploadedFile(fp), shylock, file_size)
FixtureData = Mapping[Union[str, int, None], List[int]] FixtureData: TypeAlias = Mapping[Union[str, int, None], List[int]]
def insert_fixture_data( def insert_fixture_data(
stat: CountStat, stat: CountStat,

View File

@ -10,6 +10,7 @@ from django.shortcuts import render
from django.utils import translation from django.utils import translation
from django.utils.timezone import now as timezone_now from django.utils.timezone import now as timezone_now
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from typing_extensions import TypeAlias
from analytics.lib.counts import COUNT_STATS, CountStat from analytics.lib.counts import COUNT_STATS, CountStat
from analytics.lib.time_utils import time_range from analytics.lib.time_utils import time_range
@ -242,7 +243,7 @@ def get_chart_data(
remote_realm_id: Optional[int] = None, remote_realm_id: Optional[int] = None,
server: Optional["RemoteZulipServer"] = None, server: Optional["RemoteZulipServer"] = None,
) -> HttpResponse: ) -> HttpResponse:
TableType = Union[ TableType: TypeAlias = Union[
Type["RemoteInstallationCount"], Type["RemoteInstallationCount"],
Type[InstallationCount], Type[InstallationCount],
Type["RemoteRealmCount"], Type["RemoteRealmCount"],

View File

@ -16,6 +16,7 @@ from django.http import HttpRequest, HttpResponse
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.urls import reverse from django.urls import reverse
from django.utils.timezone import now as timezone_now from django.utils.timezone import now as timezone_now
from typing_extensions import TypeAlias
from confirmation import settings as confirmation_settings from confirmation import settings as confirmation_settings
from zerver.lib.types import UnspecifiedValue from zerver.lib.types import UnspecifiedValue
@ -55,7 +56,7 @@ def generate_key() -> str:
return b32encode(secrets.token_bytes(15)).decode().lower() return b32encode(secrets.token_bytes(15)).decode().lower()
ConfirmationObjT = Union[ ConfirmationObjT: TypeAlias = Union[
MultiuseInvite, MultiuseInvite,
PreregistrationRealm, PreregistrationRealm,
PreregistrationUser, PreregistrationUser,

View File

@ -11,6 +11,7 @@ from django.utils.timezone import now as timezone_now
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from django.utils.translation import override as override_language from django.utils.translation import override as override_language
from django_stubs_ext import ValuesQuerySet from django_stubs_ext import ValuesQuerySet
from typing_extensions import TypeAlias
from zerver.actions.default_streams import ( from zerver.actions.default_streams import (
do_remove_default_stream, do_remove_default_stream,
@ -560,7 +561,7 @@ def send_peer_subscriber_events(
send_event_on_commit(realm, event, peer_user_ids) send_event_on_commit(realm, event, peer_user_ids)
SubT = Tuple[List[SubInfo], List[SubInfo]] SubT: TypeAlias = Tuple[List[SubInfo], List[SubInfo]]
def bulk_add_subscriptions( def bulk_add_subscriptions(
@ -729,7 +730,9 @@ def notify_subscriptions_removed(
send_event(realm, event, [user_profile.id]) send_event(realm, event, [user_profile.id])
SubAndRemovedT = Tuple[List[Tuple[UserProfile, Stream]], List[Tuple[UserProfile, Stream]]] SubAndRemovedT: TypeAlias = Tuple[
List[Tuple[UserProfile, Stream]], List[Tuple[UserProfile, Stream]]
]
def send_subscription_remove_events( def send_subscription_remove_events(

View File

@ -7,6 +7,7 @@ import orjson
from django.conf import settings from django.conf import settings
from django.forms.models import model_to_dict from django.forms.models import model_to_dict
from django.utils.timezone import now as timezone_now from django.utils.timezone import now as timezone_now
from typing_extensions import TypeAlias
from zerver.data_import.import_util import ( from zerver.data_import.import_util import (
ZerverFieldsT, ZerverFieldsT,
@ -29,7 +30,7 @@ from zerver.models import Recipient, UserProfile
from zproject.backends import GitHubAuthBackend from zproject.backends import GitHubAuthBackend
# stubs # stubs
GitterDataT = List[Dict[str, Any]] GitterDataT: TypeAlias = List[Dict[str, Any]]
realm_id = 0 realm_id = 0

View File

@ -25,6 +25,7 @@ import orjson
import requests import requests
from django.forms.models import model_to_dict from django.forms.models import model_to_dict
from django.utils.timezone import now as timezone_now from django.utils.timezone import now as timezone_now
from typing_extensions import TypeAlias
from zerver.data_import.sequencer import NEXT_ID from zerver.data_import.sequencer import NEXT_ID
from zerver.lib.avatar_hash import user_avatar_path_from_ids from zerver.lib.avatar_hash import user_avatar_path_from_ids
@ -43,7 +44,7 @@ from zerver.models import (
from zproject.backends import all_implemented_backend_names from zproject.backends import all_implemented_backend_names
# stubs # stubs
ZerverFieldsT = Dict[str, Any] ZerverFieldsT: TypeAlias = Dict[str, Any]
class SubscriberHandler: class SubscriberHandler:

View File

@ -16,6 +16,7 @@ import requests
from django.conf import settings from django.conf import settings
from django.forms.models import model_to_dict from django.forms.models import model_to_dict
from django.utils.timezone import now as timezone_now from django.utils.timezone import now as timezone_now
from typing_extensions import TypeAlias
from zerver.data_import.import_util import ( from zerver.data_import.import_util import (
ZerverFieldsT, ZerverFieldsT,
@ -56,11 +57,11 @@ from zerver.models import (
UserProfile, UserProfile,
) )
SlackToZulipUserIDT = Dict[str, int] SlackToZulipUserIDT: TypeAlias = Dict[str, int]
AddedChannelsT = Dict[str, Tuple[str, int]] AddedChannelsT: TypeAlias = Dict[str, Tuple[str, int]]
AddedMPIMsT = Dict[str, Tuple[str, int]] AddedMPIMsT: TypeAlias = Dict[str, Tuple[str, int]]
DMMembersT = Dict[str, Tuple[str, str]] DMMembersT: TypeAlias = Dict[str, Tuple[str, str]]
SlackToZulipRecipientT = Dict[str, int] SlackToZulipRecipientT: TypeAlias = Dict[str, int]
# Generic type for SlackBotEmail class # Generic type for SlackBotEmail class
SlackBotEmailT = TypeVar("SlackBotEmailT", bound="SlackBotEmail") SlackBotEmailT = TypeVar("SlackBotEmailT", bound="SlackBotEmail")

View File

@ -1,10 +1,12 @@
import re import re
from typing import Any, Dict, List, Optional, Tuple from typing import Any, Dict, List, Optional, Tuple
from typing_extensions import TypeAlias
# stubs # stubs
ZerverFieldsT = Dict[str, Any] ZerverFieldsT: TypeAlias = Dict[str, Any]
SlackToZulipUserIDT = Dict[str, int] SlackToZulipUserIDT: TypeAlias = Dict[str, int]
AddedChannelsT = Dict[str, Tuple[str, int]] AddedChannelsT: TypeAlias = Dict[str, Tuple[str, int]]
# Slack link can be in the format <http://www.foo.com|www.foo.com> and <http://foo.com/> # Slack link can be in the format <http://www.foo.com|www.foo.com> and <http://foo.com/>
LINK_REGEX = r""" LINK_REGEX = r"""

View File

@ -3,10 +3,11 @@ from typing import Any, Callable, Dict, Iterable, List, Mapping, Sequence, TypeV
from psycopg2.extensions import connection, cursor from psycopg2.extensions import connection, cursor
from psycopg2.sql import Composable from psycopg2.sql import Composable
from typing_extensions import TypeAlias
CursorObj = TypeVar("CursorObj", bound=cursor) CursorObj = TypeVar("CursorObj", bound=cursor)
Query = Union[str, bytes, Composable] Query: TypeAlias = Union[str, bytes, Composable]
Params = Union[Sequence[object], Mapping[str, object], None] Params: TypeAlias = Union[Sequence[object], Mapping[str, object], None]
ParamsT = TypeVar("ParamsT") ParamsT = TypeVar("ParamsT")

View File

@ -7,6 +7,7 @@ from typing import Any, Collection, Dict, List, Set, Tuple
from django.conf import settings from django.conf import settings
from django.db import transaction from django.db import transaction
from django.utils.timezone import now as timezone_now from django.utils.timezone import now as timezone_now
from typing_extensions import TypeAlias
from confirmation.models import one_click_unsubscribe_link from confirmation.models import one_click_unsubscribe_link
from zerver.context_processors import common_context from zerver.context_processors import common_context
@ -34,7 +35,7 @@ log_to_file(logger, settings.DIGEST_LOG_PATH)
DIGEST_CUTOFF = 5 DIGEST_CUTOFF = 5
MAX_HOT_TOPICS_TO_BE_INCLUDED_IN_DIGEST = 4 MAX_HOT_TOPICS_TO_BE_INCLUDED_IN_DIGEST = 4
TopicKey = Tuple[int, str] TopicKey: TypeAlias = Tuple[int, str]
class DigestTopic: class DigestTopic:

View File

@ -24,6 +24,7 @@ from django.db.models import Exists, OuterRef, Q
from django.forms.models import model_to_dict from django.forms.models import model_to_dict
from django.utils.timezone import is_naive as timezone_is_naive from django.utils.timezone import is_naive as timezone_is_naive
from mypy_boto3_s3.service_resource import Object from mypy_boto3_s3.service_resource import Object
from typing_extensions import TypeAlias
import zerver.lib.upload import zerver.lib.upload
from analytics.models import RealmCount, StreamCount, UserCount from analytics.models import RealmCount, StreamCount, UserCount
@ -74,17 +75,17 @@ from zerver.models import (
) )
# Custom mypy types follow: # Custom mypy types follow:
Record = Dict[str, Any] Record: TypeAlias = Dict[str, Any]
TableName = str TableName = str
TableData = Dict[TableName, List[Record]] TableData: TypeAlias = Dict[TableName, List[Record]]
Field = str Field = str
Path = str Path = str
Context = Dict[str, Any] Context: TypeAlias = Dict[str, Any]
FilterArgs = Dict[str, Any] FilterArgs: TypeAlias = Dict[str, Any]
IdSource = Tuple[TableName, Field] IdSource: TypeAlias = Tuple[TableName, Field]
SourceFilter = Callable[[Record], bool] SourceFilter: TypeAlias = Callable[[Record], bool]
CustomFetch = Callable[[TableData, Context], None] CustomFetch: TypeAlias = Callable[[TableData, Context], None]
class MessagePartial(TypedDict): class MessagePartial(TypedDict):

View File

@ -7,6 +7,7 @@ from django.urls import URLResolver, path
from django.utils.module_loading import import_string from django.utils.module_loading import import_string
from django.utils.translation import gettext_lazy from django.utils.translation import gettext_lazy
from django_stubs_ext import StrPromise from django_stubs_ext import StrPromise
from typing_extensions import TypeAlias
from zerver.lib.storage import static_path from zerver.lib.storage import static_path
@ -31,7 +32,7 @@ Over time, we expect this registry to grow additional convenience
features for writing and configuring integrations efficiently. features for writing and configuring integrations efficiently.
""" """
OptionValidator = Callable[[str, str], Optional[str]] OptionValidator: TypeAlias = Callable[[str, str], Optional[str]]
META_CATEGORY: Dict[str, StrPromise] = { META_CATEGORY: Dict[str, StrPromise] = {
"meta-integration": gettext_lazy("Integration frameworks"), "meta-integration": gettext_lazy("Integration frameworks"),

View File

@ -47,6 +47,7 @@ from markdown.blockparser import BlockParser
from markdown.extensions import codehilite, nl2br, sane_lists, tables from markdown.extensions import codehilite, nl2br, sane_lists, tables
from soupsieve import escape as css_escape from soupsieve import escape as css_escape
from tlds import tld_set from tlds import tld_set
from typing_extensions import TypeAlias
from zerver.lib import mention from zerver.lib import mention
from zerver.lib.cache import cache_with_key from zerver.lib.cache import cache_with_key
@ -148,7 +149,7 @@ class DbData:
version = 1 version = 1
_T = TypeVar("_T") _T = TypeVar("_T")
ElementStringNone = Union[Element, Optional[str]] ElementStringNone: TypeAlias = Union[Element, Optional[str]]
EMOJI_REGEX = r"(?P<syntax>:[\w\-\+]+:)" EMOJI_REGEX = r"(?P<syntax>:[\w\-\+]+:)"

View File

@ -43,6 +43,7 @@ from sqlalchemy.sql import (
) )
from sqlalchemy.sql.selectable import SelectBase from sqlalchemy.sql.selectable import SelectBase
from sqlalchemy.types import ARRAY, Boolean, Integer, Text from sqlalchemy.types import ARRAY, Boolean, Integer, Text
from typing_extensions import TypeAlias
from zerver.lib.addressee import get_user_profiles, get_user_profiles_by_ids from zerver.lib.addressee import get_user_profiles, get_user_profiles_by_ids
from zerver.lib.exceptions import ErrorCode, JsonableError from zerver.lib.exceptions import ErrorCode, JsonableError
@ -207,9 +208,9 @@ class BadNarrowOperatorError(JsonableError):
return _("Invalid narrow operator: {desc}") return _("Invalid narrow operator: {desc}")
ConditionTransform = Callable[[ClauseElement], ClauseElement] ConditionTransform: TypeAlias = Callable[[ClauseElement], ClauseElement]
OptionalNarrowListT = Optional[List[Dict[str, Any]]] OptionalNarrowListT: TypeAlias = Optional[List[Dict[str, Any]]]
# These delimiters will not appear in rendered messages or HTML-escaped topics. # These delimiters will not appear in rendered messages or HTML-escaped topics.
TS_START = "<ts-match>" TS_START = "<ts-match>"

View File

@ -17,6 +17,7 @@ from django.db.models import F, Q
from django.utils.timezone import now as timezone_now from django.utils.timezone import now as timezone_now
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from django.utils.translation import override as override_language from django.utils.translation import override as override_language
from typing_extensions import TypeAlias
from zerver.lib.avatar import absolute_avatar_url from zerver.lib.avatar import absolute_avatar_url
from zerver.lib.exceptions import JsonableError from zerver.lib.exceptions import JsonableError
@ -47,7 +48,7 @@ logger = logging.getLogger(__name__)
if settings.ZILENCER_ENABLED: if settings.ZILENCER_ENABLED:
from zilencer.models import RemotePushDeviceToken, RemoteZulipServer from zilencer.models import RemotePushDeviceToken, RemoteZulipServer
DeviceToken = Union[PushDeviceToken, "RemotePushDeviceToken"] DeviceToken: TypeAlias = Union[PushDeviceToken, "RemotePushDeviceToken"]
# We store the token as b64, but apns-client wants hex strings # We store the token as b64, but apns-client wants hex strings

View File

@ -17,12 +17,13 @@ from pika.adapters.blocking_connection import BlockingChannel
from pika.channel import Channel from pika.channel import Channel
from pika.spec import Basic from pika.spec import Basic
from tornado import ioloop from tornado import ioloop
from typing_extensions import TypeAlias
from zerver.lib.utils import assert_is_not_none from zerver.lib.utils import assert_is_not_none
MAX_REQUEST_RETRIES = 3 MAX_REQUEST_RETRIES = 3
ChannelT = TypeVar("ChannelT", Channel, BlockingChannel) ChannelT = TypeVar("ChannelT", Channel, BlockingChannel)
Consumer = Callable[[ChannelT, Basic.Deliver, pika.BasicProperties, bytes], None] Consumer: TypeAlias = Callable[[ChannelT, Basic.Deliver, pika.BasicProperties, bytes], None]
# This simple queuing library doesn't expose much of the power of # This simple queuing library doesn't expose much of the power of

View File

@ -14,6 +14,7 @@ from django.db import ProgrammingError, connections
from django.test import runner as django_runner from django.test import runner as django_runner
from django.test.runner import DiscoverRunner from django.test.runner import DiscoverRunner
from django.test.signals import template_rendered from django.test.signals import template_rendered
from typing_extensions import TypeAlias
from scripts.lib.zulip_tools import ( from scripts.lib.zulip_tools import (
TEMPLATE_DATABASE_DIR, TEMPLATE_DATABASE_DIR,
@ -103,8 +104,8 @@ def process_instrumented_calls(func: Callable[[Dict[str, Any]], None]) -> None:
func(call) func(call)
SerializedSubsuite = Tuple[Type[TestSuite], List[str]] SerializedSubsuite: TypeAlias = Tuple[Type[TestSuite], List[str]]
SubsuiteArgs = Tuple[Type["RemoteTestRunner"], int, SerializedSubsuite, bool, bool] SubsuiteArgs: TypeAlias = Tuple[Type["RemoteTestRunner"], int, SerializedSubsuite, bool, bool]
def run_subsuite(args: SubsuiteArgs) -> Tuple[int, Any]: def run_subsuite(args: SubsuiteArgs) -> Tuple[int, Any]:

View File

@ -3,17 +3,17 @@ from dataclasses import dataclass
from typing import Any, Callable, Dict, List, Optional, Tuple, TypedDict, TypeVar, Union from typing import Any, Callable, Dict, List, Optional, Tuple, TypedDict, TypeVar, Union
from django_stubs_ext import StrPromise from django_stubs_ext import StrPromise
from typing_extensions import NotRequired from typing_extensions import NotRequired, TypeAlias
# See zerver/lib/validator.py for more details of Validators, # See zerver/lib/validator.py for more details of Validators,
# including many examples # including many examples
ResultT = TypeVar("ResultT") ResultT = TypeVar("ResultT")
Validator = Callable[[str, object], ResultT] Validator: TypeAlias = Callable[[str, object], ResultT]
ExtendedValidator = Callable[[str, str, object], str] ExtendedValidator: TypeAlias = Callable[[str, str, object], str]
RealmUserValidator = Callable[[int, object, bool], List[int]] RealmUserValidator: TypeAlias = Callable[[int, object, bool], List[int]]
ProfileDataElementValue = Union[str, List[int]] ProfileDataElementValue: TypeAlias = Union[str, List[int]]
class ProfileDataElementBase(TypedDict, total=False): class ProfileDataElementBase(TypedDict, total=False):
@ -36,13 +36,17 @@ class ProfileDataElementUpdateDict(TypedDict):
value: ProfileDataElementValue value: ProfileDataElementValue
ProfileData = List[ProfileDataElement] ProfileData: TypeAlias = List[ProfileDataElement]
FieldElement = Tuple[int, StrPromise, Validator[ProfileDataElementValue], Callable[[Any], Any], str] FieldElement: TypeAlias = Tuple[
ExtendedFieldElement = Tuple[int, StrPromise, ExtendedValidator, Callable[[Any], Any], str] int, StrPromise, Validator[ProfileDataElementValue], Callable[[Any], Any], str
UserFieldElement = Tuple[int, StrPromise, RealmUserValidator, Callable[[Any], Any], str] ]
ExtendedFieldElement: TypeAlias = Tuple[
int, StrPromise, ExtendedValidator, Callable[[Any], Any], str
]
UserFieldElement: TypeAlias = Tuple[int, StrPromise, RealmUserValidator, Callable[[Any], Any], str]
ProfileFieldData = Dict[str, Union[Dict[str, str], str]] ProfileFieldData: TypeAlias = Dict[str, Union[Dict[str, str], str]]
class UserDisplayRecipient(TypedDict): class UserDisplayRecipient(TypedDict):
@ -52,7 +56,7 @@ class UserDisplayRecipient(TypedDict):
is_mirror_dummy: bool is_mirror_dummy: bool
DisplayRecipientT = Union[str, List[UserDisplayRecipient]] DisplayRecipientT: TypeAlias = Union[str, List[UserDisplayRecipient]]
class LinkifierDict(TypedDict): class LinkifierDict(TypedDict):

View File

@ -15,6 +15,7 @@ import time_machine
from django.conf import settings from django.conf import settings
from django.db.utils import IntegrityError from django.db.utils import IntegrityError
from django.test import override_settings from django.test import override_settings
from typing_extensions import TypeAlias
from zerver.lib.email_mirror import RateLimitedRealmMirror from zerver.lib.email_mirror import RateLimitedRealmMirror
from zerver.lib.email_mirror_helpers import encode_email_address from zerver.lib.email_mirror_helpers import encode_email_address
@ -43,7 +44,7 @@ from zerver.worker.queue_processors import (
get_active_worker_queues, get_active_worker_queues,
) )
Event = Dict[str, Any] Event: TypeAlias = Dict[str, Any]
class FakeClient: class FakeClient:

View File

@ -27,7 +27,7 @@ from django.views.decorators.http import require_safe
from social_django.utils import load_backend, load_strategy from social_django.utils import load_backend, load_strategy
from two_factor.forms import BackupTokenForm from two_factor.forms import BackupTokenForm
from two_factor.views import LoginView as BaseTwoFactorLoginView from two_factor.views import LoginView as BaseTwoFactorLoginView
from typing_extensions import Concatenate, ParamSpec from typing_extensions import Concatenate, ParamSpec, TypeAlias
from confirmation.models import ( from confirmation.models import (
Confirmation, Confirmation,
@ -103,7 +103,7 @@ if TYPE_CHECKING:
from django.http.request import _ImmutableQueryDict from django.http.request import _ImmutableQueryDict
ParamT = ParamSpec("ParamT") ParamT = ParamSpec("ParamT")
ExtraContext = Optional[Dict[str, Any]] ExtraContext: TypeAlias = Optional[Dict[str, Any]]
EXPIRABLE_SESSION_VAR_DEFAULT_EXPIRY_SECS = 3600 EXPIRABLE_SESSION_VAR_DEFAULT_EXPIRY_SECS = 3600

View File

@ -4,6 +4,7 @@ from django.conf import settings
from django.contrib.auth.models import AnonymousUser from django.contrib.auth.models import AnonymousUser
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from typing_extensions import TypeAlias
from zerver.context_processors import get_valid_realm_from_request from zerver.context_processors import get_valid_realm_from_request
from zerver.lib.compatibility import is_pronouns_field_type_supported from zerver.lib.compatibility import is_pronouns_field_type_supported
@ -34,7 +35,7 @@ def _default_narrow(
return narrow return narrow
NarrowT = Sequence[Sequence[str]] NarrowT: TypeAlias = Sequence[Sequence[str]]
@has_request_variables @has_request_variables

View File

@ -2,6 +2,7 @@ from email.headerregistry import Address
from typing import Dict, Union from typing import Dict, Union
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
from typing_extensions import TypeAlias
from zerver.decorator import webhook_view from zerver.decorator import webhook_view
from zerver.lib.exceptions import UnsupportedWebhookEventTypeError from zerver.lib.exceptions import UnsupportedWebhookEventTypeError
@ -11,7 +12,7 @@ from zerver.lib.validator import WildValue, check_int, check_none_or, check_stri
from zerver.lib.webhooks.common import check_send_webhook_message from zerver.lib.webhooks.common import check_send_webhook_message
from zerver.models import UserProfile from zerver.models import UserProfile
FormatDictType = Dict[str, Union[str, int]] FormatDictType: TypeAlias = Dict[str, Union[str, int]]
PAGER_DUTY_EVENT_NAMES = { PAGER_DUTY_EVENT_NAMES = {
"incident.trigger": "triggered", "incident.trigger": "triggered",

View File

@ -9,6 +9,7 @@ should be in bold.
from typing import Dict, List, Optional, Tuple, Union from typing import Dict, List, Optional, Tuple, Union
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
from typing_extensions import TypeAlias
from zerver.decorator import webhook_view from zerver.decorator import webhook_view
from zerver.lib.request import REQ, has_request_variables from zerver.lib.request import REQ, has_request_variables
@ -17,8 +18,8 @@ from zerver.lib.validator import WildValue, check_bool, check_none_or, check_str
from zerver.lib.webhooks.common import check_send_webhook_message from zerver.lib.webhooks.common import check_send_webhook_message
from zerver.models import UserProfile from zerver.models import UserProfile
EventType = Dict[str, Union[str, Dict[str, Optional[Union[str, bool]]]]] EventType: TypeAlias = Dict[str, Union[str, Dict[str, Optional[Union[str, bool]]]]]
ReturnType = Tuple[WildValue, WildValue] ReturnType: TypeAlias = Tuple[WildValue, WildValue]
@webhook_view("Taiga") @webhook_view("Taiga")