Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove 3.6 compat #3517

Merged
merged 3 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading