Skip to content

Commit 06bc982

Browse files
committed
Merge branch 'master' into ivana/set-global-attrs-on-global-scope
2 parents eb76a3d + d7aebef commit 06bc982

File tree

7 files changed

+134
-27
lines changed

7 files changed

+134
-27
lines changed

scripts/populate_tox/config.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
"deps": {
3535
"*": ["async-timeout", "pytest-asyncio", "fakeredis>=2.2.0,<2.8"],
3636
"<=0.23": ["pydantic<2"],
37-
"py3.7": ["pydantic<1.10.25"],
3837
},
3938
"num_versions": 2,
4039
},
@@ -134,7 +133,6 @@
134133
# deprecated argument.
135134
"<0.110.1": ["httpx<0.28.0"],
136135
"py3.6": ["aiocontextvars"],
137-
"py3.7": ["pydantic<1.10.25"],
138136
},
139137
},
140138
"flask": {

scripts/populate_tox/package_dependencies.jsonl

Lines changed: 3 additions & 3 deletions
Large diffs are not rendered by default.

scripts/populate_tox/releases.jsonl

Lines changed: 7 additions & 8 deletions
Large diffs are not rendered by default.

tests/test_attributes.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,41 @@ def test_remove_attribute(sentry_init, capture_envelopes):
117117
(metric,) = metrics
118118

119119
assert "some.attribute" not in metric["attributes"]
120+
121+
122+
def test_scope_attributes_preserialized(sentry_init, capture_envelopes):
123+
def before_send_metric(metric, _):
124+
# Scope attrs show up serialized in before_send
125+
assert isinstance(metric["attributes"]["instance"], str)
126+
assert isinstance(metric["attributes"]["dictionary"], str)
127+
128+
return metric
129+
130+
sentry_init(before_send_metric=before_send_metric)
131+
132+
envelopes = capture_envelopes()
133+
134+
class Cat:
135+
pass
136+
137+
instance = Cat()
138+
dictionary = {"color": "tortoiseshell"}
139+
140+
with sentry_sdk.new_scope() as scope:
141+
scope.set_attribute("instance", instance)
142+
scope.set_attribute("dictionary", dictionary)
143+
144+
# Scope attrs are stored preserialized
145+
assert isinstance(scope._attributes["instance"], str)
146+
assert isinstance(scope._attributes["dictionary"], str)
147+
148+
sentry_sdk.metrics.count("test", 1)
149+
150+
sentry_sdk.get_client().flush()
151+
152+
metrics = envelopes_to_metrics(envelopes)
153+
(metric,) = metrics
154+
155+
# Attrs originally from the scope are serialized when sent
156+
assert isinstance(metric["attributes"]["instance"], str)
157+
assert isinstance(metric["attributes"]["dictionary"], str)

tests/test_logs.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,3 +597,40 @@ def test_log_attributes_override_scope_attributes(sentry_init, capture_envelopes
597597

598598
assert log["attributes"]["durable.attribute"] == "value1"
599599
assert log["attributes"]["temp.attribute"] == "value2"
600+
601+
602+
@minimum_python_37
603+
def test_attributes_preserialized_in_before_send(sentry_init, capture_envelopes):
604+
"""We don't surface references to objects in attributes."""
605+
606+
def before_send_log(log, _):
607+
assert isinstance(log["attributes"]["instance"], str)
608+
assert isinstance(log["attributes"]["dictionary"], str)
609+
610+
return log
611+
612+
sentry_init(enable_logs=True, before_send_log=before_send_log)
613+
614+
envelopes = capture_envelopes()
615+
616+
class Cat:
617+
pass
618+
619+
instance = Cat()
620+
dictionary = {"color": "tortoiseshell"}
621+
622+
sentry_sdk.logger.warning(
623+
"Hello world!",
624+
attributes={
625+
"instance": instance,
626+
"dictionary": dictionary,
627+
},
628+
)
629+
630+
get_client().flush()
631+
632+
logs = envelopes_to_logs(envelopes)
633+
(log,) = logs
634+
635+
assert isinstance(log["attributes"]["instance"], str)
636+
assert isinstance(log["attributes"]["dictionary"], str)

tests/test_metrics.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,3 +335,40 @@ def test_metric_attributes_override_scope_attributes(sentry_init, capture_envelo
335335

336336
assert metric["attributes"]["durable.attribute"] == "value1"
337337
assert metric["attributes"]["temp.attribute"] == "value2"
338+
339+
340+
def test_attributes_preserialized_in_before_send(sentry_init, capture_envelopes):
341+
"""We don't surface references to objects in attributes."""
342+
343+
def before_send_metric(metric, _):
344+
assert isinstance(metric["attributes"]["instance"], str)
345+
assert isinstance(metric["attributes"]["dictionary"], str)
346+
347+
return metric
348+
349+
sentry_init(before_send_metric=before_send_metric)
350+
351+
envelopes = capture_envelopes()
352+
353+
class Cat:
354+
pass
355+
356+
instance = Cat()
357+
dictionary = {"color": "tortoiseshell"}
358+
359+
sentry_sdk.metrics.count(
360+
"test.counter",
361+
1,
362+
attributes={
363+
"instance": instance,
364+
"dictionary": dictionary,
365+
},
366+
)
367+
368+
get_client().flush()
369+
370+
metrics = envelopes_to_metrics(envelopes)
371+
(metric,) = metrics
372+
373+
assert isinstance(metric["attributes"]["instance"], str)
374+
assert isinstance(metric["attributes"]["dictionary"], str)

tox.ini

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,12 @@ envlist =
7171
{py3.10,py3.11,py3.12}-openai_agents-v0.0.19
7272
{py3.10,py3.12,py3.13}-openai_agents-v0.2.11
7373
{py3.10,py3.12,py3.13}-openai_agents-v0.4.2
74-
{py3.10,py3.13,py3.14,py3.14t}-openai_agents-v0.6.3
74+
{py3.10,py3.13,py3.14,py3.14t}-openai_agents-v0.6.4
7575

7676
{py3.10,py3.12,py3.13}-pydantic_ai-v1.0.18
7777
{py3.10,py3.12,py3.13}-pydantic_ai-v1.12.0
7878
{py3.10,py3.12,py3.13}-pydantic_ai-v1.24.0
79-
{py3.10,py3.12,py3.13}-pydantic_ai-v1.35.0
79+
{py3.10,py3.12,py3.13}-pydantic_ai-v1.36.0
8080

8181

8282
# ~~~ AI Workflow ~~~
@@ -101,7 +101,7 @@ envlist =
101101
{py3.9,py3.10,py3.11}-cohere-v5.4.0
102102
{py3.9,py3.11,py3.12}-cohere-v5.10.0
103103
{py3.9,py3.11,py3.12}-cohere-v5.15.0
104-
{py3.9,py3.11,py3.12}-cohere-v5.20.0
104+
{py3.9,py3.11,py3.12}-cohere-v5.20.1
105105

106106
{py3.9,py3.12,py3.13}-google_genai-v1.29.0
107107
{py3.9,py3.12,py3.13}-google_genai-v1.38.0
@@ -119,18 +119,18 @@ envlist =
119119

120120
{py3.8,py3.11,py3.12}-openai-base-v1.0.1
121121
{py3.8,py3.12,py3.13}-openai-base-v1.109.1
122-
{py3.9,py3.13,py3.14,py3.14t}-openai-base-v2.13.0
122+
{py3.9,py3.13,py3.14,py3.14t}-openai-base-v2.14.0
123123

124124
{py3.8,py3.11,py3.12}-openai-notiktoken-v1.0.1
125125
{py3.8,py3.12,py3.13}-openai-notiktoken-v1.109.1
126-
{py3.9,py3.13,py3.14,py3.14t}-openai-notiktoken-v2.13.0
126+
{py3.9,py3.13,py3.14,py3.14t}-openai-notiktoken-v2.14.0
127127

128128

129129
# ~~~ Cloud ~~~
130130
{py3.6,py3.7}-boto3-v1.12.49
131131
{py3.6,py3.9,py3.10}-boto3-v1.21.46
132132
{py3.7,py3.11,py3.12}-boto3-v1.33.13
133-
{py3.9,py3.13,py3.14,py3.14t}-boto3-v1.42.12
133+
{py3.9,py3.13,py3.14,py3.14t}-boto3-v1.42.13
134134

135135
{py3.6,py3.7,py3.8}-chalice-v1.16.0
136136
{py3.9,py3.12,py3.13}-chalice-v1.32.0
@@ -396,13 +396,13 @@ deps =
396396
openai_agents-v0.0.19: openai-agents==0.0.19
397397
openai_agents-v0.2.11: openai-agents==0.2.11
398398
openai_agents-v0.4.2: openai-agents==0.4.2
399-
openai_agents-v0.6.3: openai-agents==0.6.3
399+
openai_agents-v0.6.4: openai-agents==0.6.4
400400
openai_agents: pytest-asyncio
401401

402402
pydantic_ai-v1.0.18: pydantic-ai==1.0.18
403403
pydantic_ai-v1.12.0: pydantic-ai==1.12.0
404404
pydantic_ai-v1.24.0: pydantic-ai==1.24.0
405-
pydantic_ai-v1.35.0: pydantic-ai==1.35.0
405+
pydantic_ai-v1.36.0: pydantic-ai==1.36.0
406406
pydantic_ai: pytest-asyncio
407407

408408

@@ -444,7 +444,7 @@ deps =
444444
cohere-v5.4.0: cohere==5.4.0
445445
cohere-v5.10.0: cohere==5.10.0
446446
cohere-v5.15.0: cohere==5.15.0
447-
cohere-v5.20.0: cohere==5.20.0
447+
cohere-v5.20.1: cohere==5.20.1
448448

449449
google_genai-v1.29.0: google-genai==1.29.0
450450
google_genai-v1.38.0: google-genai==1.38.0
@@ -465,14 +465,14 @@ deps =
465465

466466
openai-base-v1.0.1: openai==1.0.1
467467
openai-base-v1.109.1: openai==1.109.1
468-
openai-base-v2.13.0: openai==2.13.0
468+
openai-base-v2.14.0: openai==2.14.0
469469
openai-base: pytest-asyncio
470470
openai-base: tiktoken
471471
openai-base-v1.0.1: httpx<0.28
472472

473473
openai-notiktoken-v1.0.1: openai==1.0.1
474474
openai-notiktoken-v1.109.1: openai==1.109.1
475-
openai-notiktoken-v2.13.0: openai==2.13.0
475+
openai-notiktoken-v2.14.0: openai==2.14.0
476476
openai-notiktoken: pytest-asyncio
477477
openai-notiktoken-v1.0.1: httpx<0.28
478478

@@ -481,7 +481,7 @@ deps =
481481
boto3-v1.12.49: boto3==1.12.49
482482
boto3-v1.21.46: boto3==1.21.46
483483
boto3-v1.33.13: boto3==1.33.13
484-
boto3-v1.42.12: boto3==1.42.12
484+
boto3-v1.42.13: boto3==1.42.13
485485
{py3.7,py3.8}-boto3: urllib3<2.0.0
486486

487487
chalice-v1.16.0: chalice==1.16.0
@@ -594,7 +594,6 @@ deps =
594594
arq: pytest-asyncio
595595
arq: fakeredis>=2.2.0,<2.8
596596
arq-v0.23: pydantic<2
597-
{py3.7}-arq: pydantic<1.10.25
598597

599598
beam-v2.14.0: apache-beam==2.14.0
600599
beam-v2.70.0: apache-beam==2.70.0
@@ -696,7 +695,6 @@ deps =
696695
fastapi-v0.94.1: httpx<0.28.0
697696
fastapi-v0.109.2: httpx<0.28.0
698697
{py3.6}-fastapi: aiocontextvars
699-
{py3.7}-fastapi: pydantic<1.10.25
700698

701699

702700
# ~~~ Web 2 ~~~

0 commit comments

Comments
 (0)