ruff: Fix UP007 Use X | Y for type annotations.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg
2024-07-11 17:30:23 -07:00
committed by Tim Abbott
parent e08a24e47f
commit 531b34cb4c
355 changed files with 2759 additions and 3029 deletions

View File

@@ -2,7 +2,7 @@ import logging
import time
from collections import OrderedDict, defaultdict
from datetime import datetime, timedelta
from typing import Callable, Optional, Sequence, Union
from typing import Callable, Sequence, Union
from django.conf import settings
from django.db import connection, models
@@ -55,7 +55,7 @@ class CountStat:
property: str,
data_collector: "DataCollector",
frequency: str,
interval: Optional[timedelta] = None,
interval: timedelta | None = None,
) -> None:
self.property = property
self.data_collector = data_collector
@@ -72,7 +72,7 @@ class CountStat:
def __repr__(self) -> str:
return f"<CountStat: {self.property}>"
def last_successful_fill(self) -> Optional[datetime]:
def last_successful_fill(self) -> datetime | None:
fillstate = FillState.objects.filter(property=self.property).first()
if fillstate is None:
return None
@@ -92,7 +92,7 @@ class DependentCountStat(CountStat):
property: str,
data_collector: "DataCollector",
frequency: str,
interval: Optional[timedelta] = None,
interval: timedelta | None = None,
dependencies: Sequence[str] = [],
) -> None:
CountStat.__init__(self, property, data_collector, frequency, interval=interval)
@@ -103,7 +103,7 @@ class DataCollector:
def __init__(
self,
output_table: type[BaseCount],
pull_function: Optional[Callable[[str, datetime, datetime, Optional[Realm]], int]],
pull_function: Callable[[str, datetime, datetime, Realm | None], int] | None,
) -> None:
self.output_table = output_table
self.pull_function = pull_function
@@ -115,9 +115,7 @@ class DataCollector:
## CountStat-level operations ##
def process_count_stat(
stat: CountStat, fill_to_time: datetime, realm: Optional[Realm] = None
) -> None:
def process_count_stat(stat: CountStat, fill_to_time: datetime, realm: Realm | None = None) -> None:
# TODO: The realm argument is not yet supported, in that we don't
# have a solution for how to update FillState if it is passed. It
# exists solely as partial plumbing for when we do fully implement
@@ -180,7 +178,7 @@ def do_update_fill_state(fill_state: FillState, end_time: datetime, state: int)
# We assume end_time is valid (e.g. is on a day or hour boundary as appropriate)
# and is time-zone-aware. It is the caller's responsibility to enforce this!
def do_fill_count_stat_at_hour(
stat: CountStat, end_time: datetime, realm: Optional[Realm] = None
stat: CountStat, end_time: datetime, realm: Realm | None = None
) -> None:
start_time = end_time - stat.interval
if not isinstance(stat, LoggingCountStat):
@@ -209,7 +207,7 @@ def do_delete_counts_at_hour(stat: CountStat, end_time: datetime) -> None:
def do_aggregate_to_summary_table(
stat: CountStat, end_time: datetime, realm: Optional[Realm] = None
stat: CountStat, end_time: datetime, realm: Realm | None = None
) -> None:
cursor = connection.cursor()
@@ -303,7 +301,7 @@ def do_aggregate_to_summary_table(
def do_increment_logging_stat(
model_object_for_bucket: Union[Realm, UserProfile, Stream, "RemoteRealm", "RemoteZulipServer"],
stat: CountStat,
subgroup: Optional[Union[str, int, bool]],
subgroup: str | int | bool | None,
event_time: datetime,
increment: int = 1,
) -> None:
@@ -311,7 +309,7 @@ def do_increment_logging_stat(
return
table = stat.data_collector.output_table
id_args: dict[str, Union[int, None]] = {}
id_args: dict[str, int | None] = {}
conflict_args: list[str] = []
if table == RealmCount:
assert isinstance(model_object_for_bucket, Realm)
@@ -433,7 +431,7 @@ def do_pull_by_sql_query(
start_time: datetime,
end_time: datetime,
query: QueryFn,
group_by: Optional[tuple[type[models.Model], str]],
group_by: tuple[type[models.Model], str] | None,
) -> int:
if group_by is None:
subgroup: Composable = SQL("NULL")
@@ -469,10 +467,10 @@ def do_pull_by_sql_query(
def sql_data_collector(
output_table: type[BaseCount],
query: QueryFn,
group_by: Optional[tuple[type[models.Model], str]],
group_by: tuple[type[models.Model], str] | None,
) -> DataCollector:
def pull_function(
property: str, start_time: datetime, end_time: datetime, realm: Optional[Realm] = None
property: str, start_time: datetime, end_time: datetime, realm: Realm | None = None
) -> int:
# The pull function type needs to accept a Realm argument
# because the 'minutes_active::day' CountStat uses
@@ -485,7 +483,7 @@ def sql_data_collector(
return DataCollector(output_table, pull_function)
def count_upload_space_used_by_realm_query(realm: Optional[Realm]) -> QueryFn:
def count_upload_space_used_by_realm_query(realm: Realm | None) -> QueryFn:
if realm is None:
realm_clause: Composable = SQL("")
else:
@@ -520,7 +518,7 @@ def count_upload_space_used_by_realm_query(realm: Optional[Realm]) -> QueryFn:
def do_pull_minutes_active(
property: str, start_time: datetime, end_time: datetime, realm: Optional[Realm] = None
property: str, start_time: datetime, end_time: datetime, realm: Realm | None = None
) -> int:
user_activity_intervals = (
UserActivityInterval.objects.filter(
@@ -555,7 +553,7 @@ def do_pull_minutes_active(
return len(rows)
def count_message_by_user_query(realm: Optional[Realm]) -> QueryFn:
def count_message_by_user_query(realm: Realm | None) -> QueryFn:
if realm is None:
realm_clause: Composable = SQL("")
else:
@@ -588,7 +586,7 @@ def count_message_by_user_query(realm: Optional[Realm]) -> QueryFn:
# Note: ignores the group_by / group_by_clause.
def count_message_type_by_user_query(realm: Optional[Realm]) -> QueryFn:
def count_message_type_by_user_query(realm: Realm | None) -> QueryFn:
if realm is None:
realm_clause: Composable = SQL("")
else:
@@ -643,7 +641,7 @@ def count_message_type_by_user_query(realm: Optional[Realm]) -> QueryFn:
# use this also subgroup on UserProfile.is_bot. If in the future there is a
# stat that counts messages by stream and doesn't need the UserProfile
# table, consider writing a new query for efficiency.
def count_message_by_stream_query(realm: Optional[Realm]) -> QueryFn:
def count_message_by_stream_query(realm: Realm | None) -> QueryFn:
if realm is None:
realm_clause: Composable = SQL("")
else:
@@ -683,7 +681,7 @@ def count_message_by_stream_query(realm: Optional[Realm]) -> QueryFn:
# same event_time and event_type in [RealmAuditLog.USER_CREATED,
# USER_DEACTIVATED, etc]. In particular, it's important to ensure
# that migrations don't cause that to happen.
def check_realmauditlog_by_user_query(realm: Optional[Realm]) -> QueryFn:
def check_realmauditlog_by_user_query(realm: Realm | None) -> QueryFn:
if realm is None:
realm_clause: Composable = SQL("")
else:
@@ -722,7 +720,7 @@ def check_realmauditlog_by_user_query(realm: Optional[Realm]) -> QueryFn:
)
def check_useractivityinterval_by_user_query(realm: Optional[Realm]) -> QueryFn:
def check_useractivityinterval_by_user_query(realm: Realm | None) -> QueryFn:
if realm is None:
realm_clause: Composable = SQL("")
else:
@@ -746,7 +744,7 @@ def check_useractivityinterval_by_user_query(realm: Optional[Realm]) -> QueryFn:
).format(**kwargs, realm_clause=realm_clause)
def count_realm_active_humans_query(realm: Optional[Realm]) -> QueryFn:
def count_realm_active_humans_query(realm: Realm | None) -> QueryFn:
if realm is None:
realm_clause: Composable = SQL("")
else:
@@ -817,7 +815,7 @@ count_stream_by_realm_query = lambda kwargs: SQL(
).format(**kwargs)
def get_count_stats(realm: Optional[Realm] = None) -> dict[str, CountStat]:
def get_count_stats(realm: Realm | None = None) -> dict[str, CountStat]:
## CountStat declarations ##
count_stats_ = [

View File

@@ -1,5 +1,4 @@
from datetime import datetime, timedelta
from typing import Optional
from analytics.lib.counts import CountStat
from zerver.lib.timestamp import floor_to_day, floor_to_hour, verify_UTC
@@ -10,7 +9,7 @@ from zerver.lib.timestamp import floor_to_day, floor_to_hour, verify_UTC
# So informally, time_range(Sep 20, Sep 22, day, None) returns [Sep 20, Sep 21, Sep 22],
# and time_range(Sep 20, Sep 22, day, 5) returns [Sep 18, Sep 19, Sep 20, Sep 21, Sep 22]
def time_range(
start: datetime, end: datetime, frequency: str, min_length: Optional[int]
start: datetime, end: datetime, frequency: str, min_length: int | None
) -> list[datetime]:
verify_UTC(start)
verify_UTC(end)

View File

@@ -1,5 +1,5 @@
from datetime import timedelta
from typing import Any, Mapping, Union
from typing import Any, Mapping
from django.core.files.uploadedfile import UploadedFile
from django.utils.timezone import now as timezone_now
@@ -147,7 +147,7 @@ class Command(ZulipBaseCommand):
with open(IMAGE_FILE_PATH, "rb") as fp:
upload_message_attachment_from_request(UploadedFile(fp), shylock)
FixtureData: TypeAlias = Mapping[Union[str, int, None], list[int]]
FixtureData: TypeAlias = Mapping[str | int | None, list[int]]
def insert_fixture_data(
stat: CountStat,
@@ -330,7 +330,7 @@ class Command(ZulipBaseCommand):
"true": self.generate_fixture_data(stat, 20, 2, 3, 0.2, 3),
}
insert_fixture_data(stat, realm_data, RealmCount)
stream_data: Mapping[Union[int, str, None], list[int]] = {
stream_data: Mapping[int | str | None, list[int]] = {
"false": self.generate_fixture_data(stat, 10, 7, 5, 0.6, 4),
"true": self.generate_fixture_data(stat, 5, 3, 2, 0.4, 2),
}

View File

@@ -1,6 +1,6 @@
from contextlib import AbstractContextManager, ExitStack, contextmanager
from datetime import datetime, timedelta, timezone
from typing import Any, Iterator, Optional
from typing import Any, Iterator
from unittest import mock
import time_machine
@@ -111,7 +111,7 @@ class AnalyticsTestCase(ZulipTestCase):
# used to generate unique names in self.create_*
self.name_counter = 100
# used as defaults in self.assert_table_count
self.current_property: Optional[str] = None
self.current_property: str | None = None
# Delete RemoteRealm registrations to have a clean slate - the relevant
# tests want to construct this from scratch.
@@ -226,10 +226,10 @@ class AnalyticsTestCase(ZulipTestCase):
self,
table: type[BaseCount],
value: int,
property: Optional[str] = None,
subgroup: Optional[str] = None,
property: str | None = None,
subgroup: str | None = None,
end_time: datetime = TIME_ZERO,
realm: Optional[Realm] = None,
realm: Realm | None = None,
**kwargs: models.Model,
) -> None:
if property is None:
@@ -1812,7 +1812,7 @@ class TestActiveUsersAudit(AnalyticsTestCase):
self.current_property = self.stat.property
def add_event(
self, event_type: int, days_offset: float, user: Optional[UserProfile] = None
self, event_type: int, days_offset: float, user: UserProfile | None = None
) -> None:
hours_offset = int(24 * days_offset)
if user is None:
@@ -1984,7 +1984,7 @@ class TestRealmActiveHumans(AnalyticsTestCase):
self.stat = COUNT_STATS["realm_active_humans::day"]
self.current_property = self.stat.property
def mark_15day_active(self, user: UserProfile, end_time: Optional[datetime] = None) -> None:
def mark_15day_active(self, user: UserProfile, end_time: datetime | None = None) -> None:
if end_time is None:
end_time = self.TIME_ZERO
UserCount.objects.create(

View File

@@ -1,5 +1,4 @@
from datetime import datetime, timedelta, timezone
from typing import Optional
from django.utils.timezone import now as timezone_now
from typing_extensions import override
@@ -88,7 +87,7 @@ class TestGetChartData(ZulipTestCase):
return [0, 0, i, 0]
def insert_data(
self, stat: CountStat, realm_subgroups: list[Optional[str]], user_subgroups: list[str]
self, stat: CountStat, realm_subgroups: list[str | None], user_subgroups: list[str]
) -> None:
if stat.frequency == CountStat.HOUR:
insert_time = self.end_times_hour[2]

View File

@@ -1,5 +1,3 @@
from typing import Union
from django.conf import settings
from django.conf.urls import include
from django.urls import path
@@ -16,7 +14,7 @@ from analytics.views.stats import (
)
from zerver.lib.rest import rest_path
i18n_urlpatterns: list[Union[URLPattern, URLResolver]] = [
i18n_urlpatterns: list[URLPattern | URLResolver] = [
# Server admin (user_profile.is_staff) visible stats pages
path("stats/realm/<realm_str>/", stats_for_realm),
path("stats/installation", stats_for_installation),

View File

@@ -1,7 +1,7 @@
import logging
from collections import defaultdict
from datetime import datetime, timedelta, timezone
from typing import Any, Optional, TypeVar, Union, cast
from typing import Any, Optional, TypeVar, cast
from django.conf import settings
from django.db.models import QuerySet
@@ -52,9 +52,9 @@ def is_analytics_ready(realm: Realm) -> bool:
def render_stats(
request: HttpRequest,
data_url_suffix: str,
realm: Optional[Realm],
realm: Realm | None,
*,
title: Optional[str] = None,
title: str | None = None,
analytics_ready: bool = True,
) -> HttpResponse:
assert request.user.is_authenticated
@@ -246,25 +246,25 @@ def get_chart_data(
request: HttpRequest,
user_profile: UserProfile,
chart_name: str = REQ(),
min_length: Optional[int] = REQ(converter=to_non_negative_int, default=None),
start: Optional[datetime] = REQ(converter=to_utc_datetime, default=None),
end: Optional[datetime] = REQ(converter=to_utc_datetime, default=None),
min_length: int | None = REQ(converter=to_non_negative_int, default=None),
start: datetime | None = REQ(converter=to_utc_datetime, default=None),
end: datetime | None = REQ(converter=to_utc_datetime, default=None),
# These last several parameters are only used by functions
# wrapping get_chart_data; the callers are responsible for
# parsing/validation/authorization for them.
realm: Optional[Realm] = None,
realm: Realm | None = None,
for_installation: bool = False,
remote: bool = False,
remote_realm_id: Optional[int] = None,
remote_realm_id: int | None = None,
server: Optional["RemoteZulipServer"] = None,
stream: Optional[Stream] = None,
stream: Stream | None = None,
) -> HttpResponse:
TableType: TypeAlias = Union[
type["RemoteInstallationCount"],
type[InstallationCount],
type["RemoteRealmCount"],
type[RealmCount],
]
TableType: TypeAlias = (
type["RemoteInstallationCount"]
| type[InstallationCount]
| type["RemoteRealmCount"]
| type[RealmCount]
)
if for_installation:
if remote:
assert settings.ZILENCER_ENABLED
@@ -281,9 +281,9 @@ def get_chart_data(
else:
aggregate_table = RealmCount
tables: Union[
tuple[TableType], tuple[TableType, type[UserCount]], tuple[TableType, type[StreamCount]]
]
tables: (
tuple[TableType] | tuple[TableType, type[UserCount]] | tuple[TableType, type[StreamCount]]
)
if chart_name == "number_of_humans":
stats = [
@@ -292,7 +292,7 @@ def get_chart_data(
COUNT_STATS["active_users_audit:is_bot:day"],
]
tables = (aggregate_table,)
subgroup_to_label: dict[CountStat, dict[Optional[str], str]] = {
subgroup_to_label: dict[CountStat, dict[str | None, str]] = {
stats[0]: {None: "_1day"},
stats[1]: {None: "_15day"},
stats[2]: {"false": "all_time"},
@@ -372,7 +372,7 @@ def get_chart_data(
assert server is not None
assert aggregate_table is RemoteInstallationCount or aggregate_table is RemoteRealmCount
aggregate_table_remote = cast(
Union[type[RemoteInstallationCount], type[RemoteRealmCount]], aggregate_table
type[RemoteInstallationCount] | type[RemoteRealmCount], aggregate_table
) # https://stackoverflow.com/questions/68540528/mypy-assertions-on-the-types-of-types
if not aggregate_table_remote.objects.filter(server=server).exists():
raise JsonableError(
@@ -552,7 +552,7 @@ def get_time_series_by_subgroup(
table: type[BaseCount],
key_id: int,
end_times: list[datetime],
subgroup_to_label: dict[Optional[str], str],
subgroup_to_label: dict[str | None, str],
include_empty_subgroups: bool,
) -> dict[str, list[int]]:
queryset = (
@@ -560,7 +560,7 @@ def get_time_series_by_subgroup(
.filter(property=stat.property)
.values_list("subgroup", "end_time", "value")
)
value_dicts: dict[Optional[str], dict[datetime, int]] = defaultdict(lambda: defaultdict(int))
value_dicts: dict[str | None, dict[datetime, int]] = defaultdict(lambda: defaultdict(int))
for subgroup, end_time, value in queryset:
value_dicts[subgroup][end_time] = value
value_arrays = {}