Skip to content

Commit

Permalink
Remove 3.6 compat (#3517)
Browse files Browse the repository at this point in the history
* Remove 3.6 compat

* fix
  • Loading branch information
sentrivana authored Sep 11, 2024
1 parent 3ce8065 commit 28d8b82
Show file tree
Hide file tree
Showing 10 changed files with 54 additions and 171 deletions.
4 changes: 2 additions & 2 deletions scripts/init_serverless_sdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ def extract_and_load_lambda_function_module(self, module_path):
module_name = module_path.split(os.path.sep)[-1]
module_file_path = module_path + ".py"

# Supported python versions are 3.6, 3.7, 3.8
if py_version >= (3, 6):
# Supported python versions are 3.7, 3.8
if py_version >= (3, 7):
import importlib.util

spec = importlib.util.spec_from_file_location(
Expand Down
1 change: 0 additions & 1 deletion sentry_sdk/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
T = TypeVar("T")


PY37 = sys.version_info[0] == 3 and sys.version_info[1] >= 7
PY310 = sys.version_info[0] == 3 and sys.version_info[1] >= 10
PY311 = sys.version_info[0] == 3 and sys.version_info[1] >= 11

Expand Down
35 changes: 9 additions & 26 deletions sentry_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from importlib import import_module
from typing import cast

from sentry_sdk._compat import PY37, check_uwsgi_thread_support
from sentry_sdk._compat import check_uwsgi_thread_support
from sentry_sdk.utils import (
ContextVar,
capture_internal_exceptions,
Expand All @@ -18,7 +18,6 @@
get_type_name,
get_default_release,
handle_in_app,
is_gevent,
logger,
)
from sentry_sdk.serializer import serialize
Expand Down Expand Up @@ -132,14 +131,6 @@ def _get_options(*args, **kwargs):
return rv


try:
# Python 3.6+
module_not_found_error = ModuleNotFoundError
except Exception:
# Older Python versions
module_not_found_error = ImportError # type: ignore


class BaseClient:
"""
.. versionadded:: 2.0.0
Expand Down Expand Up @@ -264,7 +255,7 @@ def _setup_instrumentation(self, functions_to_trace):
function_obj = getattr(module_obj, function_name)
setattr(module_obj, function_name, trace(function_obj))
logger.debug("Enabled tracing for %s", function_qualname)
except module_not_found_error:
except ModuleNotFoundError:
try:
# Try to import a class
# ex: "mymodule.submodule.MyClassName.member_function"
Expand Down Expand Up @@ -320,22 +311,14 @@ def _capture_envelope(envelope):
self.metrics_aggregator = None # type: Optional[MetricsAggregator]
experiments = self.options.get("_experiments", {})
if experiments.get("enable_metrics", True):
# Context vars are not working correctly on Python <=3.6
# with gevent.
metrics_supported = not is_gevent() or PY37
if metrics_supported:
from sentry_sdk.metrics import MetricsAggregator
from sentry_sdk.metrics import MetricsAggregator

self.metrics_aggregator = MetricsAggregator(
capture_func=_capture_envelope,
enable_code_locations=bool(
experiments.get("metric_code_locations", True)
),
)
else:
logger.info(
"Metrics not supported on Python 3.6 and lower with gevent."
)
self.metrics_aggregator = MetricsAggregator(
capture_func=_capture_envelope,
enable_code_locations=bool(
experiments.get("metric_code_locations", True)
),
)

max_request_body_size = ("always", "never", "small", "medium")
if self.options["max_request_body_size"] not in max_request_body_size:
Expand Down
87 changes: 27 additions & 60 deletions sentry_sdk/integrations/aws_lambda.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,77 +208,44 @@ def setup_once():
)
return

pre_37 = hasattr(lambda_bootstrap, "handle_http_request") # Python 3.6
lambda_bootstrap.LambdaRuntimeClient.post_init_error = _wrap_init_error(
lambda_bootstrap.LambdaRuntimeClient.post_init_error
)

if pre_37:
old_handle_event_request = lambda_bootstrap.handle_event_request
old_handle_event_request = lambda_bootstrap.handle_event_request

def sentry_handle_event_request(request_handler, *args, **kwargs):
# type: (Any, *Any, **Any) -> Any
request_handler = _wrap_handler(request_handler)
return old_handle_event_request(request_handler, *args, **kwargs)

lambda_bootstrap.handle_event_request = sentry_handle_event_request

old_handle_http_request = lambda_bootstrap.handle_http_request

def sentry_handle_http_request(request_handler, *args, **kwargs):
# type: (Any, *Any, **Any) -> Any
request_handler = _wrap_handler(request_handler)
return old_handle_http_request(request_handler, *args, **kwargs)

lambda_bootstrap.handle_http_request = sentry_handle_http_request
def sentry_handle_event_request( # type: ignore
lambda_runtime_client, request_handler, *args, **kwargs
):
request_handler = _wrap_handler(request_handler)
return old_handle_event_request(
lambda_runtime_client, request_handler, *args, **kwargs
)

# Patch to_json to drain the queue. This should work even when the
# SDK is initialized inside of the handler
lambda_bootstrap.handle_event_request = sentry_handle_event_request

old_to_json = lambda_bootstrap.to_json
# Patch the runtime client to drain the queue. This should work
# even when the SDK is initialized inside of the handler

def sentry_to_json(*args, **kwargs):
def _wrap_post_function(f):
# type: (F) -> F
def inner(*args, **kwargs):
# type: (*Any, **Any) -> Any
_drain_queue()
return old_to_json(*args, **kwargs)

lambda_bootstrap.to_json = sentry_to_json
else:
lambda_bootstrap.LambdaRuntimeClient.post_init_error = _wrap_init_error(
lambda_bootstrap.LambdaRuntimeClient.post_init_error
)
return f(*args, **kwargs)

old_handle_event_request = lambda_bootstrap.handle_event_request
return inner # type: ignore

def sentry_handle_event_request( # type: ignore
lambda_runtime_client, request_handler, *args, **kwargs
):
request_handler = _wrap_handler(request_handler)
return old_handle_event_request(
lambda_runtime_client, request_handler, *args, **kwargs
)

lambda_bootstrap.handle_event_request = sentry_handle_event_request

# Patch the runtime client to drain the queue. This should work
# even when the SDK is initialized inside of the handler

def _wrap_post_function(f):
# type: (F) -> F
def inner(*args, **kwargs):
# type: (*Any, **Any) -> Any
_drain_queue()
return f(*args, **kwargs)

return inner # type: ignore

lambda_bootstrap.LambdaRuntimeClient.post_invocation_result = (
_wrap_post_function(
lambda_bootstrap.LambdaRuntimeClient.post_invocation_result
)
lambda_bootstrap.LambdaRuntimeClient.post_invocation_result = (
_wrap_post_function(
lambda_bootstrap.LambdaRuntimeClient.post_invocation_result
)
lambda_bootstrap.LambdaRuntimeClient.post_invocation_error = (
_wrap_post_function(
lambda_bootstrap.LambdaRuntimeClient.post_invocation_error
)
)
lambda_bootstrap.LambdaRuntimeClient.post_invocation_error = (
_wrap_post_function(
lambda_bootstrap.LambdaRuntimeClient.post_invocation_error
)
)


def get_lambda_bootstrap():
Expand Down
7 changes: 3 additions & 4 deletions sentry_sdk/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from sentry_sdk.utils import (
ContextVar,
now,
nanosecond_time,
to_timestamp,
serialize_frame,
json_dumps,
Expand Down Expand Up @@ -362,9 +361,9 @@ def _encode_locations(timestamp, code_locations):

# some of these are dumb
TIMING_FUNCTIONS = {
"nanosecond": nanosecond_time,
"microsecond": lambda: nanosecond_time() / 1000.0,
"millisecond": lambda: nanosecond_time() / 1000000.0,
"nanosecond": time.perf_counter_ns,
"microsecond": lambda: time.perf_counter_ns() / 1000.0,
"millisecond": lambda: time.perf_counter_ns() / 1000000.0,
"second": now,
"minute": lambda: now() / 60.0,
"hour": lambda: now() / 3600.0,
Expand Down
7 changes: 3 additions & 4 deletions sentry_sdk/profiler/transaction_profiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
is_gevent,
is_valid_sample_rate,
logger,
nanosecond_time,
set_in_app_in_frames,
)

Expand Down Expand Up @@ -330,7 +329,7 @@ def start(self):
logger.debug("[Profiling] Starting profile")
self.active = True
if not self.start_ns:
self.start_ns = nanosecond_time()
self.start_ns = time.perf_counter_ns()
self.scheduler.start_profiling(self)

def stop(self):
Expand All @@ -341,7 +340,7 @@ def stop(self):
assert self.scheduler, "No scheduler specified"
logger.debug("[Profiling] Stopping profile")
self.active = False
self.stop_ns = nanosecond_time()
self.stop_ns = time.perf_counter_ns()

def __enter__(self):
# type: () -> Profile
Expand Down Expand Up @@ -580,7 +579,7 @@ def _sample_stack(*args, **kwargs):
# were started after this point.
new_profiles = len(self.new_profiles)

now = nanosecond_time()
now = time.perf_counter_ns()

try:
sample = [
Expand Down
3 changes: 1 addition & 2 deletions sentry_sdk/scope.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
capture_internal_exception,
capture_internal_exceptions,
ContextVar,
datetime_from_isoformat,
disable_capture_event,
event_from_exception,
exc_info_from_error,
Expand Down Expand Up @@ -1258,7 +1257,7 @@ def _apply_breadcrumbs_to_event(self, event, hint, options):
try:
for crumb in event["breadcrumbs"]["values"]:
if isinstance(crumb["timestamp"], str):
crumb["timestamp"] = datetime_from_isoformat(crumb["timestamp"])
crumb["timestamp"] = datetime.fromisoformat(crumb["timestamp"])

event["breadcrumbs"]["values"].sort(key=lambda crumb: crumb["timestamp"])
except Exception:
Expand Down
6 changes: 3 additions & 3 deletions sentry_sdk/tracing.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import uuid
import random
import time
import warnings
from datetime import datetime, timedelta, timezone

Expand All @@ -15,7 +16,6 @@
get_current_thread_meta,
is_valid_sample_rate,
logger,
nanosecond_time,
)

from typing import TYPE_CHECKING, cast
Expand Down Expand Up @@ -303,7 +303,7 @@ def __init__(
try:
# profiling depends on this value and requires that
# it is measured in nanoseconds
self._start_timestamp_monotonic_ns = nanosecond_time()
self._start_timestamp_monotonic_ns = time.perf_counter_ns()
except AttributeError:
pass

Expand Down Expand Up @@ -612,7 +612,7 @@ def finish(self, scope=None, end_timestamp=None):
end_timestamp = datetime.fromtimestamp(end_timestamp, timezone.utc)
self.timestamp = end_timestamp
else:
elapsed = nanosecond_time() - self._start_timestamp_monotonic_ns
elapsed = time.perf_counter_ns() - self._start_timestamp_monotonic_ns
self.timestamp = self.start_timestamp + timedelta(
microseconds=elapsed / 1000
)
Expand Down
49 changes: 6 additions & 43 deletions sentry_sdk/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
BaseExceptionGroup = None # type: ignore

import sentry_sdk
from sentry_sdk._compat import PY37
from sentry_sdk.consts import DEFAULT_MAX_VALUE_LENGTH, EndpointType

from typing import TYPE_CHECKING
Expand Down Expand Up @@ -239,15 +238,6 @@ def format_timestamp(value):
return utctime.strftime("%Y-%m-%dT%H:%M:%S.%fZ")


def datetime_from_isoformat(value):
# type: (str) -> datetime
try:
return datetime.fromisoformat(value)
except AttributeError:
# py 3.6
return datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%f")


def event_hint_with_exc_info(exc_info=None):
# type: (Optional[ExcInfo]) -> Dict[str, Optional[ExcInfo]]
"""Creates a hint with the exc info filled in."""
Expand Down Expand Up @@ -1325,27 +1315,13 @@ def _get_contextvars():
See https://docs.sentry.io/platforms/python/contextvars/ for more information.
"""
if not _is_contextvars_broken():
# aiocontextvars is a PyPI package that ensures that the contextvars
# backport (also a PyPI package) works with asyncio under Python 3.6
#
# Import it if available.
if sys.version_info < (3, 7):
# `aiocontextvars` is absolutely required for functional
# contextvars on Python 3.6.
try:
from aiocontextvars import ContextVar

return True, ContextVar
except ImportError:
pass
else:
# On Python 3.7 contextvars are functional.
try:
from contextvars import ContextVar
# On Python 3.7+ contextvars are functional.
try:
from contextvars import ContextVar

return True, ContextVar
except ImportError:
pass
return True, ContextVar
except ImportError:
pass

# Fall back to basic thread-local usage.

Expand Down Expand Up @@ -1830,19 +1806,6 @@ async def runner(*args: "P.args", **kwargs: "P.kwargs"):
return patcher


if PY37:

def nanosecond_time():
# type: () -> int
return time.perf_counter_ns()

else:

def nanosecond_time():
# type: () -> int
return int(time.perf_counter() * 1e9)


def now():
# type: () -> float
return time.perf_counter()
Expand Down
Loading

0 comments on commit 28d8b82

Please sign in to comment.