From 3909e91634a74e174db91b14e8f4b22aa4e620b1 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Thu, 30 Nov 2023 18:05:24 +0100 Subject: [PATCH 01/16] Fix static/class method tracing --- sentry_sdk/client.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py index 749ab23cfe..296867fe4a 100644 --- a/sentry_sdk/client.py +++ b/sentry_sdk/client.py @@ -3,6 +3,7 @@ import uuid import random import socket +import inspect from sentry_sdk._compat import datetime_utcnow, string_types, text_type, iteritems from sentry_sdk.utils import ( @@ -197,7 +198,15 @@ def _setup_instrumentation(self, functions_to_trace): module_obj = import_module(module_name) class_obj = getattr(module_obj, class_name) function_obj = getattr(class_obj, function_name) - setattr(class_obj, function_name, trace(function_obj)) + function_type = type( + inspect.getattr_static(class_obj, function_name) + ) + traced_function = trace(function_obj) + + if function_type in (staticmethod, classmethod): + traced_function = function_type(traced_function) + + setattr(class_obj, function_name, traced_function) setattr(module_obj, class_name, class_obj) logger.debug("Enabled tracing for %s", function_qualname) From 166a4105b23830a98ea2076a89e9a30f25c763bf Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Fri, 1 Dec 2023 14:15:31 +0100 Subject: [PATCH 02/16] Add tests, fix classmethod --- sentry_sdk/client.py | 2 +- tests/tracing/test_decorator_py3.py | 49 ++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py index 296867fe4a..d61551ea4d 100644 --- a/sentry_sdk/client.py +++ b/sentry_sdk/client.py @@ -204,7 +204,7 @@ def _setup_instrumentation(self, functions_to_trace): traced_function = trace(function_obj) if function_type in (staticmethod, classmethod): - traced_function = function_type(traced_function) + traced_function = staticmethod(traced_function) setattr(class_obj, function_name, traced_function) setattr(module_obj, class_name, class_obj) diff --git a/tests/tracing/test_decorator_py3.py b/tests/tracing/test_decorator_py3.py index c458e8add4..5b8a2d05b3 100644 --- a/tests/tracing/test_decorator_py3.py +++ b/tests/tracing/test_decorator_py3.py @@ -1,4 +1,5 @@ from unittest import mock +from contextlib import contextmanager import pytest import sys @@ -11,6 +12,16 @@ pytest.skip("Async decorator only works on Python 3.6+", allow_module_level=True) +class TestClass: + @staticmethod + def static(arg): + return arg + + @classmethod + def class_(cls, arg): + return cls, arg + + def my_example_function(): return "return_of_sync_function" @@ -19,7 +30,8 @@ async def my_async_example_function(): return "return_of_async_function" -def test_trace_decorator_sync_py3(): +@contextmanager +def patch_start_child(): fake_start_child = mock.MagicMock() fake_transaction = mock.MagicMock() fake_transaction.start_child = fake_start_child @@ -28,6 +40,11 @@ def test_trace_decorator_sync_py3(): "sentry_sdk.tracing_utils_py3.get_current_span", return_value=fake_transaction, ): + yield fake_start_child + + +def test_trace_decorator_sync_py3(): + with patch_start_child() as fake_start_child: result = my_example_function() fake_start_child.assert_not_called() assert result == "return_of_sync_function" @@ -101,3 +118,33 @@ async def test_trace_decorator_async_py3_no_trx(): "test_decorator_py3.my_async_example_function", ) assert result2 == "return_of_async_function" + + +def test_staticmethod_patching(sentry_init): + test_staticmethod_name = "test_decorator_py3.TestClass.static" + assert ( + ".".join([TestClass.static.__module__, TestClass.static.__qualname__]) + == test_staticmethod_name + ), "The test static method was moved or renamed. Please update the name accordingly" + + sentry_init(functions_to_trace=[{"qualified_name": test_staticmethod_name}]) + + for instance_or_class in (TestClass, TestClass()): + with patch_start_child() as fake_start_child: + assert instance_or_class.static(1) == 1 + fake_start_child.assert_called_once() + + +def test_classmethod_patching(sentry_init): + test_classmethod_name = "test_decorator_py3.TestClass.class_" + assert ( + ".".join([TestClass.class_.__module__, TestClass.class_.__qualname__]) + == test_classmethod_name + ), "The test class method was moved or renamed. Please update the name accordingly" + + sentry_init(functions_to_trace=[{"qualified_name": test_classmethod_name}]) + + for instance_or_class in (TestClass, TestClass()): + with patch_start_child() as fake_start_child: + assert instance_or_class.class_(1) == (TestClass, 1) + fake_start_child.assert_called_once() From 5ce591a27fe49abca79e72a3dcfd8d9313c9db8c Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Fri, 1 Dec 2023 15:31:11 +0100 Subject: [PATCH 03/16] Fix Python 2 --- sentry_sdk/client.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py index de85ec6a0e..e14c1fd5fc 100644 --- a/sentry_sdk/client.py +++ b/sentry_sdk/client.py @@ -3,7 +3,6 @@ import uuid import random import socket -import inspect from sentry_sdk._compat import datetime_utcnow, string_types, text_type, iteritems from sentry_sdk.utils import ( @@ -199,9 +198,7 @@ def _setup_instrumentation(self, functions_to_trace): module_obj = import_module(module_name) class_obj = getattr(module_obj, class_name) function_obj = getattr(class_obj, function_name) - function_type = type( - inspect.getattr_static(class_obj, function_name) - ) + function_type = type(class_obj.__dict__[function_name]) traced_function = trace(function_obj) if function_type in (staticmethod, classmethod): From 2e815cb6d4ffed1bdf36619af0e0312a5782db94 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 27 Dec 2023 11:07:34 -0500 Subject: [PATCH 04/16] Restructure tracing decorator tests --- tests/conftest.py | 32 +++++++- tests/test_basics.py | 46 ++++++++++++ tests/tracing/test_decorator_py2.py | 36 ++++----- tests/tracing/test_decorator_py3.py | 110 +--------------------------- 4 files changed, 96 insertions(+), 128 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 44ee18b4ee..654e0559d5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,6 +2,7 @@ import os import socket from threading import Thread +from contextlib import contextmanager import pytest import jsonschema @@ -27,8 +28,13 @@ from http.server import BaseHTTPRequestHandler, HTTPServer +try: + from unittest import mock +except ImportError: + import mock + import sentry_sdk -from sentry_sdk._compat import iteritems, reraise, string_types +from sentry_sdk._compat import iteritems, reraise, string_types, PY2 from sentry_sdk.envelope import Envelope from sentry_sdk.integrations import _processed_integrations # noqa: F401 from sentry_sdk.profiler import teardown_profiler @@ -37,6 +43,12 @@ from tests import _warning_recorder, _warning_recorder_mgr +from sentry_sdk._types import TYPE_CHECKING + +if TYPE_CHECKING: + from typing import Optional + from collections.abc import Iterator + SENTRY_EVENT_SCHEMA = "./checkouts/data-schemas/relay/event.schema.json" @@ -620,3 +632,21 @@ def werkzeug_set_cookie(client, servername, key, value): client.set_cookie(servername, key, value) except TypeError: client.set_cookie(key, value) + + +@contextmanager +def patch_start_tracing_child(fake_transaction=mock.MagicMock()): + # type: (Optional[mock.MagicMock]) -> Iterator[Optional[mock.MagicMock]] + if fake_transaction is not None: + fake_start_child = mock.MagicMock() + fake_transaction.start_child = fake_start_child + else: + fake_start_child = None + + version = "2" if PY2 else "3" + + with mock.patch( + "sentry_sdk.tracing_utils_py%s.get_current_span" % version, + return_value=fake_transaction, + ): + yield fake_start_child diff --git a/tests/test_basics.py b/tests/test_basics.py index 2c2dcede3f..1b80270c16 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -5,6 +5,8 @@ import pytest +from tests.conftest import patch_start_tracing_child + from sentry_sdk import ( Client, push_scope, @@ -736,3 +738,47 @@ def test_multiple_setup_integrations_calls(): second_call_return = setup_integrations([NoOpIntegration()], with_defaults=False) assert second_call_return == {NoOpIntegration.identifier: NoOpIntegration()} + + +class TracingTestClass: + @staticmethod + def static(arg): + return arg + + @classmethod + def class_(cls, arg): + return cls, arg + + +def test_staticmethod_tracing(sentry_init): + test_staticmethod_name = "tests.test_basics.TracingTestClass.static" + assert ( + ".".join( + [TracingTestClass.static.__module__, TracingTestClass.static.__qualname__] + ) + == test_staticmethod_name + ), "The test static method was moved or renamed. Please update the name accordingly" + + sentry_init(functions_to_trace=[{"qualified_name": test_staticmethod_name}]) + + for instance_or_class in (TracingTestClass, TracingTestClass()): + with patch_start_tracing_child() as fake_start_child: + assert instance_or_class.static(1) == 1 + fake_start_child.assert_called_once() + + +def test_classmethod_tracing(sentry_init): + test_classmethod_name = "tests.test_basics.TracingTestClass.class_" + assert ( + ".".join( + [TracingTestClass.class_.__module__, TracingTestClass.class_.__qualname__] + ) + == test_classmethod_name + ), "The test class method was moved or renamed. Please update the name accordingly" + + sentry_init(functions_to_trace=[{"qualified_name": test_classmethod_name}]) + + for instance_or_class in (TracingTestClass, TracingTestClass()): + with patch_start_tracing_child() as fake_start_child: + assert instance_or_class.class_(1) == (TracingTestClass, 1) + fake_start_child.assert_called_once() diff --git a/tests/tracing/test_decorator_py2.py b/tests/tracing/test_decorator_py2.py index 9969786623..1d62a35311 100644 --- a/tests/tracing/test_decorator_py2.py +++ b/tests/tracing/test_decorator_py2.py @@ -1,8 +1,14 @@ -from sentry_sdk.tracing_utils_py2 import ( - start_child_span_decorator as start_child_span_decorator_py2, -) +from sentry_sdk._compat import PY2 + +if PY2: + from sentry_sdk.tracing_utils_py2 import start_child_span_decorator +else: + from sentry_sdk.tracing_utils_py3 import start_child_span_decorator + from sentry_sdk.utils import logger +from tests.conftest import patch_start_tracing_child + try: from unittest import mock # python 3.3 and above except ImportError: @@ -13,39 +19,27 @@ def my_example_function(): return "return_of_sync_function" -def test_trace_decorator_py2(): - fake_start_child = mock.MagicMock() - fake_transaction = mock.MagicMock() - fake_transaction.start_child = fake_start_child - - with mock.patch( - "sentry_sdk.tracing_utils_py2.get_current_span", - return_value=fake_transaction, - ): +def test_trace_decorator(): + with patch_start_tracing_child() as fake_start_child: result = my_example_function() fake_start_child.assert_not_called() assert result == "return_of_sync_function" - result2 = start_child_span_decorator_py2(my_example_function)() + result2 = start_child_span_decorator(my_example_function)() fake_start_child.assert_called_once_with( op="function", description="test_decorator_py2.my_example_function" ) assert result2 == "return_of_sync_function" -def test_trace_decorator_py2_no_trx(): - fake_transaction = None - - with mock.patch( - "sentry_sdk.tracing_utils_py2.get_current_span", - return_value=fake_transaction, - ): +def test_trace_decorator_no_trx(): + with patch_start_tracing_child(fake_transaction=None): with mock.patch.object(logger, "warning", mock.Mock()) as fake_warning: result = my_example_function() fake_warning.assert_not_called() assert result == "return_of_sync_function" - result2 = start_child_span_decorator_py2(my_example_function)() + result2 = start_child_span_decorator(my_example_function)() fake_warning.assert_called_once_with( "Can not create a child span for %s. " "Please start a Sentry transaction before calling this function.", diff --git a/tests/tracing/test_decorator_py3.py b/tests/tracing/test_decorator_py3.py index 5b8a2d05b3..bb8d607981 100644 --- a/tests/tracing/test_decorator_py3.py +++ b/tests/tracing/test_decorator_py3.py @@ -1,8 +1,9 @@ from unittest import mock -from contextlib import contextmanager import pytest import sys +from tests.conftest import patch_start_tracing_child + from sentry_sdk.tracing_utils_py3 import ( start_child_span_decorator as start_child_span_decorator_py3, ) @@ -12,81 +13,13 @@ pytest.skip("Async decorator only works on Python 3.6+", allow_module_level=True) -class TestClass: - @staticmethod - def static(arg): - return arg - - @classmethod - def class_(cls, arg): - return cls, arg - - -def my_example_function(): - return "return_of_sync_function" - - async def my_async_example_function(): return "return_of_async_function" -@contextmanager -def patch_start_child(): - fake_start_child = mock.MagicMock() - fake_transaction = mock.MagicMock() - fake_transaction.start_child = fake_start_child - - with mock.patch( - "sentry_sdk.tracing_utils_py3.get_current_span", - return_value=fake_transaction, - ): - yield fake_start_child - - -def test_trace_decorator_sync_py3(): - with patch_start_child() as fake_start_child: - result = my_example_function() - fake_start_child.assert_not_called() - assert result == "return_of_sync_function" - - result2 = start_child_span_decorator_py3(my_example_function)() - fake_start_child.assert_called_once_with( - op="function", description="test_decorator_py3.my_example_function" - ) - assert result2 == "return_of_sync_function" - - -def test_trace_decorator_sync_py3_no_trx(): - fake_transaction = None - - with mock.patch( - "sentry_sdk.tracing_utils_py3.get_current_span", - return_value=fake_transaction, - ): - with mock.patch.object(logger, "warning", mock.Mock()) as fake_warning: - result = my_example_function() - fake_warning.assert_not_called() - assert result == "return_of_sync_function" - - result2 = start_child_span_decorator_py3(my_example_function)() - fake_warning.assert_called_once_with( - "Can not create a child span for %s. " - "Please start a Sentry transaction before calling this function.", - "test_decorator_py3.my_example_function", - ) - assert result2 == "return_of_sync_function" - - @pytest.mark.asyncio async def test_trace_decorator_async_py3(): - fake_start_child = mock.MagicMock() - fake_transaction = mock.MagicMock() - fake_transaction.start_child = fake_start_child - - with mock.patch( - "sentry_sdk.tracing_utils_py3.get_current_span", - return_value=fake_transaction, - ): + with patch_start_tracing_child() as fake_start_child: result = await my_async_example_function() fake_start_child.assert_not_called() assert result == "return_of_async_function" @@ -100,12 +33,7 @@ async def test_trace_decorator_async_py3(): @pytest.mark.asyncio async def test_trace_decorator_async_py3_no_trx(): - fake_transaction = None - - with mock.patch( - "sentry_sdk.tracing_utils_py3.get_current_span", - return_value=fake_transaction, - ): + with patch_start_tracing_child(fake_transaction=None): with mock.patch.object(logger, "warning", mock.Mock()) as fake_warning: result = await my_async_example_function() fake_warning.assert_not_called() @@ -118,33 +46,3 @@ async def test_trace_decorator_async_py3_no_trx(): "test_decorator_py3.my_async_example_function", ) assert result2 == "return_of_async_function" - - -def test_staticmethod_patching(sentry_init): - test_staticmethod_name = "test_decorator_py3.TestClass.static" - assert ( - ".".join([TestClass.static.__module__, TestClass.static.__qualname__]) - == test_staticmethod_name - ), "The test static method was moved or renamed. Please update the name accordingly" - - sentry_init(functions_to_trace=[{"qualified_name": test_staticmethod_name}]) - - for instance_or_class in (TestClass, TestClass()): - with patch_start_child() as fake_start_child: - assert instance_or_class.static(1) == 1 - fake_start_child.assert_called_once() - - -def test_classmethod_patching(sentry_init): - test_classmethod_name = "test_decorator_py3.TestClass.class_" - assert ( - ".".join([TestClass.class_.__module__, TestClass.class_.__qualname__]) - == test_classmethod_name - ), "The test class method was moved or renamed. Please update the name accordingly" - - sentry_init(functions_to_trace=[{"qualified_name": test_classmethod_name}]) - - for instance_or_class in (TestClass, TestClass()): - with patch_start_child() as fake_start_child: - assert instance_or_class.class_(1) == (TestClass, 1) - fake_start_child.assert_called_once() From 056b30a5115f4b854cadc4cdd6b878633f9479c1 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 27 Dec 2023 11:08:57 -0500 Subject: [PATCH 05/16] Rename decorator tests --- .../{test_decorator_py3.py => test_decorator_async_py3.py} | 0 tests/tracing/{test_decorator_py2.py => test_decorator_sync.py} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/tracing/{test_decorator_py3.py => test_decorator_async_py3.py} (100%) rename tests/tracing/{test_decorator_py2.py => test_decorator_sync.py} (100%) diff --git a/tests/tracing/test_decorator_py3.py b/tests/tracing/test_decorator_async_py3.py similarity index 100% rename from tests/tracing/test_decorator_py3.py rename to tests/tracing/test_decorator_async_py3.py diff --git a/tests/tracing/test_decorator_py2.py b/tests/tracing/test_decorator_sync.py similarity index 100% rename from tests/tracing/test_decorator_py2.py rename to tests/tracing/test_decorator_sync.py From 38138cc3caae269deba9cbda695281ef09ddccfe Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 27 Dec 2023 11:15:22 -0500 Subject: [PATCH 06/16] Restore incorrectly deleted file --- tests/tracing/test_decorator_py3.py | 48 +++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 tests/tracing/test_decorator_py3.py diff --git a/tests/tracing/test_decorator_py3.py b/tests/tracing/test_decorator_py3.py new file mode 100644 index 0000000000..bb8d607981 --- /dev/null +++ b/tests/tracing/test_decorator_py3.py @@ -0,0 +1,48 @@ +from unittest import mock +import pytest +import sys + +from tests.conftest import patch_start_tracing_child + +from sentry_sdk.tracing_utils_py3 import ( + start_child_span_decorator as start_child_span_decorator_py3, +) +from sentry_sdk.utils import logger + +if sys.version_info < (3, 6): + pytest.skip("Async decorator only works on Python 3.6+", allow_module_level=True) + + +async def my_async_example_function(): + return "return_of_async_function" + + +@pytest.mark.asyncio +async def test_trace_decorator_async_py3(): + with patch_start_tracing_child() as fake_start_child: + result = await my_async_example_function() + fake_start_child.assert_not_called() + assert result == "return_of_async_function" + + result2 = await start_child_span_decorator_py3(my_async_example_function)() + fake_start_child.assert_called_once_with( + op="function", description="test_decorator_py3.my_async_example_function" + ) + assert result2 == "return_of_async_function" + + +@pytest.mark.asyncio +async def test_trace_decorator_async_py3_no_trx(): + with patch_start_tracing_child(fake_transaction=None): + with mock.patch.object(logger, "warning", mock.Mock()) as fake_warning: + result = await my_async_example_function() + fake_warning.assert_not_called() + assert result == "return_of_async_function" + + result2 = await start_child_span_decorator_py3(my_async_example_function)() + fake_warning.assert_called_once_with( + "Can not create a child span for %s. " + "Please start a Sentry transaction before calling this function.", + "test_decorator_py3.my_async_example_function", + ) + assert result2 == "return_of_async_function" From 8a99a8b5b89f9d654fdd6046df1e3124bc48a924 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 27 Dec 2023 11:15:43 -0500 Subject: [PATCH 07/16] Delete incorrectly renamed file --- tests/tracing/test_decorator_async_py3.py | 48 ----------------------- 1 file changed, 48 deletions(-) delete mode 100644 tests/tracing/test_decorator_async_py3.py diff --git a/tests/tracing/test_decorator_async_py3.py b/tests/tracing/test_decorator_async_py3.py deleted file mode 100644 index bb8d607981..0000000000 --- a/tests/tracing/test_decorator_async_py3.py +++ /dev/null @@ -1,48 +0,0 @@ -from unittest import mock -import pytest -import sys - -from tests.conftest import patch_start_tracing_child - -from sentry_sdk.tracing_utils_py3 import ( - start_child_span_decorator as start_child_span_decorator_py3, -) -from sentry_sdk.utils import logger - -if sys.version_info < (3, 6): - pytest.skip("Async decorator only works on Python 3.6+", allow_module_level=True) - - -async def my_async_example_function(): - return "return_of_async_function" - - -@pytest.mark.asyncio -async def test_trace_decorator_async_py3(): - with patch_start_tracing_child() as fake_start_child: - result = await my_async_example_function() - fake_start_child.assert_not_called() - assert result == "return_of_async_function" - - result2 = await start_child_span_decorator_py3(my_async_example_function)() - fake_start_child.assert_called_once_with( - op="function", description="test_decorator_py3.my_async_example_function" - ) - assert result2 == "return_of_async_function" - - -@pytest.mark.asyncio -async def test_trace_decorator_async_py3_no_trx(): - with patch_start_tracing_child(fake_transaction=None): - with mock.patch.object(logger, "warning", mock.Mock()) as fake_warning: - result = await my_async_example_function() - fake_warning.assert_not_called() - assert result == "return_of_async_function" - - result2 = await start_child_span_decorator_py3(my_async_example_function)() - fake_warning.assert_called_once_with( - "Can not create a child span for %s. " - "Please start a Sentry transaction before calling this function.", - "test_decorator_py3.my_async_example_function", - ) - assert result2 == "return_of_async_function" From 94bb77c77094ddab7449ffe30e354a3a91739311 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 27 Dec 2023 11:16:24 -0500 Subject: [PATCH 08/16] Rename py3 decorator test --- .../{test_decorator_py3.py => test_decorator_async_py3.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/tracing/{test_decorator_py3.py => test_decorator_async_py3.py} (100%) diff --git a/tests/tracing/test_decorator_py3.py b/tests/tracing/test_decorator_async_py3.py similarity index 100% rename from tests/tracing/test_decorator_py3.py rename to tests/tracing/test_decorator_async_py3.py From 419628eceaa4d6c25813e1cbc1eab37fca92122e Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 27 Dec 2023 12:48:49 -0500 Subject: [PATCH 09/16] Correct decorator tests for new file name --- tests/tracing/test_decorator_async_py3.py | 5 +++-- tests/tracing/test_decorator_sync.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/tracing/test_decorator_async_py3.py b/tests/tracing/test_decorator_async_py3.py index bb8d607981..6afcfdf229 100644 --- a/tests/tracing/test_decorator_async_py3.py +++ b/tests/tracing/test_decorator_async_py3.py @@ -26,7 +26,8 @@ async def test_trace_decorator_async_py3(): result2 = await start_child_span_decorator_py3(my_async_example_function)() fake_start_child.assert_called_once_with( - op="function", description="test_decorator_py3.my_async_example_function" + op="function", + description="test_decorator_async_py3.my_async_example_function", ) assert result2 == "return_of_async_function" @@ -43,6 +44,6 @@ async def test_trace_decorator_async_py3_no_trx(): fake_warning.assert_called_once_with( "Can not create a child span for %s. " "Please start a Sentry transaction before calling this function.", - "test_decorator_py3.my_async_example_function", + "test_decorator_async_py3.my_async_example_function", ) assert result2 == "return_of_async_function" diff --git a/tests/tracing/test_decorator_sync.py b/tests/tracing/test_decorator_sync.py index 1d62a35311..ff129a79bf 100644 --- a/tests/tracing/test_decorator_sync.py +++ b/tests/tracing/test_decorator_sync.py @@ -27,7 +27,7 @@ def test_trace_decorator(): result2 = start_child_span_decorator(my_example_function)() fake_start_child.assert_called_once_with( - op="function", description="test_decorator_py2.my_example_function" + op="function", description="test_decorator_sync.my_example_function" ) assert result2 == "return_of_sync_function" From bd5d43e0ba4392d68bf0d4f1739bd73ce0673e9b Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 27 Dec 2023 13:14:14 -0500 Subject: [PATCH 10/16] Fix CI errors --- tests/conftest.py | 8 +++++--- tests/tracing/test_decorator_async_py3.py | 2 +- tests/tracing/test_decorator_sync.py | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 654e0559d5..85c65462cb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -635,12 +635,14 @@ def werkzeug_set_cookie(client, servername, key, value): @contextmanager -def patch_start_tracing_child(fake_transaction=mock.MagicMock()): - # type: (Optional[mock.MagicMock]) -> Iterator[Optional[mock.MagicMock]] - if fake_transaction is not None: +def patch_start_tracing_child(fake_transaction_is_none=False): + # type: (bool) -> Iterator[Optional[mock.MagicMock]] + if not fake_transaction_is_none: + fake_transaction = mock.MagicMock() fake_start_child = mock.MagicMock() fake_transaction.start_child = fake_start_child else: + fake_transaction = None fake_start_child = None version = "2" if PY2 else "3" diff --git a/tests/tracing/test_decorator_async_py3.py b/tests/tracing/test_decorator_async_py3.py index 6afcfdf229..401180ad39 100644 --- a/tests/tracing/test_decorator_async_py3.py +++ b/tests/tracing/test_decorator_async_py3.py @@ -34,7 +34,7 @@ async def test_trace_decorator_async_py3(): @pytest.mark.asyncio async def test_trace_decorator_async_py3_no_trx(): - with patch_start_tracing_child(fake_transaction=None): + with patch_start_tracing_child(fake_transaction_is_none=True): with mock.patch.object(logger, "warning", mock.Mock()) as fake_warning: result = await my_async_example_function() fake_warning.assert_not_called() diff --git a/tests/tracing/test_decorator_sync.py b/tests/tracing/test_decorator_sync.py index ff129a79bf..badfb4eae8 100644 --- a/tests/tracing/test_decorator_sync.py +++ b/tests/tracing/test_decorator_sync.py @@ -33,7 +33,7 @@ def test_trace_decorator(): def test_trace_decorator_no_trx(): - with patch_start_tracing_child(fake_transaction=None): + with patch_start_tracing_child(fake_transaction_is_none=True): with mock.patch.object(logger, "warning", mock.Mock()) as fake_warning: result = my_example_function() fake_warning.assert_not_called() From 20c17c4e3aa3efecf36395e0e5c98d13a4aa2943 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 27 Dec 2023 13:50:35 -0500 Subject: [PATCH 11/16] Removed unused `type: ignore` comments --- sentry_sdk/integrations/aiohttp.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sentry_sdk/integrations/aiohttp.py b/sentry_sdk/integrations/aiohttp.py index c9ff2a5301..58fe09bf1e 100644 --- a/sentry_sdk/integrations/aiohttp.py +++ b/sentry_sdk/integrations/aiohttp.py @@ -141,7 +141,7 @@ async def sentry_app_handle(self, request, *args, **kwargs): transaction.set_http_status(response.status) return response - Application._handle = sentry_app_handle # type: ignore[method-assign] + Application._handle = sentry_app_handle old_urldispatcher_resolve = UrlDispatcher.resolve @@ -173,7 +173,7 @@ async def sentry_urldispatcher_resolve(self, request): return rv - UrlDispatcher.resolve = sentry_urldispatcher_resolve # type: ignore[method-assign] + UrlDispatcher.resolve = sentry_urldispatcher_resolve old_client_session_init = ClientSession.__init__ @@ -190,7 +190,7 @@ def init(*args, **kwargs): kwargs["trace_configs"] = client_trace_configs return old_client_session_init(*args, **kwargs) - ClientSession.__init__ = init # type: ignore[method-assign] + ClientSession.__init__ = init def create_trace_config(): From 7d064f3f2d370556f9e3be9aedcc63e4a6695c0b Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 27 Dec 2023 14:35:13 -0500 Subject: [PATCH 12/16] Fix test failures (hopefully) --- tests/tracing/test_decorator_sync.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tracing/test_decorator_sync.py b/tests/tracing/test_decorator_sync.py index badfb4eae8..6d7be8b8f9 100644 --- a/tests/tracing/test_decorator_sync.py +++ b/tests/tracing/test_decorator_sync.py @@ -43,6 +43,6 @@ def test_trace_decorator_no_trx(): fake_warning.assert_called_once_with( "Can not create a child span for %s. " "Please start a Sentry transaction before calling this function.", - "test_decorator_py2.my_example_function", + "test_decorator_sync.my_example_function", ) assert result2 == "return_of_sync_function" From 40cb9ca3afd3cc639aca672b5d1d49be7c5b3779 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 27 Dec 2023 14:49:41 -0500 Subject: [PATCH 13/16] Change `assert_called_once` to `assert_called_once_with` --- tests/test_basics.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_basics.py b/tests/test_basics.py index 1b80270c16..2008c2a54b 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -764,7 +764,7 @@ def test_staticmethod_tracing(sentry_init): for instance_or_class in (TracingTestClass, TracingTestClass()): with patch_start_tracing_child() as fake_start_child: assert instance_or_class.static(1) == 1 - fake_start_child.assert_called_once() + fake_start_child.assert_called_once_with() def test_classmethod_tracing(sentry_init): @@ -781,4 +781,4 @@ def test_classmethod_tracing(sentry_init): for instance_or_class in (TracingTestClass, TracingTestClass()): with patch_start_tracing_child() as fake_start_child: assert instance_or_class.class_(1) == (TracingTestClass, 1) - fake_start_child.assert_called_once() + fake_start_child.assert_called_once_with() From d296a32432786fbb3e1f3cd2e8b3aa9cac71b8ad Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 27 Dec 2023 14:56:11 -0500 Subject: [PATCH 14/16] Change to call_count check --- tests/test_basics.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_basics.py b/tests/test_basics.py index 2008c2a54b..b6537b4fd3 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -764,7 +764,7 @@ def test_staticmethod_tracing(sentry_init): for instance_or_class in (TracingTestClass, TracingTestClass()): with patch_start_tracing_child() as fake_start_child: assert instance_or_class.static(1) == 1 - fake_start_child.assert_called_once_with() + assert fake_start_child.call_counnt == 1 def test_classmethod_tracing(sentry_init): @@ -781,4 +781,4 @@ def test_classmethod_tracing(sentry_init): for instance_or_class in (TracingTestClass, TracingTestClass()): with patch_start_tracing_child() as fake_start_child: assert instance_or_class.class_(1) == (TracingTestClass, 1) - fake_start_child.assert_called_once_with() + assert fake_start_child.call_count == 1 From e2b915db47f4e353c3dc56c401b6f53623837d15 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 27 Dec 2023 15:02:45 -0500 Subject: [PATCH 15/16] Only use `__qualname__` in Python 3 --- tests/test_basics.py | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/tests/test_basics.py b/tests/test_basics.py index b6537b4fd3..cbed4e39f9 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -19,7 +19,7 @@ last_event_id, Hub, ) -from sentry_sdk._compat import reraise +from sentry_sdk._compat import reraise, PY2 from sentry_sdk.integrations import ( _AUTO_ENABLING_INTEGRATIONS, Integration, @@ -752,12 +752,18 @@ def class_(cls, arg): def test_staticmethod_tracing(sentry_init): test_staticmethod_name = "tests.test_basics.TracingTestClass.static" - assert ( - ".".join( - [TracingTestClass.static.__module__, TracingTestClass.static.__qualname__] - ) - == test_staticmethod_name - ), "The test static method was moved or renamed. Please update the name accordingly" + if not PY2: + # Skip this check on Python 2 since __qualname__ is available in Python 3 only. Skipping is okay, + # since the assertion would be expected to fail in Python 3 if there is any problem. + assert ( + ".".join( + [ + TracingTestClass.static.__module__, + TracingTestClass.static.__qualname__, + ] + ) + == test_staticmethod_name + ), "The test static method was moved or renamed. Please update the name accordingly" sentry_init(functions_to_trace=[{"qualified_name": test_staticmethod_name}]) @@ -769,12 +775,18 @@ def test_staticmethod_tracing(sentry_init): def test_classmethod_tracing(sentry_init): test_classmethod_name = "tests.test_basics.TracingTestClass.class_" - assert ( - ".".join( - [TracingTestClass.class_.__module__, TracingTestClass.class_.__qualname__] - ) - == test_classmethod_name - ), "The test class method was moved or renamed. Please update the name accordingly" + if not PY2: + # Skip this check on Python 2 since __qualname__ is available in Python 3 only. Skipping is okay, + # since the assertion would be expected to fail in Python 3 if there is any problem. + assert ( + ".".join( + [ + TracingTestClass.class_.__module__, + TracingTestClass.class_.__qualname__, + ] + ) + == test_classmethod_name + ), "The test class method was moved or renamed. Please update the name accordingly" sentry_init(functions_to_trace=[{"qualified_name": test_classmethod_name}]) From 162816096e88f03049e07ac324c7643113b80fa2 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 27 Dec 2023 15:06:08 -0500 Subject: [PATCH 16/16] Correcting typo --- tests/test_basics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_basics.py b/tests/test_basics.py index cbed4e39f9..26dad73274 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -770,7 +770,7 @@ def test_staticmethod_tracing(sentry_init): for instance_or_class in (TracingTestClass, TracingTestClass()): with patch_start_tracing_child() as fake_start_child: assert instance_or_class.static(1) == 1 - assert fake_start_child.call_counnt == 1 + assert fake_start_child.call_count == 1 def test_classmethod_tracing(sentry_init):