Skip to content

Commit

Permalink
fix(tests): Fix exception on copying frame.f_locals (Python 3.13) (#…
Browse files Browse the repository at this point in the history
…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/
python/cpython#118921
python/cpython#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
  • Loading branch information
rominf committed Jul 16, 2024
1 parent b9d1e3e commit 49b4cf3
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 2 deletions.
3 changes: 1 addition & 2 deletions sentry_sdk/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
7 changes: 7 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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()`."""
Expand Down

0 comments on commit 49b4cf3

Please sign in to comment.