Skip to content
Merged
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- `opentelemetry-instrumentation-pika` Use `ObjectProxy` instead of `BaseObjectProxy` for `ReadyMessagesDequeProxy` to restore iterability with wrapt 2.x
([#4461](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4461))
- `opentelemetry-instrumentation-dbapi` Use `ObjectProxy` instead of `BaseObjectProxy` for `TracedCursorProxy` to restore iterability with wrapt 2.x
([#4427](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4427))

### Breaking changes

Expand Down
1 change: 1 addition & 0 deletions docs-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ sqlalchemy>=1.0
starlette~=0.50
tornado>=5.1.1
tortoise-orm>=0.17.0
wrapt~=2.1

# required by opamp
uuid_utils
Expand Down
1 change: 1 addition & 0 deletions docs/nitpick-exceptions.ini
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ py-class=
psycopg.Connection
psycopg.AsyncConnection
ObjectProxy
wrapt.proxies.ObjectProxy
fastapi.applications.FastAPI
starlette.applications.Starlette
_contextvars.Token
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,12 @@

try:
# wrapt 2.0.0+
from wrapt import BaseObjectProxy # pylint: disable=no-name-in-module
from wrapt import ( # pylint: disable=no-name-in-module
BaseObjectProxy,
ObjectProxy,
)
except ImportError:
from wrapt import ObjectProxy
from wrapt import ObjectProxy as BaseObjectProxy

from opentelemetry import trace as trace_api
Expand Down Expand Up @@ -805,14 +809,14 @@ async def traced_execution_async(


# pylint: disable=abstract-method,no-member
class TracedCursorProxy(BaseObjectProxy, Generic[CursorT]):
class TracedCursorProxy(ObjectProxy, Generic[CursorT]):
# pylint: disable=unused-argument
def __init__(
self,
cursor: CursorT,
db_api_integration: DatabaseApiIntegration,
):
BaseObjectProxy.__init__(self, cursor)
ObjectProxy.__init__(self, cursor)
self._self_cursor_tracer = CursorTracer[CursorT](db_api_integration)

def execute(self, *args: Any, **kwargs: Any):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,20 @@ def test_executemany(self):
span = spans_list[0]
self.assertEqual(span.attributes[DB_STATEMENT], "Test query")

# pylint: disable=no-self-use
def test_executemany_iterable_cursor(self):
Comment thread
xrmx marked this conversation as resolved.
db_integration = dbapi.DatabaseApiIntegration(
"instrumenting_module_test_name", "testcomponent"
)
mock_connection = db_integration.wrapped_connection(
mock_connect, {}, {}
)
cursor = mock_connection.cursor()
cursor.executemany("Test query")

for _row in cursor:
Comment thread
xrmx marked this conversation as resolved.
pass

def test_executemany_comment(self):
connect_module = mock.MagicMock()
connect_module.__name__ = "test"
Expand Down Expand Up @@ -1296,13 +1310,17 @@ def __init__(self) -> None:
self._cnx._cmysql.get_client_info = mock.MagicMock(
return_value="1.2.3"
)
self._items = []

# pylint: disable=unused-argument, no-self-use
def execute(self, query, params=None, throw_exception=False):
if throw_exception:
# pylint: disable=broad-exception-raised
raise Exception("Test Exception")

def __iter__(self):
yield from self._items

# pylint: disable=unused-argument, no-self-use
def executemany(self, query, params=None, throw_exception=False):
if throw_exception:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,16 @@ def test_executemany(self):
self._cursor.executemany(stmt, data)
self.validate_spans("INSERT")

def test_executemany_with_cursor_iteration(self):
"""Should create a child span for executemany while iterating over the cursor"""
stmt = "SELECT * FROM test"
with self._tracer.start_as_current_span("rootSpan"):
with self._connection.cursor() as cursor:
cursor.execute(stmt)
for _row in cursor:
pass
self.validate_spans("SELECT")

def test_callproc(self):
"""Should create a child span for callproc"""
with (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ def test_executemany(self):
self._cursor.executemany(stmt, data)
self.validate_spans("INSERT")

def test_executemany_with_cursor_iteration(self):
"""Should create a child span for executemany while iterating over the cursor"""
stmt = "SELECT * FROM test"
with self._tracer.start_as_current_span("rootSpan"):
with self._connection.cursor() as cursor:
cursor.execute(stmt)
for _row in cursor:
pass
self.validate_spans("SELECT")

def test_callproc(self):
"""Should create a child span for callproc"""
with (
Expand Down
Loading