From 946461ec12a9f95dc5579232c846e9e5e73b9ddf Mon Sep 17 00:00:00 2001 From: alejandro Date: Tue, 20 Oct 2026 20:29:32 +0000 Subject: [PATCH] perf(serializer): Skip cycle-detection memo for atomic values Fixes #8091 Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- sentry_sdk/serializer.py | 11 ++++++++++ tests/test_serializer.py | 45 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/serializer.py b/sentry_sdk/serializer.py index f4867f39b0..bce6ed90e8 100644 --- a/sentry_sdk/serializer.py +++ b/sentry_sdk/serializer.py @@ -46,6 +46,7 @@ MAX_DATABAG_DEPTH: int = 5 MAX_DATABAG_BREADTH: int = 10 CYCLE_MARKER = "" +_ATOMIC_TYPES = frozenset((str, int, float, bool, type(None))) global_repr_processors: "List[ReprProcessor]" = [] @@ -199,6 +200,16 @@ def _serialize_node( self.path.append(segment) try: + if type(obj) in _ATOMIC_TYPES: + return self._serialize_node_impl( + obj, + is_databag=is_databag, + is_request_body=is_request_body, + should_repr_strings=should_repr_strings, + remaining_depth=remaining_depth, + remaining_breadth=remaining_breadth, + ) + with self.memo.memoize(obj) as result: if result: return CYCLE_MARKER diff --git a/tests/test_serializer.py b/tests/test_serializer.py index f1483aba8d..4e83dd19ab 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -3,7 +3,12 @@ import pytest -from sentry_sdk.serializer import MAX_DATABAG_BREADTH, MAX_DATABAG_DEPTH, serialize +from sentry_sdk.serializer import ( + MAX_DATABAG_BREADTH, + MAX_DATABAG_DEPTH, + Memo, + serialize, +) try: import hypothesis.strategies as st @@ -115,6 +120,44 @@ def test_custom_mapping_doesnt_mess_with_mock(extra_normalizer): assert len(m.mock_calls) == 0 +def test_atomic_values_serialization_output(): + result = serialize( + { + "nested": { + "values": [ + "string", + 42, + 3.14, + True, + False, + None, + float("inf"), + float("nan"), + ] + } + } + ) + + assert result == { + "nested": {"values": ["string", 42, 3.14, True, False, None, "inf", "nan"]} + } + + +def test_atomic_values_are_not_memoized(monkeypatch): + memoized_objects = [] + original_memoize = Memo.memoize + + def counting_memoize(self, obj): + memoized_objects.append(obj) + return original_memoize(self, obj) + + monkeypatch.setattr(Memo, "memoize", counting_memoize) + event = {"one": "1", "two": "2", "three": "3"} + + assert serialize(event) == event + assert memoized_objects == [event] + + def test_custom_repr(extra_normalizer): class Foo: pass