From af5f129c9e2a0d4bbcdb2d586ea6e6ffd478576d Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Mon, 5 Oct 2026 15:13:58 +0200 Subject: [PATCH 1/4] chore: Remove include_local_variables, include_source_context --- MIGRATION_GUIDE.md | 3 +- sentry_sdk/client.py | 9 +- sentry_sdk/consts.py | 10 -- sentry_sdk/data_collection.py | 35 +----- sentry_sdk/integrations/logging.py | 3 - sentry_sdk/utils.py | 34 +----- .../integrations/pure_eval/test_pure_eval.py | 2 +- tests/test_client.py | 22 ++-- tests/test_data_collection.py | 19 --- tests/test_exceptiongroup.py | 18 --- tests/test_utils.py | 113 +----------------- 11 files changed, 31 insertions(+), 237 deletions(-) diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 41bb93ff69..9cdbe9b9bc 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -165,7 +165,8 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh - The `stream_gen_ai_spans` option was removed. All spans are streamed now. - The experimental `record_sql_params` option was removed. Use the `database_query_data` setting of `data_collection` instead. - The `record_params` option of `AsyncPGIntegration` and `AioMySQLIntegration` was removed. Use the `database_query_data` setting of `data_collection` instead. - +- The `include_local_variables` option was removed. Use `data_collection`'s `stack_frame_variables` as a drop-in replacement. +- The `include_source_context` option was removed. Use `data_collection`'s `frame_context_lines` for more granular control over the source context reported by specifying the number of lines to include around the failing line, or set `frame_context_lines=0` to disable source context entirely. ## Deprecated diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py index 7692427fa3..f38f17a68e 100644 --- a/sentry_sdk/client.py +++ b/sentry_sdk/client.py @@ -377,11 +377,7 @@ def _record_lost_event( # data_collection explicitly). if not self.options["data_collection"]["provided_by_user"]: self.options["data_collection"] = _map_from_send_default_pii( - send_default_pii=True, - include_local_variables=self.options["include_local_variables"] - is not False, - include_source_context=self.options["include_source_context"] - is not False, + send_default_pii=True ) self.session_flusher = SessionFlusher(capture_func=_capture_envelope) @@ -524,9 +520,6 @@ def _prepare_event( "values": [ { "stacktrace": current_stacktrace( - include_local_variables=self.options.get( - "include_local_variables", True - ), max_value_length=self.options.get( "max_value_length", DEFAULT_MAX_VALUE_LENGTH ), diff --git a/sentry_sdk/consts.py b/sentry_sdk/consts.py index dd8b2ef775..cefad4b634 100644 --- a/sentry_sdk/consts.py +++ b/sentry_sdk/consts.py @@ -1379,8 +1379,6 @@ def __init__( _experiments: "Experiments" = {}, # noqa: B006 proxy_headers: "Optional[Dict[str, str]]" = None, project_root: "Optional[str]" = None, - include_local_variables: "Optional[bool]" = True, - include_source_context: "Optional[bool]" = True, trace_propagation_targets: "Optional[Sequence[str]]" = [ # noqa: B006 MATCH_ALL ], @@ -1517,14 +1515,6 @@ def __init__( See https://docs.sentry.io/platforms/python/configuration/options/#data_collection for more details. - :param include_source_context: When enabled, source context will be included in events sent to Sentry. - - This source context includes the five lines of code above and below the line of code where an error - happened. - - :param include_local_variables: When enabled, the SDK will capture a snapshot of local variables to send with - the event to help with debugging. - :param add_full_stack: When capturing errors, Sentry stack traces typically only include frames that start the moment an error occurs. diff --git a/sentry_sdk/data_collection.py b/sentry_sdk/data_collection.py index 1cc92a2763..a7511c1a1a 100644 --- a/sentry_sdk/data_collection.py +++ b/sentry_sdk/data_collection.py @@ -149,12 +149,7 @@ def _apply_key_value_collection_filtering( return result -def _map_from_send_default_pii( - *, - send_default_pii: bool, - include_local_variables: bool, - include_source_context: bool, -) -> "DataCollection": +def _map_from_send_default_pii(*, send_default_pii: bool) -> "DataCollection": """ Build a fully-resolved ``DataCollection`` dict that mirrors the data ``send_default_pii`` collects today. Used when ``data_collection`` is not @@ -179,10 +174,8 @@ def _map_from_send_default_pii( "gen_ai": {"inputs": send_default_pii, "outputs": send_default_pii}, "database_query_data": send_default_pii, "queues": send_default_pii, - "stack_frame_variables": include_local_variables, - "frame_context_lines": ( - _DEFAULT_FRAME_CONTEXT_LINES if include_source_context else 0 - ), + "stack_frame_variables": True, + "frame_context_lines": (_DEFAULT_FRAME_CONTEXT_LINES), } @@ -287,9 +280,8 @@ def _resolve_data_collection(options: "Dict[str, Any]") -> "DataCollection": """ Resolve the effective ``DataCollection`` dict from client ``options``. - Reads ``data_collection``, ``send_default_pii``, ``include_local_variables`` - and ``include_source_context`` and returns a fully-resolved dict with - concrete values for every field. + Reads ``data_collection``, ``send_default_pii`` and returns a fully-resolved + dict with concrete values for every field. ``data_collection`` must be a plain ``dict``. @@ -305,17 +297,6 @@ def _resolve_data_collection(options: "Dict[str, Any]") -> "DataCollection": send_default_pii = options.get("send_default_pii") - include_local_variables = ( - bool(options.get("include_local_variables")) - if options.get("include_local_variables") is not None - else True - ) - include_source_context = ( - bool(options.get("include_source_context")) - if options.get("include_source_context") is not None - else True - ) - if user_dc is not None: if not isinstance(user_dc, dict): raise TypeError( @@ -332,8 +313,4 @@ def _resolve_data_collection(options: "Dict[str, Any]") -> "DataCollection": user_dc, ) - return _map_from_send_default_pii( - send_default_pii=bool(send_default_pii), - include_local_variables=include_local_variables, - include_source_context=include_source_context, - ) + return _map_from_send_default_pii(send_default_pii=bool(send_default_pii)) diff --git a/sentry_sdk/integrations/logging.py b/sentry_sdk/integrations/logging.py index e272787888..787cdbd1f2 100644 --- a/sentry_sdk/integrations/logging.py +++ b/sentry_sdk/integrations/logging.py @@ -303,9 +303,6 @@ def _emit(self, record: "LogRecord") -> None: "values": [ { "stacktrace": current_stacktrace( - include_local_variables=client_options[ - "include_local_variables" - ], max_value_length=client_options["max_value_length"], ), "crashed": False, diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index 37b12f36dc..acdc06bd63 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -589,8 +589,6 @@ def filename_for_module( def serialize_frame( frame: "FrameType", tb_lineno: "Optional[int]" = None, - include_local_variables: bool = True, - include_source_context: bool = True, max_value_length: "Optional[int]" = None, custom_repr: "Optional[Callable[..., Optional[str]]]" = None, ) -> "Dict[str, Any]": @@ -624,21 +622,15 @@ def serialize_frame( "lineno": tb_lineno, } - client_options = sentry_sdk.get_client().options - if has_data_collection_enabled(client_options): - include_source_context = bool( - client_options["data_collection"]["frame_context_lines"] - ) + data_collection = sentry_sdk.get_client().options["data_collection"] + include_source_context = bool(data_collection["frame_context_lines"]) if include_source_context: rv["pre_context"], rv["context_line"], rv["post_context"] = get_source_context( frame, tb_lineno, max_value_length ) - if has_data_collection_enabled(client_options): - dc_stack_frame_vars_config = client_options["data_collection"][ - "stack_frame_variables" - ] + dc_stack_frame_vars_config = data_collection["stack_frame_variables"] if isinstance(dc_stack_frame_vars_config, bool): if dc_stack_frame_vars_config: @@ -658,19 +650,10 @@ def serialize_frame( rv["vars"] = serialized_variables - elif include_local_variables: - rv["vars"] = serialize( - dict(frame.f_locals), is_vars=True, custom_repr=custom_repr - ) - return rv -def current_stacktrace( - include_local_variables: bool = True, - include_source_context: bool = True, - max_value_length: "Optional[int]" = None, -) -> "Dict[str, Any]": +def current_stacktrace(max_value_length: "Optional[int]" = None) -> "Dict[str, Any]": __tracebackhide__ = True frames = [] @@ -680,8 +663,6 @@ def current_stacktrace( frames.append( serialize_frame( f, - include_local_variables=include_local_variables, - include_source_context=include_source_context, max_value_length=max_value_length, ) ) @@ -770,13 +751,9 @@ def single_exception_from_error_tuple( exception_value["value"] = get_error_message(exc_value) if client_options is None: - include_local_variables = True - include_source_context = True max_value_length = None # fallback custom_repr = None else: - include_local_variables = client_options["include_local_variables"] - include_source_context = client_options["include_source_context"] max_value_length = client_options["max_value_length"] custom_repr = client_options.get("custom_repr") @@ -784,8 +761,6 @@ def single_exception_from_error_tuple( serialize_frame( tb.tb_frame, tb_lineno=tb.tb_lineno, - include_local_variables=include_local_variables, - include_source_context=include_source_context, max_value_length=max_value_length, custom_repr=custom_repr, ) @@ -1176,7 +1151,6 @@ def event_from_exception( if client_options and client_options.get("add_full_stack", DEFAULT_ADD_FULL_STACK): full_stack = current_stacktrace( - include_local_variables=client_options["include_local_variables"], max_value_length=client_options["max_value_length"], )["frames"] else: diff --git a/tests/integrations/pure_eval/test_pure_eval.py b/tests/integrations/pure_eval/test_pure_eval.py index 057960693c..2c81295503 100644 --- a/tests/integrations/pure_eval/test_pure_eval.py +++ b/tests/integrations/pure_eval/test_pure_eval.py @@ -7,7 +7,7 @@ @pytest.mark.parametrize("integrations", [[], [PureEvalIntegration()]]) -def test_include_local_variables_enabled(sentry_init, capture_events, integrations): +def test_stack_frame_variables_enabled(sentry_init, capture_events, integrations): sentry_init( data_collection={"stack_frame_variables": True}, integrations=integrations ) diff --git a/tests/test_client.py b/tests/test_client.py index 09f6a5e2d5..11d0f409ce 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -411,8 +411,8 @@ def e(exc): assert events[0]["exception"]["values"][0]["type"] == "ValueError" -def test_include_local_variables_enabled(sentry_init, capture_events): - sentry_init(include_local_variables=True) +def test_stack_frame_variables_enabled(sentry_init, capture_events): + sentry_init(data_collection={"stack_frame_variables": True}) events = capture_events() try: 1 / 0 @@ -427,8 +427,8 @@ def test_include_local_variables_enabled(sentry_init, capture_events): ) -def test_include_local_variables_disabled(sentry_init, capture_events): - sentry_init(include_local_variables=False) +def test_stack_frame_variables_disabled(sentry_init, capture_events): + sentry_init(data_collection={"stack_frame_variables": False}) events = capture_events() try: 1 / 0 @@ -443,8 +443,8 @@ def test_include_local_variables_disabled(sentry_init, capture_events): ) -def test_include_source_context_enabled(sentry_init, capture_events): - sentry_init(include_source_context=True) +def test_frame_source_context_enabled(sentry_init, capture_events): + sentry_init(data_collection={"frame_context_lines": 5}) events = capture_events() try: 1 / 0 @@ -459,8 +459,8 @@ def test_include_source_context_enabled(sentry_init, capture_events): assert "context_line" in frame -def test_include_source_context_disabled(sentry_init, capture_events): - sentry_init(include_source_context=False) +def test_frame_source_context_disabled(sentry_init, capture_events): + sentry_init(data_collection={"frame_context_lines": False}) events = capture_events() try: 1 / 0 @@ -542,8 +542,10 @@ def bar(): assert functions[-2:] == ["foo", "bar"] -def test_attach_stacktrace_enabled_no_locals(sentry_init, capture_events): - sentry_init(attach_stacktrace=True, include_local_variables=False) +def test_attach_stacktrace_enabled_no_stack_trace_vars(sentry_init, capture_events): + sentry_init( + attach_stacktrace=True, data_collection={"stack_frame_variables": False} + ) events = capture_events() def foo(): diff --git a/tests/test_data_collection.py b/tests/test_data_collection.py index ff1eed11e0..fa8b04a571 100644 --- a/tests/test_data_collection.py +++ b/tests/test_data_collection.py @@ -151,15 +151,6 @@ def _get(dc, path): }, id="explicit_partial_fills_omitted_with_spec_defaults", ), - pytest.param( - { - "data_collection": {}, - "include_local_variables": False, - "include_source_context": False, - }, - {"stack_frame_variables": True, "frame_context_lines": 5}, - id="explicit_data_collection_ignores_legacy_include_local_variables", - ), pytest.param( { "data_collection": { @@ -311,16 +302,6 @@ def _get(dc, path): {"frame_context_lines": 5}, id="frame_context_lines_none_falls_back_to_spec_default", ), - pytest.param( - {"include_local_variables": False, "include_source_context": False}, - {"stack_frame_variables": False, "frame_context_lines": 0}, - id="legacy_include_local_variables_off_disables_stack_frame_variables", - ), - pytest.param( - {"include_local_variables": True, "include_source_context": True}, - {"stack_frame_variables": True, "frame_context_lines": 5}, - id="legacy_include_local_variables_on_enables_stack_frame_variables", - ), ], ) def test_initialize_client_data_collection(sentry_init, options, expected): diff --git a/tests/test_exceptiongroup.py b/tests/test_exceptiongroup.py index ae476f9c33..ea777feefa 100644 --- a/tests/test_exceptiongroup.py +++ b/tests/test_exceptiongroup.py @@ -45,8 +45,6 @@ def test_exceptiongroup(): (event, _) = event_from_exception( exception_group, client_options={ - "include_local_variables": True, - "include_source_context": True, "max_value_length": 1024, }, mechanism={"type": "test_suite", "handled": False}, @@ -161,8 +159,6 @@ def test_exceptiongroup_simple(): (event, _) = event_from_exception( exception_group, client_options={ - "include_local_variables": True, - "include_source_context": True, "max_value_length": 1024, }, mechanism={"type": "test_suite", "handled": False}, @@ -206,8 +202,6 @@ def test_exception_chain_cause(): (event, _) = event_from_exception( exception_chain_cause, client_options={ - "include_local_variables": True, - "include_source_context": True, "max_value_length": 1024, }, mechanism={"type": "test_suite", "handled": False}, @@ -250,8 +244,6 @@ def test_exception_chain_context(): (event, _) = event_from_exception( exception_chain_context, client_options={ - "include_local_variables": True, - "include_source_context": True, "max_value_length": 1024, }, mechanism={"type": "test_suite", "handled": False}, @@ -293,8 +285,6 @@ def test_simple_exception(): (event, _) = event_from_exception( simple_excpetion, client_options={ - "include_local_variables": True, - "include_source_context": True, "max_value_length": 1024, }, mechanism={"type": "test_suite", "handled": False}, @@ -342,8 +332,6 @@ def test_exception_group_chained_with_context(): (event, _) = event_from_exception( exc, client_options={ - "include_local_variables": True, - "include_source_context": True, "max_value_length": 1024, }, mechanism={"type": "test_suite", "handled": False}, @@ -445,8 +433,6 @@ def test_exceptiongroup_starlette_collapse(): (event, _) = event_from_exception( exception_group, client_options={ - "include_local_variables": True, - "include_source_context": True, "max_value_length": 1024, }, mechanism={"type": "test_suite", "handled": False}, @@ -516,8 +502,6 @@ def test_cyclic_exception_group_cause(): (event, _) = event_from_exception( group, client_options={ - "include_local_variables": True, - "include_source_context": True, "max_value_length": 1024, }, mechanism={"type": "test_suite", "handled": False}, @@ -554,8 +538,6 @@ def test_deeply_nested_cyclic_exception_group(): (event, _) = event_from_exception( outer_group, client_options={ - "include_local_variables": True, - "include_source_context": True, "max_value_length": 1024, }, mechanism={"type": "test_suite", "handled": False}, diff --git a/tests/test_utils.py b/tests/test_utils.py index 7f740f299e..75e9925c86 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -478,44 +478,6 @@ def test_warns_on_invalid_sample_rate(rate, StringContaining): # noqa: N803 assert result is False -@pytest.mark.parametrize( - "options,include_source_context,expected_source_context", - [ - pytest.param({}, True, True, id="no_data_collection-include_true"), - pytest.param({}, False, False, id="no_data_collection-include_false"), - pytest.param( - {"data_collection": {}}, - False, - True, - id="data_collection-spec_default_overrides_include_false", - ), - pytest.param( - {"data_collection": {"frame_context_lines": 3}}, - True, - True, - id="data_collection-frame_context_lines_3", - ), - pytest.param( - {"data_collection": {"frame_context_lines": 0}}, - True, - False, - id="data_collection-frame_context_lines_0_overrides_include_true", - ), - ], -) -def test_include_source_context_when_serializing_frame( - sentry_init, options, include_source_context, expected_source_context -): - sentry_init(**options) - - frame = sys._getframe() - result = serialize_frame(frame, include_source_context=include_source_context) - - assert ("pre_context" in result) is expected_source_context - assert ("context_line" in result) is expected_source_context - assert ("post_context" in result) is expected_source_context - - def _frame_with_locals(): safe_value = "not sensitive" # noqa: F841 password = "ada123" # noqa: F841 @@ -525,36 +487,31 @@ def _frame_with_locals(): @pytest.mark.parametrize( - "data_collection,include_local_variables,expected_vars", + "data_collection,expected_vars", [ pytest.param( {"stack_frame_variables": True}, - False, True, - id="data_collection_stack_frame_variables_true_overrides_include_false", + id="data_collection_stack_frame_variables_true", ), pytest.param( {"stack_frame_variables": False}, - True, False, - id="data_collection_stack_frame_variables_false_overrides_include_true", + id="data_collection_stack_frame_variables_false", ), pytest.param( {}, - False, True, id="data_collection_stack_frame_variables_spec_default_is_true", ), ], ) def test_stack_frame_variables_bool_when_serializing_frame( - sentry_init, data_collection, include_local_variables, expected_vars + sentry_init, data_collection, expected_vars ): sentry_init(data_collection=data_collection) - result = serialize_frame( - _frame_with_locals(), include_local_variables=include_local_variables - ) + result = serialize_frame(_frame_with_locals()) assert ("vars" in result) is expected_vars @@ -654,58 +611,6 @@ def custom_repr(value): assert result["vars"]["password"] == "'[Filtered]'" -@pytest.mark.parametrize( - "options,include_local_variables,expected_vars", - [ - pytest.param( - {}, - True, - True, - id="no_data_collection-include_local_variables_true", - ), - pytest.param( - {}, - False, - False, - id="no_data_collection-include_local_variables_false", - ), - ], -) -def test_include_local_variables_when_data_collection_is_unset( - sentry_init, options, include_local_variables, expected_vars -): - sentry_init(**options) - - result = serialize_frame( - _frame_with_locals(), include_local_variables=include_local_variables - ) - - assert ("vars" in result) is expected_vars - - -def test_data_collection_stack_frame_variables_overrides_include_local_variables_option( - sentry_init, capture_events -): - sentry_init( - include_local_variables=False, - data_collection={"stack_frame_variables": True}, - ) - events = capture_events() - - def raise_with_locals(): - safe_value = "not sensitive" # noqa: F841 - raise ValueError("boom") - - try: - raise_with_locals() - except ValueError: - sentry_sdk.capture_exception() - - (event,) = events - frame = event["exception"]["values"][0]["stacktrace"]["frames"][-1] - assert frame["vars"]["safe_value"] == "'not sensitive'" - - def test_data_collection_stack_frame_variables_filtering_applies_to_captured_exception( sentry_init, capture_events ): @@ -1335,14 +1240,6 @@ def fake_getlines(filename): 0, id="data_collection-frame_context_lines_0", ), - pytest.param( - { - "data_collection": {}, - "include_source_context": False, - }, - 5, - id="data_collection-spec_default_overrides_include_source_context_false", - ), ], ) def test_get_lines_from_file_frame_context_lines( From deb4abb96e29aa2e7d517a9c1d76f5c86c6422b4 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Tue, 6 Oct 2026 08:25:25 +0200 Subject: [PATCH 2/4] init sdk to init data collection --- tests/test_exceptiongroup.py | 12 ++++++++---- tests/test_transport.py | 15 ++++++++++----- tests/utils/test_general.py | 3 ++- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/tests/test_exceptiongroup.py b/tests/test_exceptiongroup.py index ea777feefa..18d3aac3c3 100644 --- a/tests/test_exceptiongroup.py +++ b/tests/test_exceptiongroup.py @@ -18,7 +18,8 @@ @minimum_python_311 -def test_exceptiongroup(): +def test_exceptiongroup(sentry_init): + sentry_init() exception_group = None try: @@ -143,7 +144,8 @@ def test_exceptiongroup(): @minimum_python_311 -def test_exceptiongroup_simple(): +def test_exceptiongroup_simple(sentry_init): + sentry_init() exception_group = None try: @@ -308,7 +310,8 @@ def test_simple_exception(): @minimum_python_311 -def test_exception_group_chained_with_context(): +def test_exception_group_chained_with_context(sentry_init): + sentry_init() try: try: raise ExceptionGroup( @@ -390,7 +393,7 @@ def test_exception_group_chained_with_context(): @minimum_python_311 -def test_exceptiongroup_starlette_collapse(): +def test_exceptiongroup_starlette_collapse(sentry_init): """ Simulates the Starlette collapse_excgroups() pattern where a single-exception ExceptionGroup is caught and the inner exception is unwrapped and re-raised. @@ -410,6 +413,7 @@ def test_exceptiongroup_starlette_collapse(): Without cycle detection in exceptions_from_error(), this causes infinite recursion and a silent RecursionError that drops the event. """ + sentry_init() exception_group = None try: diff --git a/tests/test_transport.py b/tests/test_transport.py index a21ff3b1e2..2ae25458ce 100644 --- a/tests/test_transport.py +++ b/tests/test_transport.py @@ -456,7 +456,8 @@ def test_parse_rate_limits(input, expected): assert dict(_parse_rate_limits(input, now=NOW)) == expected -def test_envelope_too_large_response(capturing_server, make_client): +def test_envelope_too_large_response(sentry_init, capturing_server, make_client): + sentry_init() client = make_client() capturing_server.respond_with(code=413) @@ -476,7 +477,8 @@ def test_envelope_too_large_response(capturing_server, make_client): capturing_server.clear_captured() -def test_simple_rate_limits(capturing_server, make_client): +def test_simple_rate_limits(sentry_init, capturing_server, make_client): + sentry_init() client = make_client() capturing_server.respond_with(code=429, headers={"Retry-After": "4"}) @@ -498,8 +500,9 @@ def test_simple_rate_limits(capturing_server, make_client): @pytest.mark.parametrize("response_code", [200, 429]) def test_data_category_limits( - capturing_server, response_code, make_client, monkeypatch + sentry_init, capturing_server, response_code, make_client, monkeypatch ): + sentry_init() client = make_client(send_client_reports=False) captured_outcomes = [] @@ -557,8 +560,9 @@ def record_lost_event(reason, data_category=None, item=None): @pytest.mark.parametrize("response_code", [200, 429]) def test_data_category_limits_reporting( - capturing_server, response_code, make_client, monkeypatch + sentry_init, capturing_server, response_code, make_client, monkeypatch ): + sentry_init() client = make_client(send_client_reports=True) capturing_server.respond_with( @@ -671,8 +675,9 @@ def intercepting_fetch(*args, **kwargs): @pytest.mark.parametrize("response_code", [200, 429]) def test_complex_limits_without_data_category( - capturing_server, response_code, make_client + sentry_init, capturing_server, response_code, make_client ): + sentry_init() client = make_client() capturing_server.respond_with( code=response_code, diff --git a/tests/utils/test_general.py b/tests/utils/test_general.py index ed0df8b3b5..d518717729 100644 --- a/tests/utils/test_general.py +++ b/tests/utils/test_general.py @@ -52,10 +52,11 @@ def test_safe_repr_non_printable(prefix, character): assert character not in safe_repr(string.encode("utf-8")) -def test_abs_path(): +def test_abs_path(sentry_init): """Check if abs_path is actually an absolute path. This can happen either with eval/exec like here, or when the file in the frame is relative to __main__""" + sentry_init() code = compile("1/0", "test.py", "exec") try: From b708f7f170bf1ef454f4f170253fe0a13a67f886 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Tue, 6 Oct 2026 09:24:27 +0200 Subject: [PATCH 3/4] format fix --- sentry_sdk/data_collection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/data_collection.py b/sentry_sdk/data_collection.py index a7511c1a1a..fbac357a18 100644 --- a/sentry_sdk/data_collection.py +++ b/sentry_sdk/data_collection.py @@ -175,7 +175,7 @@ def _map_from_send_default_pii(*, send_default_pii: bool) -> "DataCollection": "database_query_data": send_default_pii, "queues": send_default_pii, "stack_frame_variables": True, - "frame_context_lines": (_DEFAULT_FRAME_CONTEXT_LINES), + "frame_context_lines": _DEFAULT_FRAME_CONTEXT_LINES, } From e46f50c962232b37bac8a39a0419f7451f8d5acf Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Tue, 6 Oct 2026 10:14:07 +0200 Subject: [PATCH 4/4] make independent --- sentry_sdk/utils.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index acdc06bd63..7c3bb567e7 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -630,25 +630,25 @@ def serialize_frame( frame, tb_lineno, max_value_length ) - dc_stack_frame_vars_config = data_collection["stack_frame_variables"] + dc_stack_frame_vars_config = data_collection["stack_frame_variables"] - if isinstance(dc_stack_frame_vars_config, bool): - if dc_stack_frame_vars_config: - rv["vars"] = serialize( - dict(frame.f_locals), is_vars=True, custom_repr=custom_repr - ) - else: - local_variables_to_send = _apply_key_value_collection_filtering( - items=dict(frame.f_locals), - behaviour=dc_stack_frame_vars_config, + if isinstance(dc_stack_frame_vars_config, bool): + if dc_stack_frame_vars_config: + rv["vars"] = serialize( + dict(frame.f_locals), is_vars=True, custom_repr=custom_repr ) + else: + local_variables_to_send = _apply_key_value_collection_filtering( + items=dict(frame.f_locals), + behaviour=dc_stack_frame_vars_config, + ) - if local_variables_to_send: - serialized_variables = serialize( - local_variables_to_send, is_vars=True, custom_repr=custom_repr - ) + if local_variables_to_send: + serialized_variables = serialize( + local_variables_to_send, is_vars=True, custom_repr=custom_repr + ) - rv["vars"] = serialized_variables + rv["vars"] = serialized_variables return rv