make operations on closed dumb databases raise a consistent exception (closes #19385)
Patch by Claudiu Popa.
This commit is contained in:
parent
d4992dccfb
commit
e3083d3ad5
|
@ -118,9 +118,14 @@ class _Database(collections.MutableMapping):
|
|||
|
||||
sync = _commit
|
||||
|
||||
def _verify_open(self):
|
||||
if self._index is None:
|
||||
raise error('DBM object has already been closed')
|
||||
|
||||
def __getitem__(self, key):
|
||||
if isinstance(key, str):
|
||||
key = key.encode('utf-8')
|
||||
self._verify_open()
|
||||
pos, siz = self._index[key] # may raise KeyError
|
||||
f = _io.open(self._datfile, 'rb')
|
||||
f.seek(pos)
|
||||
|
@ -173,6 +178,7 @@ class _Database(collections.MutableMapping):
|
|||
val = val.encode('utf-8')
|
||||
elif not isinstance(val, (bytes, bytearray)):
|
||||
raise TypeError("values must be bytes or strings")
|
||||
self._verify_open()
|
||||
if key not in self._index:
|
||||
self._addkey(key, self._addval(val))
|
||||
else:
|
||||
|
@ -200,6 +206,7 @@ class _Database(collections.MutableMapping):
|
|||
def __delitem__(self, key):
|
||||
if isinstance(key, str):
|
||||
key = key.encode('utf-8')
|
||||
self._verify_open()
|
||||
# The blocks used by the associated value are lost.
|
||||
del self._index[key]
|
||||
# XXX It's unclear why we do a _commit() here (the code always
|
||||
|
@ -209,21 +216,26 @@ class _Database(collections.MutableMapping):
|
|||
self._commit()
|
||||
|
||||
def keys(self):
|
||||
self._verify_open()
|
||||
return list(self._index.keys())
|
||||
|
||||
def items(self):
|
||||
self._verify_open()
|
||||
return [(key, self[key]) for key in self._index.keys()]
|
||||
|
||||
def __contains__(self, key):
|
||||
if isinstance(key, str):
|
||||
key = key.encode('utf-8')
|
||||
self._verify_open()
|
||||
return key in self._index
|
||||
|
||||
def iterkeys(self):
|
||||
self._verify_open()
|
||||
return iter(self._index.keys())
|
||||
__iter__ = iterkeys
|
||||
|
||||
def __len__(self):
|
||||
self._verify_open()
|
||||
return len(self._index)
|
||||
|
||||
def close(self):
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
"""
|
||||
|
||||
import io
|
||||
import operator
|
||||
import os
|
||||
import unittest
|
||||
import dbm.dumb as dumbdbm
|
||||
from test import support
|
||||
from functools import partial
|
||||
|
||||
_fname = support.TESTFN
|
||||
|
||||
|
@ -190,12 +192,31 @@ class DumbDBMTestCase(unittest.TestCase):
|
|||
with dumbdbm.open(_fname, 'r') as db:
|
||||
self.assertEqual(list(db.keys()), [b"dumbdbm context manager"])
|
||||
|
||||
# This currently just raises AttributeError rather than a specific
|
||||
# exception like the GNU or NDBM based implementations. See
|
||||
# http://bugs.python.org/issue19385 for details.
|
||||
with self.assertRaises(Exception):
|
||||
with self.assertRaises(dumbdbm.error):
|
||||
db.keys()
|
||||
|
||||
def test_check_closed(self):
|
||||
f = dumbdbm.open(_fname, 'c')
|
||||
f.close()
|
||||
|
||||
for meth in (partial(operator.delitem, f),
|
||||
partial(operator.setitem, f, 'b'),
|
||||
partial(operator.getitem, f),
|
||||
partial(operator.contains, f)):
|
||||
with self.assertRaises(dumbdbm.error) as cm:
|
||||
meth('test')
|
||||
self.assertEqual(str(cm.exception),
|
||||
"DBM object has already been closed")
|
||||
|
||||
for meth in (operator.methodcaller('keys'),
|
||||
operator.methodcaller('iterkeys'),
|
||||
operator.methodcaller('items'),
|
||||
len):
|
||||
with self.assertRaises(dumbdbm.error) as cm:
|
||||
meth(f)
|
||||
self.assertEqual(str(cm.exception),
|
||||
"DBM object has already been closed")
|
||||
|
||||
def tearDown(self):
|
||||
_delete_files()
|
||||
|
||||
|
|
Loading…
Reference in New Issue