Browse Source

ref: use datetime.timezone.utc instead of pytz.utc / pytz.UTC (#54705)

django 4.x switches to zoneinfo-based timezones -- this gets us mostly
off of pytz for non-user timezones
anthony sottile 1 year ago
parent
commit
7d17434e01

+ 1 - 1
setup.cfg

@@ -94,7 +94,7 @@ sentry =
 # Currently, the black formatter doesn't wrap long strings: https://github.com/psf/black/issues/182#issuecomment-385325274
 # We already have a lot of E501's - these are lines black didn't wrap.
 # But rather than append # noqa: E501 to all of them, we just ignore E501 for now.
-extend-ignore = E203,E501,E402,E731,B007,B009,B010,B011,B020,B023,B024,B026,B027
+extend-ignore = E203,E501,E402,E731,B007,B009,B010,B011,B020,B023,B024,B026,B027,S008
 
 per-file-ignores =
     # these scripts must have minimal dependencies so opt out of the usual sentry rules

+ 2 - 3
src/sentry/api/base.py

@@ -3,7 +3,7 @@ from __future__ import annotations
 import functools
 import logging
 import time
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, timezone
 from typing import Any, Callable, Iterable, List, Mapping, Optional, Tuple, Type
 from urllib.parse import quote as urlquote
 
@@ -12,7 +12,6 @@ from django.conf import settings
 from django.http import HttpResponse
 from django.http.request import HttpRequest
 from django.views.decorators.csrf import csrf_exempt
-from pytz import utc
 from rest_framework import status
 from rest_framework.authentication import BaseAuthentication, SessionAuthentication
 from rest_framework.exceptions import ParseError
@@ -538,7 +537,7 @@ class StatsMixin:
             if end:
                 end = to_datetime(float(end))
             else:
-                end = datetime.utcnow().replace(tzinfo=utc)
+                end = datetime.utcnow().replace(tzinfo=timezone.utc)
         except ValueError:
             raise ParseError(detail="until must be a numeric timestamp.")
 

+ 4 - 5
src/sentry/api/endpoints/organization_details.py

@@ -1,13 +1,12 @@
 import logging
 from copy import copy
 from dataclasses import dataclass
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, timezone
 
 from django.db import IntegrityError, models, router, transaction
 from django.db.models.query_utils import DeferredAttribute
 from django.urls import reverse
-from django.utils import timezone
-from pytz import UTC
+from django.utils import timezone as django_timezone
 from rest_framework import serializers, status
 
 from bitfield.types import BitHandler
@@ -295,7 +294,7 @@ class OrganizationSerializer(BaseOrganizationSerializer):
         return attrs
 
     def save_trusted_relays(self, incoming, changed_data, organization):
-        timestamp_now = datetime.utcnow().replace(tzinfo=UTC).isoformat()
+        timestamp_now = datetime.utcnow().replace(tzinfo=timezone.utc).isoformat()
         option_key = "sentry:trusted-relays"
         try:
             # get what we already have
@@ -701,7 +700,7 @@ def send_delete_confirmation(delete_confirmation_args: DeleteConfirmationArgs):
         "username": username,
         "user_ip_address": user_ip_address,
         "deletion_datetime": deletion_datetime,
-        "eta": timezone.now() + timedelta(seconds=countdown),
+        "eta": django_timezone.now() + timedelta(seconds=countdown),
         "url": url,
     }
 

+ 4 - 6
src/sentry/dynamic_sampling/rules/helpers/latest_releases.py

@@ -1,11 +1,9 @@
 import re
 from collections import namedtuple
 from dataclasses import dataclass, field
-from datetime import datetime
+from datetime import datetime, timezone
 from typing import Callable, Dict, List, Optional, Tuple
 
-from pytz import UTC
-
 from sentry.dynamic_sampling.rules.helpers.time_to_adoptions import Platform
 from sentry.dynamic_sampling.rules.utils import BOOSTED_RELEASES_LIMIT, get_redis_client_for_ds
 from sentry.models import Project, Release
@@ -87,7 +85,7 @@ class BoostedReleases:
         # We get release models in order to have all the information to extend the releases we get from the cache.
         models = self._get_releases_models()
 
-        current_timestamp = datetime.utcnow().replace(tzinfo=UTC).timestamp()
+        current_timestamp = datetime.utcnow().replace(tzinfo=timezone.utc).timestamp()
 
         extended_boosted_releases = []
         expired_boosted_releases = []
@@ -155,7 +153,7 @@ class ProjectBoostedReleases:
         self.redis_client.hset(
             cache_key,
             self._generate_cache_key_for_boosted_release(release_id, environment),
-            datetime.utcnow().replace(tzinfo=UTC).timestamp(),
+            datetime.utcnow().replace(tzinfo=timezone.utc).timestamp(),
         )
         # In order to avoid having the boosted releases hash in memory for an indefinite amount of time, we will expire
         # it after a specific timeout.
@@ -210,7 +208,7 @@ class ProjectBoostedReleases:
         """
         cache_key = self._generate_cache_key_for_boosted_releases_hash()
         boosted_releases = self.redis_client.hgetall(cache_key)
-        current_timestamp = datetime.utcnow().replace(tzinfo=UTC).timestamp()
+        current_timestamp = datetime.utcnow().replace(tzinfo=timezone.utc).timestamp()
 
         LRBRelease = namedtuple("LRBRelease", ["key", "timestamp"])
         lrb_release = None

+ 3 - 4
src/sentry/event_manager.py

@@ -8,7 +8,7 @@ import re
 import time
 import uuid
 from dataclasses import dataclass
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, timezone
 from io import BytesIO
 from typing import (
     TYPE_CHECKING,
@@ -32,7 +32,6 @@ from django.db import IntegrityError, OperationalError, connection, router, tran
 from django.db.models import Func
 from django.db.models.signals import post_save
 from django.utils.encoding import force_str
-from pytz import UTC
 
 from sentry import (
     eventstore,
@@ -1286,7 +1285,7 @@ def _tsdb_record_all_metrics(jobs: Sequence[Job]) -> None:
 
 @metrics.wraps("save_event.nodestore_save_many")
 def _nodestore_save_many(jobs: Sequence[Job]) -> None:
-    inserted_time = datetime.utcnow().replace(tzinfo=UTC).timestamp()
+    inserted_time = datetime.utcnow().replace(tzinfo=timezone.utc).timestamp()
     for job in jobs:
         # Write the event to Nodestore
         subkeys = {}
@@ -2210,7 +2209,7 @@ def save_attachment(
     if start_time is not None:
         timestamp = to_datetime(start_time)
     else:
-        timestamp = datetime.utcnow().replace(tzinfo=UTC)
+        timestamp = datetime.utcnow().replace(tzinfo=timezone.utc)
 
     try:
         data = attachment.data

+ 4 - 4
src/sentry/notifications/notifications/rules.py

@@ -1,6 +1,7 @@
 from __future__ import annotations
 
 import logging
+from datetime import timezone
 from typing import Any, Iterable, Mapping, MutableMapping
 from urllib.parse import urlencode
 
@@ -115,17 +116,16 @@ class AlertRuleNotification(ProjectNotification):
     def get_recipient_context(
         self, recipient: RpcActor, extra_context: Mapping[str, Any]
     ) -> MutableMapping[str, Any]:
-        timezone = pytz.timezone("UTC")
-
+        tz = timezone.utc
         if recipient.actor_type == ActorType.USER:
             user_tz = UserOption.objects.get_value(user=recipient, key="timezone", default="UTC")
             try:
-                timezone = pytz.timezone(user_tz)
+                tz = pytz.timezone(user_tz)
             except pytz.UnknownTimeZoneError:
                 pass
         return {
             **super().get_recipient_context(recipient, extra_context),
-            "timezone": timezone,
+            "timezone": tz,
         }
 
     def get_context(self) -> MutableMapping[str, Any]:

+ 2 - 3
src/sentry/profiles/task.py

@@ -1,14 +1,13 @@
 from __future__ import annotations
 
 from copy import deepcopy
-from datetime import datetime
+from datetime import datetime, timezone
 from time import time
 from typing import Any, List, Mapping, MutableMapping, Optional, Tuple
 
 import msgpack
 import sentry_sdk
 from django.conf import settings
-from pytz import UTC
 from symbolic.proguard import ProguardMapper
 
 from sentry import quotas
@@ -703,7 +702,7 @@ def _track_outcome(
         key_id=None,
         outcome=outcome,
         reason=reason,
-        timestamp=datetime.utcnow().replace(tzinfo=UTC),
+        timestamp=datetime.utcnow().replace(tzinfo=timezone.utc),
         event_id=event_id,
         category=DataCategory.PROFILE_INDEXED,
         quantity=1,

+ 2 - 4
src/sentry/projectoptions/manager.py

@@ -1,8 +1,6 @@
 import bisect
 import uuid
-from datetime import datetime
-
-from pytz import utc
+from datetime import datetime, timezone
 
 from sentry.utils import json
 
@@ -78,7 +76,7 @@ class ProjectOptionsManager:
         ProjectOption.objects.set_value(
             project,
             "sentry:relay-rev-lastchange",
-            json.datetime_to_str(datetime.utcnow().replace(tzinfo=utc)),
+            json.datetime_to_str(datetime.utcnow().replace(tzinfo=timezone.utc)),
         )
 
     def register(self, key, default=None, epoch_defaults=None):

+ 8 - 9
src/sentry/receivers/onboarding.py

@@ -1,11 +1,10 @@
 from __future__ import annotations
 
 import logging
-from datetime import datetime
+from datetime import datetime, timezone
 
-import pytz
 from django.db.models import F
-from django.utils import timezone
+from django.utils import timezone as django_timezone
 
 from sentry import analytics
 from sentry.models import (
@@ -47,7 +46,7 @@ logger = logging.getLogger("sentry")
 # Used to determine if we should or not record an analytic data
 # for a first event of a project with a minified stack trace
 START_DATE_TRACKING_FIRST_EVENT_WITH_MINIFIED_STACK_TRACE_PER_PROJ = datetime(
-    2022, 12, 14, tzinfo=pytz.UTC
+    2022, 12, 14, tzinfo=timezone.utc
 )
 
 
@@ -238,7 +237,7 @@ def record_first_replay(project, **kwargs):
         organization_id=project.organization_id,
         task=OnboardingTask.SESSION_REPLAY,
         status=OnboardingTaskStatus.COMPLETE,
-        date_completed=timezone.now(),
+        date_completed=django_timezone.now(),
     )
 
     if success:
@@ -306,7 +305,7 @@ def record_member_joined(organization_id: int, organization_member_id: int, **kw
         status=OnboardingTaskStatus.PENDING,
         values={
             "status": OnboardingTaskStatus.COMPLETE,
-            "date_completed": timezone.now(),
+            "date_completed": django_timezone.now(),
             "data": {"invited_member_id": organization_member_id},
         },
     )
@@ -491,7 +490,7 @@ def record_alert_rule_created(user, project, rule, rule_type, **kwargs):
             "status": OnboardingTaskStatus.COMPLETE,
             "user_id": user.id if user else None,
             "project_id": project.id,
-            "date_completed": timezone.now(),
+            "date_completed": django_timezone.now(),
         },
     )
 
@@ -509,7 +508,7 @@ def record_issue_tracker_used(plugin, project, user, **kwargs):
             "status": OnboardingTaskStatus.COMPLETE,
             "user_id": user.id,
             "project_id": project.id,
-            "date_completed": timezone.now(),
+            "date_completed": django_timezone.now(),
             "data": {"plugin": plugin.slug},
         },
     )
@@ -563,7 +562,7 @@ def record_integration_added(
         if task.status != OnboardingTaskStatus.COMPLETE:
             task.status = OnboardingTaskStatus.COMPLETE
             task.user_id = user_id
-            task.date_completed = timezone.now()
+            task.date_completed = django_timezone.now()
         task.save()
     else:
         task = OrganizationOnboardingTask.objects.create(

+ 1 - 2
src/sentry/relay/config/__init__.py

@@ -16,7 +16,6 @@ from typing import (
 )
 
 import sentry_sdk
-from pytz import utc
 from sentry_sdk import Hub, capture_exception
 
 from sentry import features, killswitches, quotas, utils
@@ -321,7 +320,7 @@ def _get_project_config(
     public_keys = get_public_key_configs(project, full_config, project_keys=project_keys)
 
     with Hub.current.start_span(op="get_public_config"):
-        now = datetime.utcnow().replace(tzinfo=utc)
+        now = datetime.utcnow().replace(tzinfo=timezone.utc)
         cfg = {
             "disabled": False,
             "slug": project.slug,

Some files were not shown because too many files changed in this diff