Skip to content

Commit 5b0597d

Browse files
committed
Merge branch 'master' into ivana/toxgen/move-arq
2 parents 8c15e38 + 4e845d5 commit 5b0597d

File tree

10 files changed

+189
-50
lines changed

10 files changed

+189
-50
lines changed

scripts/populate_tox/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@
188188
"package": "openai-agents",
189189
"deps": {
190190
"*": ["pytest-asyncio"],
191+
"<=0.2.10": ["openai<1.103.0"],
191192
},
192193
"python": ">=3.10",
193194
},

scripts/populate_tox/populate_tox.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,6 @@
7373
"chalice",
7474
"gcp",
7575
"httpx",
76-
"langchain",
77-
"langchain_notiktoken",
7876
"pure_eval",
7977
"quart",
8078
"ray",

scripts/split_tox_gh_actions/split_tox_gh_actions.py

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import configparser
1919
import hashlib
20+
import re
2021
import sys
2122
from collections import defaultdict
2223
from functools import reduce
@@ -25,6 +26,18 @@
2526

2627
from jinja2 import Environment, FileSystemLoader
2728

29+
TOXENV_REGEX = re.compile(
30+
r"""
31+
{?(?P<py_versions>(py\d+\.\d+,?)+)}?
32+
-(?P<framework>[a-z](?:[a-z_]|-(?!v{?\d|latest))*[a-z0-9])
33+
(?:-(
34+
(v{?(?P<framework_versions>[0-9.]+[0-9a-z,.]*}?))
35+
|
36+
(?P<framework_versions_latest>latest)
37+
))?
38+
""",
39+
re.VERBOSE,
40+
)
2841

2942
OUT_DIR = Path(__file__).resolve().parent.parent.parent / ".github" / "workflows"
3043
TOX_FILE = Path(__file__).resolve().parent.parent.parent / "tox.ini"
@@ -202,29 +215,37 @@ def parse_tox():
202215
py_versions_pinned = defaultdict(set)
203216
py_versions_latest = defaultdict(set)
204217

218+
parsed_correctly = True
219+
205220
for line in lines:
206221
# normalize lines
207222
line = line.strip().lower()
208223

209224
try:
210225
# parse tox environment definition
211-
try:
212-
(raw_python_versions, framework, framework_versions) = line.split("-")
213-
except ValueError:
214-
(raw_python_versions, framework) = line.split("-")
215-
framework_versions = []
226+
parsed = TOXENV_REGEX.match(line)
227+
if not parsed:
228+
print(f"ERROR reading line {line}")
229+
raise ValueError("Failed to parse tox environment definition")
230+
231+
groups = parsed.groupdict()
232+
raw_python_versions = groups["py_versions"]
233+
framework = groups["framework"]
234+
framework_versions_latest = groups.get("framework_versions_latest") or False
216235

217236
# collect python versions to test the framework in
218-
raw_python_versions = set(
219-
raw_python_versions.replace("{", "").replace("}", "").split(",")
220-
)
221-
if "latest" in framework_versions:
237+
raw_python_versions = set(raw_python_versions.split(","))
238+
if framework_versions_latest:
222239
py_versions_latest[framework] |= raw_python_versions
223240
else:
224241
py_versions_pinned[framework] |= raw_python_versions
225242

226-
except ValueError:
243+
except Exception:
227244
print(f"ERROR reading line {line}")
245+
parsed_correctly = False
246+
247+
if not parsed_correctly:
248+
raise RuntimeError("Failed to parse tox.ini")
228249

229250
py_versions_pinned = _normalize_py_versions(py_versions_pinned)
230251
py_versions_latest = _normalize_py_versions(py_versions_latest)

sentry_sdk/ai/monitoring.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
from typing import TYPE_CHECKING
1111

1212
if TYPE_CHECKING:
13-
from typing import Optional, Callable, Any
13+
from typing import Optional, Callable, Awaitable, Any, Union, TypeVar
14+
15+
F = TypeVar("F", bound=Union[Callable[..., Any], Callable[..., Awaitable[Any]]])
1416

1517
_ai_pipeline_name = ContextVar("ai_pipeline_name", default=None)
1618

@@ -26,9 +28,9 @@ def get_ai_pipeline_name():
2628

2729

2830
def ai_track(description, **span_kwargs):
29-
# type: (str, Any) -> Callable[..., Any]
31+
# type: (str, Any) -> Callable[[F], F]
3032
def decorator(f):
31-
# type: (Callable[..., Any]) -> Callable[..., Any]
33+
# type: (F) -> F
3234
def sync_wrapped(*args, **kwargs):
3335
# type: (Any, Any) -> Any
3436
curr_pipeline = _ai_pipeline_name.get()
@@ -88,9 +90,9 @@ async def async_wrapped(*args, **kwargs):
8890
return res
8991

9092
if inspect.iscoroutinefunction(f):
91-
return wraps(f)(async_wrapped)
93+
return wraps(f)(async_wrapped) # type: ignore
9294
else:
93-
return wraps(f)(sync_wrapped)
95+
return wraps(f)(sync_wrapped) # type: ignore
9496

9597
return decorator
9698

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import sys
2+
3+
import sentry_sdk
4+
from sentry_sdk.utils import (
5+
capture_internal_exceptions,
6+
event_from_exception,
7+
)
8+
from sentry_sdk.integrations import Integration
9+
10+
from typing import TYPE_CHECKING
11+
12+
if TYPE_CHECKING:
13+
from typing import Callable
14+
from typing import Any
15+
16+
17+
class UnraisablehookIntegration(Integration):
18+
identifier = "unraisablehook"
19+
20+
@staticmethod
21+
def setup_once():
22+
# type: () -> None
23+
sys.unraisablehook = _make_unraisable(sys.unraisablehook)
24+
25+
26+
def _make_unraisable(old_unraisablehook):
27+
# type: (Callable[[sys.UnraisableHookArgs], Any]) -> Callable[[sys.UnraisableHookArgs], Any]
28+
def sentry_sdk_unraisablehook(unraisable):
29+
# type: (sys.UnraisableHookArgs) -> None
30+
integration = sentry_sdk.get_client().get_integration(UnraisablehookIntegration)
31+
32+
# Note: If we replace this with ensure_integration_enabled then
33+
# we break the exceptiongroup backport;
34+
# See: https://github.com/getsentry/sentry-python/issues/3097
35+
if integration is None:
36+
return old_unraisablehook(unraisable)
37+
38+
if unraisable.exc_value and unraisable.exc_traceback:
39+
with capture_internal_exceptions():
40+
event, hint = event_from_exception(
41+
(
42+
unraisable.exc_type,
43+
unraisable.exc_value,
44+
unraisable.exc_traceback,
45+
),
46+
client_options=sentry_sdk.get_client().options,
47+
mechanism={"type": "unraisablehook", "handled": False},
48+
)
49+
sentry_sdk.capture_event(event, hint=hint)
50+
51+
return old_unraisablehook(unraisable)
52+
53+
return sentry_sdk_unraisablehook

sentry_sdk/profiler/transaction_profiler.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
)
4646
from sentry_sdk.utils import (
4747
capture_internal_exception,
48+
capture_internal_exceptions,
4849
get_current_thread_meta,
4950
is_gevent,
5051
is_valid_sample_rate,
@@ -369,12 +370,13 @@ def __enter__(self):
369370

370371
def __exit__(self, ty, value, tb):
371372
# type: (Optional[Any], Optional[Any], Optional[Any]) -> None
372-
self.stop()
373+
with capture_internal_exceptions():
374+
self.stop()
373375

374-
scope, old_profile = self._context_manager_state
375-
del self._context_manager_state
376+
scope, old_profile = self._context_manager_state
377+
del self._context_manager_state
376378

377-
scope.profile = old_profile
379+
scope.profile = old_profile
378380

379381
def write(self, ts, sample):
380382
# type: (int, ExtractedSample) -> None

sentry_sdk/tracing.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from sentry_sdk.consts import INSTRUMENTER, SPANSTATUS, SPANDATA, SPANTEMPLATE
99
from sentry_sdk.profiler.continuous_profiler import get_profiler_id
1010
from sentry_sdk.utils import (
11+
capture_internal_exceptions,
1112
get_current_thread_meta,
1213
is_valid_sample_rate,
1314
logger,
@@ -418,10 +419,11 @@ def __exit__(self, ty, value, tb):
418419
if value is not None and should_be_treated_as_error(ty, value):
419420
self.set_status(SPANSTATUS.INTERNAL_ERROR)
420421

421-
scope, old_span = self._context_manager_state
422-
del self._context_manager_state
423-
self.finish(scope)
424-
scope.span = old_span
422+
with capture_internal_exceptions():
423+
scope, old_span = self._context_manager_state
424+
del self._context_manager_state
425+
self.finish(scope)
426+
scope.span = old_span
425427

426428
@property
427429
def containing_transaction(self):
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import pytest
2+
import sys
3+
import subprocess
4+
5+
from textwrap import dedent
6+
7+
8+
TEST_PARAMETERS = [
9+
("", "HttpTransport"),
10+
('_experiments={"transport_http2": True}', "Http2Transport"),
11+
]
12+
13+
minimum_python_38 = pytest.mark.skipif(
14+
sys.version_info < (3, 8),
15+
reason="The unraisable exception hook is only available in Python 3.8 and above.",
16+
)
17+
18+
19+
@minimum_python_38
20+
@pytest.mark.parametrize("options, transport", TEST_PARAMETERS)
21+
def test_unraisablehook(tmpdir, options, transport):
22+
app = tmpdir.join("app.py")
23+
app.write(
24+
dedent(
25+
"""
26+
from sentry_sdk import init, transport
27+
from sentry_sdk.integrations.unraisablehook import UnraisablehookIntegration
28+
29+
class Undeletable:
30+
def __del__(self):
31+
1 / 0
32+
33+
def capture_envelope(self, envelope):
34+
print("capture_envelope was called")
35+
event = envelope.get_event()
36+
if event is not None:
37+
print(event)
38+
39+
transport.{transport}.capture_envelope = capture_envelope
40+
41+
init("http://foobar@localhost/123", integrations=[UnraisablehookIntegration()], {options})
42+
43+
undeletable = Undeletable()
44+
del undeletable
45+
""".format(
46+
transport=transport, options=options
47+
)
48+
)
49+
)
50+
51+
output = subprocess.check_output(
52+
[sys.executable, str(app)], stderr=subprocess.STDOUT
53+
)
54+
55+
assert b"ZeroDivisionError" in output
56+
assert b"capture_envelope was called" in output

tests/test_basics.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,7 @@ def foo(event, hint):
870870
(["celery"], "sentry.python"),
871871
(["dedupe"], "sentry.python"),
872872
(["excepthook"], "sentry.python"),
873+
(["unraisablehook"], "sentry.python"),
873874
(["executing"], "sentry.python"),
874875
(["modules"], "sentry.python"),
875876
(["pure_eval"], "sentry.python"),

0 commit comments

Comments
 (0)