summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>2020-04-06 02:30:29 +1200
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>2020-04-06 14:10:02 +1200
commit62743c3be1de686154c3c927f1d6df99e5203b39 (patch)
tree0e126cb17a4520b3a59b385c84df51d9fc5e7d0b
parent2bee47efacd3c114fd93ce84880f91799b0b72af (diff)
downloadpsycopg2-62743c3be1de686154c3c927f1d6df99e5203b39.tar.gz
Fixed copy() on DictRowfix-1073
Close #1073.
-rw-r--r--NEWS1
-rw-r--r--lib/extras.py8
-rwxr-xr-xtests/test_extras_dictcursor.py29
3 files changed, 37 insertions, 1 deletions
diff --git a/NEWS b/NEWS
index 29aef12..4cab5cf 100644
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,7 @@ What's new in psycopg 2.8.5
`~psycopg2.extras.LoggingConnection` (:ticket:`#1026`).
- `~psycopg2.extensions.Column` objects in `cursor.description` can be sliced
(:ticket:`#1034`).
+- Fixed `~copy.copy()` of `~psycopg2.extras.DictCursor` rows (:ticket:`#1073`).
What's new in psycopg 2.8.4
diff --git a/lib/extras.py b/lib/extras.py
index 85c1a44..ccb8b3f 100644
--- a/lib/extras.py
+++ b/lib/extras.py
@@ -196,6 +196,10 @@ class DictRow(list):
def __contains__(self, x):
return x in self._index
+ def __reduce__(self):
+ # this is apparently useless, but it fixes #1073
+ return super(DictRow, self).__reduce__()
+
def __getstate__(self):
return self[:], self._index.copy()
@@ -392,6 +396,7 @@ class NamedTupleCursor(_cursor):
def _cached_make_nt(cls, key):
return cls._do_make_nt(key)
+
# Exposed for testability, and if someone wants to monkeypatch to tweak
# the cache size.
NamedTupleCursor._cached_make_nt = classmethod(_cached_make_nt)
@@ -410,7 +415,8 @@ class LoggingConnection(_connection):
instance from the standard logging module.
"""
self._logobj = logobj
- if _logging and isinstance(logobj, (_logging.Logger, _logging.LoggerAdapter)):
+ if _logging and isinstance(
+ logobj, (_logging.Logger, _logging.LoggerAdapter)):
self.log = self._logtologger
else:
self.log = self._logtofile
diff --git a/tests/test_extras_dictcursor.py b/tests/test_extras_dictcursor.py
index d4bb12f..180d996 100755
--- a/tests/test_extras_dictcursor.py
+++ b/tests/test_extras_dictcursor.py
@@ -15,6 +15,7 @@
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
+import copy
import time
import pickle
import unittest
@@ -158,6 +159,20 @@ class ExtrasDictCursorTests(_DictCursorBase):
self.assertEqual(r['b'], r1['b'])
self.assertEqual(r._index, r1._index)
+ def test_copy(self):
+ curs = self.conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
+ curs.execute("select 10 as foo, 'hi' as bar")
+ rv = curs.fetchone()
+ self.assertEqual(len(rv), 2)
+
+ rv2 = copy.copy(rv)
+ self.assertEqual(len(rv2), 2)
+ self.assertEqual(len(rv), 2)
+
+ rv3 = copy.deepcopy(rv)
+ self.assertEqual(len(rv3), 2)
+ self.assertEqual(len(rv), 2)
+
@skip_from_python(3)
def test_iter_methods_2(self):
curs = self.conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
@@ -267,6 +282,20 @@ class ExtrasDictCursorRealTests(_DictCursorBase):
self.assertEqual(r['a'], r1['a'])
self.assertEqual(r['b'], r1['b'])
+ def test_copy(self):
+ curs = self.conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
+ curs.execute("select 10 as foo, 'hi' as bar")
+ rv = curs.fetchone()
+ self.assertEqual(len(rv), 2)
+
+ rv2 = copy.copy(rv)
+ self.assertEqual(len(rv2), 2)
+ self.assertEqual(len(rv), 2)
+
+ rv3 = copy.deepcopy(rv)
+ self.assertEqual(len(rv3), 2)
+ self.assertEqual(len(rv), 2)
+
def testDictCursorRealWithNamedCursorFetchOne(self):
self._testWithNamedCursorReal(lambda curs: curs.fetchone())