Skip to content

Commit 270bc75

Browse files
authored
fix: copy tags/contexts/extras correctly (#56)
* fix: copy tags/contexts/extras correctly * fix: Add tests and fix the other code * fix: event processors should survive clear
1 parent 3269543 commit 270bc75

File tree

2 files changed

+78
-41
lines changed

2 files changed

+78
-41
lines changed

sentry_sdk/scope.py

Lines changed: 61 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,83 @@
11
from .utils import logger
22

33

4+
def _attr_setter(fn):
5+
return property(fset=fn, doc=fn.__doc__)
6+
7+
48
class Scope(object):
59
"""The scope holds extra information that should be sent with all
610
events that belong to it.
711
"""
812

9-
__slots__ = ["_data", "_breadcrumbs", "_event_processors", "_error_processors"]
13+
__slots__ = (
14+
"_fingerprint",
15+
"_transaction",
16+
"_user",
17+
"_tags",
18+
"_contexts",
19+
"_extras",
20+
"_breadcrumbs",
21+
"_event_processors",
22+
"_error_processors",
23+
)
1024

1125
def __init__(self):
12-
self._data = {}
13-
self._breadcrumbs = []
1426
self._event_processors = []
1527
self._error_processors = []
1628

17-
def _set_fingerprint(self, value):
18-
"""When set this overrides the default fingerprint."""
19-
self._data["fingerprint"] = value
29+
self.clear()
2030

21-
fingerprint = property(fset=_set_fingerprint, doc=_set_fingerprint.__doc__)
22-
del _set_fingerprint
31+
@_attr_setter
32+
def fingerprint(self, value):
33+
"""When set this overrides the default fingerprint."""
34+
self._fingerprint = value
2335

24-
def _set_transaction(self, value):
36+
@_attr_setter
37+
def transaction(self, value):
2538
"""When set this forces a specific transaction name to be set."""
26-
self._data["transaction"] = value
27-
28-
transaction = property(fset=_set_transaction, doc=_set_transaction.__doc__)
29-
del _set_transaction
39+
self._transaction = value
3040

31-
def _set_user(self, value):
41+
@_attr_setter
42+
def user(self, value):
3243
"""When set a specific user is bound to the scope."""
33-
self._data["user"] = value
34-
35-
user = property(fset=_set_user, doc=_set_user.__doc__)
36-
del _set_user
44+
self._user = value
3745

3846
def set_tag(self, key, value):
3947
"""Sets a tag for a key to a specific value."""
40-
self._data.setdefault("tags", {})[key] = value
48+
self._tags[key] = value
4149

4250
def remove_tag(self, key):
4351
"""Removes a specific tag."""
44-
self._data.setdefault("tags", {}).pop(key, None)
52+
self._tags.pop(key, None)
4553

4654
def set_context(self, key, value):
4755
"""Binds a context at a certain key to a specific value."""
48-
self._data.setdefault("contexts", {})[key] = value
56+
self._contexts[key] = value
4957

5058
def remove_context(self, key):
5159
"""Removes a context."""
52-
self._data.setdefault("contexts", {}).pop(key, None)
60+
self._contexts.pop(key, None)
5361

5462
def set_extra(self, key, value):
5563
"""Sets an extra key to a specific value."""
56-
self._data.setdefault("extras", {})[key] = value
64+
self._extras[key] = value
5765

5866
def remove_extra(self, key):
5967
"""Removes a specific extra key."""
60-
self._data.setdefault("extras", {}).pop(key, None)
68+
self._extras.pop(key, None)
6169

6270
def clear(self):
6371
"""Clears the entire scope."""
64-
self._data.clear()
65-
del self._breadcrumbs[:]
66-
del self._event_processors[:]
72+
self._fingerprint = None
73+
self._transaction = None
74+
self._user = None
75+
76+
self._tags = {}
77+
self._contexts = {}
78+
self._extras = {}
79+
80+
self._breadcrumbs = []
6781

6882
def add_event_processor(self, func):
6983
""""Register a scope local event processor on the scope.
@@ -99,23 +113,20 @@ def _drop(event, cause, ty):
99113
logger.info("%s (%s) dropped event (%s)", ty, cause, event)
100114

101115
event.setdefault("breadcrumbs", []).extend(self._breadcrumbs)
102-
if event.get("user") is None and "user" in self._data:
103-
event["user"] = self._data["user"]
116+
if event.get("user") is None and self._user is not None:
117+
event["user"] = self._user
104118

105-
if event.get("transaction") is None and "transaction" in self._data:
106-
event["transaction"] = self._data["transaction"]
119+
if event.get("transaction") is None and self._transaction is not None:
120+
event["transaction"] = self._transaction
107121

108-
extra = self._data.get("extra")
109-
if extra:
110-
event.setdefault("extra", {}).update(extra)
122+
if self._extras:
123+
event.setdefault("extra", {}).update(self._extras)
111124

112-
tags = self._data.get("tags")
113-
if tags:
114-
event.setdefault("tags", {}).update(tags)
125+
if self._tags:
126+
event.setdefault("tags", {}).update(self._tags)
115127

116-
contexts = self._data.get("contexts")
117-
if contexts:
118-
event.setdefault("contexts", {}).update(contexts)
128+
if self._contexts:
129+
event.setdefault("contexts", {}).update(self._contexts)
119130

120131
if hint is not None and hint.exc_info is not None:
121132
exc_info = hint.exc_info
@@ -135,8 +146,17 @@ def _drop(event, cause, ty):
135146

136147
def __copy__(self):
137148
rv = object.__new__(self.__class__)
138-
rv._data = dict(self._data)
149+
150+
rv._fingerprint = self._fingerprint
151+
rv._transaction = self._transaction
152+
rv._user = self._user
153+
154+
rv._tags = dict(self._tags)
155+
rv._contexts = dict(self._contexts)
156+
rv._extras = dict(self._extras)
157+
139158
rv._breadcrumbs = list(self._breadcrumbs)
140159
rv._event_processors = list(self._event_processors)
141160
rv._error_processors = list(self._error_processors)
161+
142162
return rv

tests/test_scope.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import copy
2+
from sentry_sdk.scope import Scope
3+
4+
5+
def test_copying():
6+
s1 = Scope()
7+
s1.fingerprint = {}
8+
s1.set_tag("foo", "bar")
9+
10+
s2 = copy.copy(s1)
11+
assert "foo" in s2._tags
12+
13+
s1.set_tag("bam", "baz")
14+
assert "bam" in s1._tags
15+
assert "bam" not in s2._tags
16+
17+
assert s1._fingerprint is s2._fingerprint

0 commit comments

Comments
 (0)