diff --git a/sentry_sdk/_lru_cache.py b/sentry_sdk/_lru_cache.py index 825c773529..36b7c5e571 100644 --- a/sentry_sdk/_lru_cache.py +++ b/sentry_sdk/_lru_cache.py @@ -62,8 +62,6 @@ """ -from copy import copy, deepcopy - SENTINEL = object() @@ -91,13 +89,6 @@ def __init__(self, max_size): self.hits = self.misses = 0 - def __copy__(self): - cache = LRUCache(self.max_size) - cache.full = self.full - cache.cache = copy(self.cache) - cache.root = deepcopy(self.root) - return cache - def set(self, key, value): link = self.cache.get(key, SENTINEL) diff --git a/sentry_sdk/flag_utils.py b/sentry_sdk/flag_utils.py index 2b345a7f0b..cf4800e855 100644 --- a/sentry_sdk/flag_utils.py +++ b/sentry_sdk/flag_utils.py @@ -1,4 +1,3 @@ -from copy import copy from typing import TYPE_CHECKING import sentry_sdk @@ -25,12 +24,6 @@ def clear(self): # type: () -> None self.buffer = LRUCache(self.capacity) - def __copy__(self): - # type: () -> FlagBuffer - buffer = FlagBuffer(capacity=self.capacity) - buffer.buffer = copy(self.buffer) - return buffer - def get(self): # type: () -> list[FlagData] return [{"flag": key, "result": value} for key, value in self.buffer.get_all()] diff --git a/sentry_sdk/scope.py b/sentry_sdk/scope.py index bb45143c48..cf72fabdd1 100644 --- a/sentry_sdk/scope.py +++ b/sentry_sdk/scope.py @@ -1,7 +1,7 @@ import os import sys import warnings -from copy import copy +from copy import copy, deepcopy from collections import deque from contextlib import contextmanager from enum import Enum @@ -252,7 +252,7 @@ def __copy__(self): rv._last_event_id = self._last_event_id - rv._flags = copy(self._flags) + rv._flags = deepcopy(self._flags) return rv diff --git a/tests/test_lru_cache.py b/tests/test_lru_cache.py index cab9bbc7eb..615c66f4a0 100644 --- a/tests/test_lru_cache.py +++ b/tests/test_lru_cache.py @@ -1,5 +1,5 @@ import pytest -from copy import copy +from copy import deepcopy from sentry_sdk._lru_cache import LRUCache @@ -66,13 +66,22 @@ def test_cache_copy(): cache.set(0, 0) cache.set(1, 1) - copied = copy(cache) + copied = deepcopy(cache) cache.set(2, 2) cache.set(3, 3) assert copied.get_all() == [(0, 0), (1, 1)] assert cache.get_all() == [(1, 1), (2, 2), (3, 3)] - copied = copy(cache) + copied = deepcopy(cache) cache.get(1) assert copied.get_all() == [(1, 1), (2, 2), (3, 3)] assert cache.get_all() == [(2, 2), (3, 3), (1, 1)] + + +def test_cache_pollution(): + cache1 = LRUCache(max_size=2) + cache1.set(1, True) + cache2 = deepcopy(cache1) + cache2.set(1, False) + assert cache1.get(1) is True + assert cache2.get(1) is False diff --git a/tests/test_scope.py b/tests/test_scope.py index a03eb07a99..9b16dc4344 100644 --- a/tests/test_scope.py +++ b/tests/test_scope.py @@ -43,6 +43,28 @@ def test_all_slots_copied(): assert getattr(scope_copy, attr) == getattr(scope, attr) +def test_scope_flags_copy(): + # Assert forking creates a deepcopy of the flag buffer. The new + # scope is free to mutate without consequence to the old scope. The + # old scope is free to mutate without consequence to the new scope. + old_scope = Scope() + old_scope.flags.set("a", True) + + new_scope = old_scope.fork() + new_scope.flags.set("a", False) + old_scope.flags.set("b", True) + new_scope.flags.set("c", True) + + assert old_scope.flags.get() == [ + {"flag": "a", "result": True}, + {"flag": "b", "result": True}, + ] + assert new_scope.flags.get() == [ + {"flag": "a", "result": False}, + {"flag": "c", "result": True}, + ] + + def test_merging(sentry_init, capture_events): sentry_init()