From 49b4cf328e115d5639e8bdc7b0978a8abf7c2fb6 Mon Sep 17 00:00:00 2001 From: Roman Inflianskas Date: Tue, 16 Jul 2024 16:23:47 +0300 Subject: [PATCH] fix(tests): Fix exception on copying `frame.f_locals` (Python 3.13) (#3271) Starting from Python 3.13, `frame.f_locals` is not `dict` anymore, but `FrameLocalsProxy`, that cannot be copied using `copy.copy()`. In Python 3.13 and later, it should be copied using a method `.copy()`. The new way of copying works the same as the old one for versions of Python prior to 3.13, according to the documentation (both copying methods produce a shallow copy). Since Python 3.13, `FrameLocalsProxy` skips items of `locals()` that have non-`str` keys; this is a CPython implementation detail, so we hence disable `test_non_string_variables` test on Python 3.13. See: https://peps.python.org/pep-0667/ https://github.com/python/cpython/issues/118921 https://github.com/python/cpython/pull/118923 https://docs.python.org/3.13/whatsnew/3.13.html#porting-to-python-3-13 https://docs.python.org/3/library/copy.html https://github.com/python/cpython/blame/7b413952e817ae87bfda2ac85dd84d30a6ce743b/Objects/frameobject.c#L148 --- sentry_sdk/utils.py | 3 +-- tests/test_client.py | 7 +++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index 9eb1cb3e36..41a6849b3d 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -11,7 +11,6 @@ import threading import time from collections import namedtuple -from copy import copy from datetime import datetime from decimal import Decimal from functools import partial, partialmethod, wraps @@ -618,7 +617,7 @@ def serialize_frame( ) if include_local_variables: - rv["vars"] = copy(frame.f_locals) + rv["vars"] = frame.f_locals.copy() return rv diff --git a/tests/test_client.py b/tests/test_client.py index 0464f32b5e..447359a11c 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -31,6 +31,12 @@ from sentry_sdk._types import Event +maximum_python_312 = pytest.mark.skipif( + sys.version_info > (3, 12), + reason="Since Python 3.13, `FrameLocalsProxy` skips items of `locals()` that have non-`str` keys; this is a CPython implementation detail: https://github.com/python/cpython/blame/7b413952e817ae87bfda2ac85dd84d30a6ce743b/Objects/frameobject.c#L148", +) + + class EnvelopeCapturedError(Exception): pass @@ -879,6 +885,7 @@ class FooError(Exception): assert exception["mechanism"]["meta"]["errno"]["number"] == 69 +@maximum_python_312 def test_non_string_variables(sentry_init, capture_events): """There is some extremely terrible code in the wild that inserts non-strings as variable names into `locals()`."""