diff --git a/CHANGELOG.md b/CHANGELOG.md index e991ae533a..a01a986bcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#4006](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4006)) - `opentelemetry-instrumentation-flask`: Add support for 3.1+ streaming responses ([#3938](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3938)) +- `opentelemetry-instrumentation`: Add support for wrapt 2 + ([#4082](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4082)) - `opentelemetry-instrumentation-aiohttp-server`: Support passing `TracerProvider` when instrumenting. ([#3819](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3819)) - `opentelemetry-instrumentation-system-metrics`: Add support for the `OTEL_PYTHON_SYSTEM_METRICS_EXCLUDED_METRICS` environment variable diff --git a/opentelemetry-instrumentation/pyproject.toml b/opentelemetry-instrumentation/pyproject.toml index 0e5820e0d7..0773a736dd 100644 --- a/opentelemetry-instrumentation/pyproject.toml +++ b/opentelemetry-instrumentation/pyproject.toml @@ -27,7 +27,7 @@ classifiers = [ dependencies = [ "opentelemetry-api ~= 1.4", "opentelemetry-semantic-conventions == 0.61b0.dev", - "wrapt >= 1.0.0, < 2.0.0", + "wrapt >= 1.0.0", "packaging >= 18.0", ] diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/utils.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/utils.py index e38932e28d..9e3929f049 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/utils.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/utils.py @@ -20,7 +20,10 @@ from re import escape, sub from typing import Any, Dict, Generator, Sequence -from wrapt import ObjectProxy +try: + from wrapt import BaseObjectProxy +except ImportError: + from wrapt import ObjectProxy as BaseObjectProxy from opentelemetry import context, trace @@ -108,7 +111,7 @@ def unwrap(obj: object, attr: str): ) from exc func = getattr(obj, attr, None) - if func and isinstance(func, ObjectProxy) and hasattr(func, "__wrapped__"): + if func and isinstance(func, BaseObjectProxy) and hasattr(func, "__wrapped__"): setattr(obj, attr, func.__wrapped__) diff --git a/opentelemetry-instrumentation/tests/test_utils.py b/opentelemetry-instrumentation/tests/test_utils.py index 5ddd45d692..8cd3a77e7f 100644 --- a/opentelemetry-instrumentation/tests/test_utils.py +++ b/opentelemetry-instrumentation/tests/test_utils.py @@ -15,7 +15,11 @@ import unittest from http import HTTPStatus -from wrapt import ObjectProxy, wrap_function_wrapper +from wrapt import wrap_function_wrapper +try: + from wrapt import BaseObjectProxy +except ImportError: + from wrapt import ObjectProxy as BaseObjectProxy from opentelemetry.context import ( _SUPPRESS_HTTP_INSTRUMENTATION_KEY, @@ -263,23 +267,23 @@ def _wrap_method(): def test_can_unwrap_object_attribute(self): self._wrap_method() instance = WrappedClass() - self.assertTrue(isinstance(instance.method, ObjectProxy)) + self.assertTrue(isinstance(instance.method, BaseObjectProxy)) unwrap(WrappedClass, "method") - self.assertFalse(isinstance(instance.method, ObjectProxy)) + self.assertFalse(isinstance(instance.method, BaseObjectProxy)) def test_can_unwrap_object_attribute_as_string(self): self._wrap_method() instance = WrappedClass() - self.assertTrue(isinstance(instance.method, ObjectProxy)) + self.assertTrue(isinstance(instance.method, BaseObjectProxy)) unwrap("tests.test_utils.WrappedClass", "method") - self.assertFalse(isinstance(instance.method, ObjectProxy)) + self.assertFalse(isinstance(instance.method, BaseObjectProxy)) def test_raises_import_error_if_path_not_well_formed(self): self._wrap_method() instance = WrappedClass() - self.assertTrue(isinstance(instance.method, ObjectProxy)) + self.assertTrue(isinstance(instance.method, BaseObjectProxy)) with self.assertRaisesRegex( ImportError, "Cannot parse '' as dotted import path" @@ -287,23 +291,23 @@ def test_raises_import_error_if_path_not_well_formed(self): unwrap("", "method") unwrap(WrappedClass, "method") - self.assertFalse(isinstance(instance.method, ObjectProxy)) + self.assertFalse(isinstance(instance.method, BaseObjectProxy)) def test_raises_import_error_if_cannot_find_module(self): self._wrap_method() instance = WrappedClass() - self.assertTrue(isinstance(instance.method, ObjectProxy)) + self.assertTrue(isinstance(instance.method, BaseObjectProxy)) with self.assertRaisesRegex(ImportError, "No module named 'does'"): unwrap("does.not.exist.WrappedClass", "method") unwrap(WrappedClass, "method") - self.assertFalse(isinstance(instance.method, ObjectProxy)) + self.assertFalse(isinstance(instance.method, BaseObjectProxy)) def test_raises_import_error_if_cannot_find_object(self): self._wrap_method() instance = WrappedClass() - self.assertTrue(isinstance(instance.method, ObjectProxy)) + self.assertTrue(isinstance(instance.method, BaseObjectProxy)) with self.assertRaisesRegex( ImportError, "Cannot import 'NotWrappedClass' from" @@ -311,7 +315,7 @@ def test_raises_import_error_if_cannot_find_object(self): unwrap("tests.test_utils.NotWrappedClass", "method") unwrap(WrappedClass, "method") - self.assertFalse(isinstance(instance.method, ObjectProxy)) + self.assertFalse(isinstance(instance.method, BaseObjectProxy)) # pylint: disable=no-self-use def test_does_nothing_if_cannot_find_attribute(self): @@ -320,6 +324,6 @@ def test_does_nothing_if_cannot_find_attribute(self): def test_does_nothing_if_attribute_is_not_from_wrapt(self): instance = WrappedClass() - self.assertFalse(isinstance(instance.method, ObjectProxy)) + self.assertFalse(isinstance(instance.method, BaseObjectProxy)) unwrap(WrappedClass, "method") - self.assertFalse(isinstance(instance.method, ObjectProxy)) + self.assertFalse(isinstance(instance.method, BaseObjectProxy))