Skip to content

Commit 2947d5b

Browse files
authored
fix(dbapi): add iterable methods to object proxy (backport #4205) (#4281)
This is an automatic backport of pull request #4205 done by [Mergify](https://mergify.com). --- <details> <summary>Mergify commands and options</summary> <br /> More conditions and actions can be found in the [documentation](https://docs.mergify.com/). You can also trigger Mergify actions by commenting on this pull request: - `@Mergifyio refresh` will re-evaluate the rules - `@Mergifyio rebase` will rebase this PR on its base branch - `@Mergifyio update` will merge the base branch into this PR - `@Mergifyio backport <destination>` will backport this PR on `<destination>` branch Additionally, on Mergify [dashboard](https://dashboard.mergify.com/) you can: - look at your merge queues - generate the Mergify configuration with the config editor. Finally, you can contact us on https://mergify.com </details>
1 parent 4c080ae commit 2947d5b

File tree

4 files changed

+39
-0
lines changed

4 files changed

+39
-0
lines changed

ddtrace/contrib/dbapi/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from ...constants import SPAN_MEASURED_KEY
1010
from ...ext import SpanTypes
1111
from ...ext import sql
12+
from ...internal.compat import PY2
1213
from ...internal.logger import get_logger
1314
from ...internal.utils import ArgumentError
1415
from ...internal.utils import get_argument_value
@@ -47,6 +48,18 @@ def __init__(self, cursor, pin, cfg):
4748
self._self_last_execute_operation = None
4849
self._self_config = cfg or config.dbapi2
4950

51+
def __iter__(self):
52+
return self.__wrapped__.__iter__()
53+
54+
def __next__(self):
55+
return self.__wrapped__.__next__()
56+
57+
if PY2:
58+
59+
# Python 2 iterators use `next`
60+
def next(self): # noqa: A001
61+
return self.__wrapped__.next()
62+
5063
def _trace_method(self, method, name, resource, extra_tags, *args, **kwargs):
5164
"""
5265
Internal function to trace the call to the underlying cursor method

docs/spelling_wordlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ initializer
9494
integration
9595
integrations
9696
ip
97+
iterable
9798
JSON
9899
jinja
99100
js
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
fixes:
3+
- |
4+
Add iterable methods on TracedCursor. Previously these were not present and would cause iterable usage of
5+
cursors in DB API integrations to fail.

tests/contrib/sqlite3/test_sqlite3.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import sqlite3
22
import time
3+
from typing import TYPE_CHECKING
34

45
import pytest
56

@@ -18,6 +19,19 @@
1819
from tests.utils import assert_is_not_measured
1920

2021

22+
if TYPE_CHECKING:
23+
from typing import Generator
24+
25+
26+
@pytest.fixture
27+
def patched_conn():
28+
# type: () -> Generator[sqlite3.Cursor, None, None]
29+
patch()
30+
conn = sqlite3.connect(":memory:")
31+
yield conn
32+
unpatch()
33+
34+
2135
class TestSQLite(TracerTestCase):
2236
def setUp(self):
2337
super(TestSQLite, self).setUp()
@@ -351,3 +365,9 @@ def test_context_manager(self):
351365
cursor.fetchall()
352366
spans = self.get_spans()
353367
assert len(spans) == 1
368+
369+
370+
def test_iterator_usage(patched_conn):
371+
"""Ensure sqlite3 patched cursors can be used as iterators."""
372+
rows = next(patched_conn.execute("select 1"))
373+
assert len(rows) == 1

0 commit comments

Comments
 (0)