Skip to content

Commit 4d8a8cc

Browse files
Kyle-VerhoogEmanuele Palazzetti
authored andcommitted
[psycopg2] fix for quote_ident typing bug (#477)
* [psycopg2] replicate incorrect connection type bug * [psycopg2] add manual quote_ident extension * [psycopg2] reorder patching and imports
1 parent fa61c2d commit 4d8a8cc

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

ddtrace/contrib/psycopg/patch.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,17 @@ def _unroll_args(obj, scope=None):
9393

9494
return func(obj, scope) if scope else func(obj)
9595

96+
def _extensions_quote_ident(func, _, args, kwargs):
97+
def _unroll_args(obj, scope=None):
98+
return obj, scope
99+
obj, scope = _unroll_args(*args, **kwargs)
100+
101+
# register_type performs a c-level check of the object
102+
# type so we must be sure to pass in the actual db connection
103+
if scope and isinstance(scope, wrapt.ObjectProxy):
104+
scope = scope.__wrapped__
105+
106+
return func(obj, scope) if scope else func(obj)
96107

97108
def _extensions_adapt(func, _, args, kwargs):
98109
adapt = func(*args, **kwargs)
@@ -136,3 +147,11 @@ def prepare(self, *args, **kwargs):
136147
psycopg2._json, 'register_type',
137148
_extensions_register_type),
138149
]
150+
151+
# `quote_ident` attribute is only available for psycopg >= 2.7
152+
if getattr(psycopg2, 'extensions', None) and getattr(psycopg2.extensions,
153+
'quote_ident', None):
154+
_psycopg2_extensions += [(psycopg2.extensions.quote_ident,
155+
psycopg2.extensions, 'quote_ident',
156+
_extensions_quote_ident),
157+
]

tests/contrib/psycopg/test_psycopg.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222

2323
PSYCOPG_VERSION = tuple(map(int, psycopg2.__version__.split()[0].split('.')))
2424
TEST_PORT = str(POSTGRES_CONFIG['port'])
25-
26-
2725
class PsycopgCore(object):
2826

2927
# default service
@@ -126,7 +124,6 @@ def test_manual_wrap_extension_types(self):
126124
# TypeError: argument 2 must be a connection, cursor or None
127125
extras.register_default_json(conn)
128126

129-
130127
def test_manual_wrap_extension_adapt(self):
131128
conn, _ = self._get_conn_and_tracer()
132129
# NOTE: this will crash if it doesn't work.
@@ -143,6 +140,17 @@ def test_manual_wrap_extension_adapt(self):
143140
binary = extensions.adapt(b'12345')
144141
binary.prepare(conn)
145142

143+
@skipIf(PSYCOPG_VERSION < (2, 7), 'quote_ident not available in psycopg2<2.7')
144+
def test_manual_wrap_extension_quote_ident(self):
145+
from ddtrace import patch_all
146+
patch_all()
147+
from psycopg2.extensions import quote_ident
148+
149+
# NOTE: this will crash if it doesn't work.
150+
# TypeError: argument 2 must be a connection or a cursor
151+
conn = psycopg2.connect(**POSTGRES_CONFIG)
152+
quote_ident('foo', conn)
153+
146154
def test_connect_factory(self):
147155
tracer = get_dummy_tracer()
148156

@@ -214,9 +222,21 @@ def test_patch_unpatch(self):
214222
assert spans, spans
215223
eq_(len(spans), 1)
216224

225+
217226
def test_backwards_compatibilty_v3():
218227
tracer = get_dummy_tracer()
219228
factory = connection_factory(tracer, service="my-postgres-db")
220229
conn = psycopg2.connect(connection_factory=factory, **POSTGRES_CONFIG)
221230
conn.cursor().execute("select 'blah'")
222231

232+
233+
@skipIf(PSYCOPG_VERSION < (2, 7), 'quote_ident not available in psycopg2<2.7')
234+
def test_manual_wrap_extension_quote_ident_standalone():
235+
from ddtrace import patch_all
236+
patch_all()
237+
from psycopg2.extensions import quote_ident
238+
239+
# NOTE: this will crash if it doesn't work.
240+
# TypeError: argument 2 must be a connection or a cursor
241+
conn = psycopg2.connect(**POSTGRES_CONFIG)
242+
quote_ident('foo', conn)

0 commit comments

Comments
 (0)