Skip to content

Commit 268c978

Browse files
authored
Correct semantics to use isolation scope and not current scope (#42)
* Correct semantics to use isolation scope and not current scope Previously this library was based on hubs which maps to the isolation scope now.
1 parent 9871391 commit 268c978

File tree

6 files changed

+34
-42
lines changed

6 files changed

+34
-42
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,12 @@ extreme lenghts to keep its own SDK setup separate from the SDK setup of the
153153
tested code.
154154

155155
`pytest-sentry` exposes the `sentry_test_scope` fixture whose return value is
156-
the `Scope` being used to send events to Sentry. Use `with use_scope(entry_test_scope):`
156+
the isolation `Scope` being used to send events to Sentry. Use `with use_isolation_scope(sentry_test_scope)`:
157157
to temporarily switch context. You can use this to set custom tags like so::
158158

159159
```python
160160
def test_foo(sentry_test_scope):
161-
with use_scope(sentry_test_scope):
161+
with use_isolation_scope(sentry_test_scope):
162162
sentry_sdk.set_tag("pull_request", os.environ['EXAMPLE_CI_PULL_REQUEST'])
163163
```
164164

pytest_sentry/fixtures.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
@pytest.fixture
77
def sentry_test_scope(request):
88
"""
9-
Gives back the current scope.
9+
Gives back the isolation Scope.
1010
"""
1111

1212
item = request.node

pytest_sentry/helpers.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,33 @@
11
import sentry_sdk
2+
from sentry_sdk.scope import ScopeType
3+
from sentry_sdk.opentelemetry.scope import setup_scope_context_management
24

35
from pytest_sentry.client import Client
46

57

6-
DEFAULT_SCOPE = sentry_sdk.Scope(client=Client())
8+
setup_scope_context_management()
9+
DEFAULT_ISOLATION_SCOPE = sentry_sdk.Scope(ty=ScopeType.ISOLATION)
10+
DEFAULT_ISOLATION_SCOPE.set_client(Client())
711

8-
_scope_cache = {}
12+
_isolation_scope_cache = {}
913

1014

1115
def _resolve_scope_marker_value(marker_value):
12-
if id(marker_value) not in _scope_cache:
13-
_scope_cache[id(marker_value)] = rv = _resolve_scope_marker_value_uncached(
16+
if id(marker_value) not in _isolation_scope_cache:
17+
_isolation_scope_cache[id(marker_value)] = rv = _resolve_scope_marker_value_uncached(
1418
marker_value
1519
)
1620
return rv
1721

18-
return _scope_cache[id(marker_value)]
22+
return _isolation_scope_cache[id(marker_value)]
1923

2024

2125
def _resolve_scope_marker_value_uncached(marker_value):
2226
if marker_value is None:
2327
# If no special configuration is provided
2428
# (like pytestmark or @pytest.mark.sentry_client() decorator)
2529
# use the default scope
26-
marker_value = DEFAULT_SCOPE
30+
marker_value = DEFAULT_ISOLATION_SCOPE
2731
else:
2832
marker_value = marker_value.args[0]
2933

@@ -37,25 +41,25 @@ def _resolve_scope_marker_value_uncached(marker_value):
3741

3842
if isinstance(marker_value, str):
3943
# If a DSN string is provided, create a new client and use that
40-
scope = sentry_sdk.get_current_scope()
44+
scope = sentry_sdk.get_isolation_scope()
4145
scope.set_client(Client(marker_value))
4246
return scope
4347

4448
if isinstance(marker_value, dict):
4549
# If a dict is provided, create a new client using the dict as Client options
46-
scope = sentry_sdk.get_current_scope()
50+
scope = sentry_sdk.get_isolation_scope()
4751
scope.set_client(Client(**marker_value))
4852
return scope
4953

5054
if isinstance(marker_value, Client):
5155
# If a Client instance is provided, use that
52-
scope = sentry_sdk.get_current_scope()
56+
scope = sentry_sdk.get_isolation_scope()
5357
scope.set_client(marker_value)
5458
return scope
5559

5660
if isinstance(marker_value, sentry_sdk.Scope):
5761
# If a Scope instance is provided, use the client from it
58-
scope = sentry_sdk.get_current_scope()
62+
scope = sentry_sdk.get_isolation_scope()
5963
scope.set_client(marker_value.client)
6064
return marker_value
6165

pytest_sentry/hooks.py

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,31 +27,19 @@ def hookwrapper(itemgetter, **kwargs):
2727
"""
2828

2929
@wrapt.decorator
30-
def _with_scope(wrapped, instance, args, kwargs):
30+
def _with_isolation_scope(wrapped, instance, args, kwargs):
3131
item = itemgetter(*args, **kwargs)
32-
scope = _resolve_scope_marker_value(item.get_closest_marker("sentry_client"))
32+
isolation_scope = _resolve_scope_marker_value(item.get_closest_marker("sentry_client"))
3333

34-
if scope.client.get_integration(PytestIntegration) is None:
34+
if isolation_scope.client.get_integration(PytestIntegration) is None:
3535
yield
3636
else:
37-
with sentry_sdk.use_scope(scope):
37+
with sentry_sdk.use_isolation_scope(isolation_scope):
3838
gen = wrapped(*args, **kwargs)
39-
40-
while True:
41-
try:
42-
with sentry_sdk.use_scope(scope):
43-
chunk = next(gen)
44-
45-
y = yield chunk
46-
47-
with sentry_sdk.use_scope(scope):
48-
gen.send(y)
49-
50-
except StopIteration:
51-
break
39+
yield from gen
5240

5341
def inner(f):
54-
return pytest.hookimpl(hookwrapper=True, **kwargs)(_with_scope(f))
42+
return pytest.hookimpl(hookwrapper=True, **kwargs)(_with_isolation_scope(f))
5543

5644
return inner
5745

@@ -89,7 +77,7 @@ def pytest_runtest_call(item):
8977

9078
# We use the full name including parameters because then we can identify
9179
# how often a single test has run as part of the same GITHUB_RUN_ID.
92-
with sentry_sdk.continue_trace(dict(sentry_sdk.get_current_scope().iter_trace_propagation_headers())):
80+
with sentry_sdk.continue_trace(dict(sentry_sdk.get_isolation_scope().iter_trace_propagation_headers())):
9381
with sentry_sdk.start_span(op=op, name=name) as span:
9482
span.set_attribute("pytest-sentry.rerun", is_rerun)
9583
if is_rerun:
@@ -107,7 +95,7 @@ def pytest_fixture_setup(fixturedef, request):
10795
op = "pytest.fixture.setup"
10896
name = "{} {}".format(op, fixturedef.argname)
10997

110-
with sentry_sdk.continue_trace(dict(sentry_sdk.get_current_scope().iter_trace_propagation_headers())):
98+
with sentry_sdk.continue_trace(dict(sentry_sdk.get_isolation_scope().iter_trace_propagation_headers())):
11199
with sentry_sdk.start_span(op=op, name=name) as root_span:
112100
root_span.set_tag("pytest.fixture.scope", fixturedef.scope)
113101
yield
@@ -135,8 +123,8 @@ def pytest_runtest_makereport(item, call):
135123
call.excinfo
136124
]
137125

138-
scope = _resolve_scope_marker_value(item.get_closest_marker("sentry_client"))
139-
integration = scope.client.get_integration(PytestIntegration)
126+
isolation_scope = _resolve_scope_marker_value(item.get_closest_marker("sentry_client"))
127+
integration = isolation_scope.client.get_integration(PytestIntegration)
140128

141129
if (cur_exc_chain and call.excinfo is None) or (integration is not None and integration.always_report):
142130
for exc_info in cur_exc_chain:

tests/test_envvars.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def capture_envelope(self, envelope):
3232

3333

3434
def test_basic(sentry_test_scope):
35-
with sentry_sdk.use_scope(sentry_test_scope):
35+
with sentry_sdk.use_isolation_scope(sentry_test_scope):
3636
sentry_test_scope.capture_message("hi")
3737

3838
(event,) = events

tests/test_scope.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,25 @@
99

1010
pytestmark = pytest.mark.sentry_client(GLOBAL_CLIENT)
1111

12-
_DEFAULT_GLOBAL_SCOPE = sentry_sdk.Scope.get_global_scope()
13-
_DEFAULT_ISOLATION_SCOPE = sentry_sdk.Scope.get_isolation_scope()
12+
_DEFAULT_GLOBAL_SCOPE = sentry_sdk.get_global_scope()
13+
_DEFAULT_ISOLATION_SCOPE = sentry_sdk.get_isolation_scope()
1414

1515

1616
def _assert_right_scopes():
17-
global_scope = sentry_sdk.Scope.get_global_scope()
17+
global_scope = sentry_sdk.get_global_scope()
1818
assert global_scope is _DEFAULT_GLOBAL_SCOPE
1919

20-
isolation_scope = sentry_sdk.Scope.get_isolation_scope()
20+
isolation_scope = sentry_sdk.get_isolation_scope()
2121
assert isolation_scope is _DEFAULT_ISOLATION_SCOPE
2222

2323

2424
def test_basic():
2525
_assert_right_scopes()
2626

2727

28-
def test_sentry_test_scope(sentry_test_scope):
28+
def test_correct_span():
2929
# Ensure that we are within a root span (started by the pytest_runtest_call hook)
30-
assert sentry_test_scope.span is not None
30+
assert sentry_sdk.get_current_scope().span is not None
3131

3232

3333
class TestSimpleClass(object):

0 commit comments

Comments
 (0)