Skip to content

Commit

Permalink
Remove utcnow, utcfromtimestamp deprecated in Python 3.12 (#2415)
Browse files Browse the repository at this point in the history
---------

Co-authored-by: Ivana Kellyerova <ivana.kellyerova@sentry.io>
  • Loading branch information
rmad17 and sentrivana authored Oct 9, 2023
1 parent 59a67d3 commit 99aea33
Show file tree
Hide file tree
Showing 11 changed files with 54 additions and 33 deletions.
16 changes: 16 additions & 0 deletions sentry_sdk/_compat.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import sys
import contextlib
from datetime import datetime
from functools import wraps

from sentry_sdk._types import TYPE_CHECKING
Expand Down Expand Up @@ -32,6 +33,12 @@
iteritems = lambda x: x.iteritems() # noqa: B301
binary_sequence_types = (bytearray, memoryview)

def datetime_utcnow():
return datetime.utcnow()

def utc_from_timestamp(timestamp):
return datetime.utcfromtimestamp(timestamp)

def implements_str(cls):
# type: (T) -> T
cls.__unicode__ = cls.__str__
Expand Down Expand Up @@ -78,6 +85,7 @@ def when_called(*args, **kwargs):
return DecoratorContextManager

else:
from datetime import timezone
import urllib.parse as urlparse # noqa

text_type = str
Expand All @@ -87,6 +95,14 @@ def when_called(*args, **kwargs):
iteritems = lambda x: x.items()
binary_sequence_types = (bytes, bytearray, memoryview)

def datetime_utcnow():
# type: () -> datetime
return datetime.now(timezone.utc)

def utc_from_timestamp(timestamp):
# type: (float) -> datetime
return datetime.fromtimestamp(timestamp, timezone.utc)

def implements_str(x):
# type: (T) -> T
return x
Expand Down
7 changes: 3 additions & 4 deletions sentry_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
import os
import uuid
import random
from datetime import datetime
import socket

from sentry_sdk._compat import string_types, text_type, iteritems
from sentry_sdk._compat import datetime_utcnow, string_types, text_type, iteritems
from sentry_sdk.utils import (
capture_internal_exceptions,
current_stacktrace,
Expand Down Expand Up @@ -292,7 +291,7 @@ def _prepare_event(
# type: (...) -> Optional[Event]

if event.get("timestamp") is None:
event["timestamp"] = datetime.utcnow()
event["timestamp"] = datetime_utcnow()

if scope is not None:
is_transaction = event.get("type") == "transaction"
Expand Down Expand Up @@ -568,7 +567,7 @@ def capture_event(
if should_use_envelope_endpoint:
headers = {
"event_id": event_opt["event_id"],
"sent_at": format_timestamp(datetime.utcnow()),
"sent_at": format_timestamp(datetime_utcnow()),
}

if dynamic_sampling_context:
Expand Down
5 changes: 3 additions & 2 deletions sentry_sdk/db/explain_plan/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import datetime

from sentry_sdk._compat import datetime_utcnow
from sentry_sdk.consts import TYPE_CHECKING

if TYPE_CHECKING:
Expand All @@ -15,7 +16,7 @@ def cache_statement(statement, options):
# type: (str, dict[str, Any]) -> None
global EXPLAIN_CACHE

now = datetime.datetime.utcnow()
now = datetime_utcnow()
explain_cache_timeout_seconds = options.get(
"explain_cache_timeout_seconds", EXPLAIN_CACHE_TIMEOUT_SECONDS
)
Expand All @@ -31,7 +32,7 @@ def remove_expired_cache_items():
"""
global EXPLAIN_CACHE

now = datetime.datetime.utcnow()
now = datetime_utcnow()

for key, expiration_time in EXPLAIN_CACHE.items():
expiration_in_the_past = expiration_time < now
Expand Down
5 changes: 2 additions & 3 deletions sentry_sdk/hub.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import copy
import sys

from datetime import datetime
from contextlib import contextmanager

from sentry_sdk._compat import with_metaclass
from sentry_sdk._compat import datetime_utcnow, with_metaclass
from sentry_sdk.consts import INSTRUMENTER
from sentry_sdk.scope import Scope
from sentry_sdk.client import Client
Expand Down Expand Up @@ -439,7 +438,7 @@ def add_breadcrumb(self, crumb=None, hint=None, **kwargs):
hint = dict(hint or ()) # type: Hint

if crumb.get("timestamp") is None:
crumb["timestamp"] = datetime.utcnow()
crumb["timestamp"] = datetime_utcnow()
if crumb.get("type") is None:
crumb["type"] = "default"

Expand Down
9 changes: 5 additions & 4 deletions sentry_sdk/integrations/aws_lambda.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import sys
from copy import deepcopy
from datetime import datetime, timedelta
from datetime import timedelta
from os import environ

from sentry_sdk.api import continue_trace
Expand All @@ -16,10 +16,11 @@
)
from sentry_sdk.integrations import Integration
from sentry_sdk.integrations._wsgi_common import _filter_headers
from sentry_sdk._compat import reraise
from sentry_sdk._compat import datetime_utcnow, reraise
from sentry_sdk._types import TYPE_CHECKING

if TYPE_CHECKING:
from datetime import datetime
from typing import Any
from typing import TypeVar
from typing import Callable
Expand Down Expand Up @@ -323,7 +324,7 @@ def get_lambda_bootstrap():

def _make_request_event_processor(aws_event, aws_context, configured_timeout):
# type: (Any, Any, Any) -> EventProcessor
start_time = datetime.utcnow()
start_time = datetime_utcnow()

def event_processor(sentry_event, hint, start_time=start_time):
# type: (Event, Hint, datetime) -> Optional[Event]
Expand Down Expand Up @@ -428,7 +429,7 @@ def _get_cloudwatch_logs_url(aws_context, start_time):
log_group=aws_context.log_group_name,
log_stream=aws_context.log_stream_name,
start_time=(start_time - timedelta(seconds=1)).strftime(formatstring),
end_time=(datetime.utcnow() + timedelta(seconds=2)).strftime(formatstring),
end_time=(datetime_utcnow() + timedelta(seconds=2)).strftime(formatstring),
)

return url
9 changes: 5 additions & 4 deletions sentry_sdk/integrations/gcp.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import sys
from copy import deepcopy
from datetime import datetime, timedelta
from datetime import timedelta
from os import environ

from sentry_sdk.api import continue_trace
from sentry_sdk.consts import OP
from sentry_sdk.hub import Hub, _should_send_default_pii
from sentry_sdk.tracing import TRANSACTION_SOURCE_COMPONENT
from sentry_sdk._compat import reraise
from sentry_sdk._compat import datetime_utcnow, reraise
from sentry_sdk.utils import (
AnnotatedValue,
capture_internal_exceptions,
Expand All @@ -25,6 +25,7 @@
MILLIS_TO_SECONDS = 1000.0

if TYPE_CHECKING:
from datetime import datetime
from typing import Any
from typing import TypeVar
from typing import Callable
Expand Down Expand Up @@ -57,7 +58,7 @@ def sentry_func(functionhandler, gcp_event, *args, **kwargs):

configured_time = int(configured_time)

initial_time = datetime.utcnow()
initial_time = datetime_utcnow()

with hub.push_scope() as scope:
with capture_internal_exceptions():
Expand Down Expand Up @@ -154,7 +155,7 @@ def _make_request_event_processor(gcp_event, configured_timeout, initial_time):
def event_processor(event, hint):
# type: (Event, Hint) -> Optional[Event]

final_time = datetime.utcnow()
final_time = datetime_utcnow()
time_diff = final_time - initial_time

execution_duration_in_millis = time_diff.microseconds / MILLIS_TO_SECONDS
Expand Down
5 changes: 2 additions & 3 deletions sentry_sdk/integrations/logging.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from __future__ import absolute_import

import logging
import datetime
from fnmatch import fnmatch

from sentry_sdk.hub import Hub
Expand All @@ -12,7 +11,7 @@
capture_internal_exceptions,
)
from sentry_sdk.integrations import Integration
from sentry_sdk._compat import iteritems
from sentry_sdk._compat import iteritems, utc_from_timestamp

from sentry_sdk._types import TYPE_CHECKING

Expand Down Expand Up @@ -282,6 +281,6 @@ def _breadcrumb_from_record(self, record):
"level": self._logging_to_event_level(record),
"category": record.name,
"message": record.message,
"timestamp": datetime.datetime.utcfromtimestamp(record.created),
"timestamp": utc_from_timestamp(record.created),
"data": self._extra_from_record(record),
}
7 changes: 4 additions & 3 deletions sentry_sdk/session.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import uuid
from datetime import datetime

from sentry_sdk._compat import datetime_utcnow
from sentry_sdk._types import TYPE_CHECKING
from sentry_sdk.utils import format_timestamp

if TYPE_CHECKING:
from datetime import datetime
from typing import Optional
from typing import Union
from typing import Any
Expand Down Expand Up @@ -48,7 +49,7 @@ def __init__(
if sid is None:
sid = uuid.uuid4()
if started is None:
started = datetime.utcnow()
started = datetime_utcnow()
if status is None:
status = "ok"
self.status = status
Expand Down Expand Up @@ -108,7 +109,7 @@ def update(
if did is not None:
self.did = str(did)
if timestamp is None:
timestamp = datetime.utcnow()
timestamp = datetime_utcnow()
self.timestamp = timestamp
if started is not None:
self.started = started
Expand Down
9 changes: 5 additions & 4 deletions sentry_sdk/tracing.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import uuid
import random

from datetime import datetime, timedelta
from datetime import timedelta

import sentry_sdk
from sentry_sdk.consts import INSTRUMENTER
from sentry_sdk.utils import is_valid_sample_rate, logger, nanosecond_time
from sentry_sdk._compat import PY2
from sentry_sdk._compat import datetime_utcnow, PY2
from sentry_sdk.consts import SPANDATA
from sentry_sdk._types import TYPE_CHECKING


if TYPE_CHECKING:
import typing

from datetime import datetime
from typing import Any
from typing import Dict
from typing import Iterator
Expand Down Expand Up @@ -145,7 +146,7 @@ def __init__(
self._tags = {} # type: Dict[str, str]
self._data = {} # type: Dict[str, Any]
self._containing_transaction = containing_transaction
self.start_timestamp = start_timestamp or datetime.utcnow()
self.start_timestamp = start_timestamp or datetime_utcnow()
try:
# profiling depends on this value and requires that
# it is measured in nanoseconds
Expand Down Expand Up @@ -469,7 +470,7 @@ def finish(self, hub=None, end_timestamp=None):
microseconds=elapsed / 1000
)
except AttributeError:
self.timestamp = datetime.utcnow()
self.timestamp = datetime_utcnow()

maybe_create_breadcrumbs_from_span(hub, self)
return None
Expand Down
12 changes: 7 additions & 5 deletions sentry_sdk/transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@
import gzip
import time

from datetime import datetime, timedelta
from datetime import timedelta
from collections import defaultdict

from sentry_sdk.utils import Dsn, logger, capture_internal_exceptions, json_dumps
from sentry_sdk.worker import BackgroundWorker
from sentry_sdk.envelope import Envelope, Item, PayloadRef

from sentry_sdk._compat import datetime_utcnow
from sentry_sdk._types import TYPE_CHECKING

if TYPE_CHECKING:
from datetime import datetime
from typing import Any
from typing import Callable
from typing import Dict
Expand Down Expand Up @@ -122,7 +124,7 @@ def __del__(self):
def _parse_rate_limits(header, now=None):
# type: (Any, Optional[datetime]) -> Iterable[Tuple[DataCategory, datetime]]
if now is None:
now = datetime.utcnow()
now = datetime_utcnow()

for limit in header.split(","):
try:
Expand Down Expand Up @@ -209,7 +211,7 @@ def _update_rate_limits(self, response):
# sentries if a proxy in front wants to globally slow things down.
elif response.status == 429:
logger.warning("Rate-limited via 429")
self._disabled_until[None] = datetime.utcnow() + timedelta(
self._disabled_until[None] = datetime_utcnow() + timedelta(
seconds=self._retry.get_retry_after(response) or 60
)

Expand Down Expand Up @@ -316,13 +318,13 @@ def _check_disabled(self, category):
def _disabled(bucket):
# type: (Any) -> bool
ts = self._disabled_until.get(bucket)
return ts is not None and ts > datetime.utcnow()
return ts is not None and ts > datetime_utcnow()

return _disabled(category) or _disabled(None)

def _is_rate_limited(self):
# type: () -> bool
return any(ts > datetime.utcnow() for ts in self._disabled_until.values())
return any(ts > datetime_utcnow() for ts in self._disabled_until.values())

def _is_worker_full(self):
# type: () -> bool
Expand Down
3 changes: 2 additions & 1 deletion tests/test_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from pytest_localserver.http import WSGIServer

from sentry_sdk import Hub, Client, add_breadcrumb, capture_message, Scope
from sentry_sdk._compat import datetime_utcnow
from sentry_sdk.transport import _parse_rate_limits
from sentry_sdk.envelope import Envelope, parse_json
from sentry_sdk.integrations.logging import LoggingIntegration
Expand Down Expand Up @@ -118,7 +119,7 @@ def test_transport_works(
Hub.current.bind_client(client)
request.addfinalizer(lambda: Hub.current.bind_client(None))

add_breadcrumb(level="info", message="i like bread", timestamp=datetime.utcnow())
add_breadcrumb(level="info", message="i like bread", timestamp=datetime_utcnow())
capture_message("löl")

getattr(client, client_flush_method)()
Expand Down

0 comments on commit 99aea33

Please sign in to comment.