Fixed copy() on DictRow

Close #1073.
This commit is contained in:
Daniele Varrazzo 2020-04-06 02:30:29 +12:00
parent 2bee47efac
commit 62743c3be1
3 changed files with 37 additions and 1 deletions

1
NEWS
View File

@ -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

View File

@ -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

View File

@ -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())