make operations on closed dumb databases raise a consistent exception (closes #19385)

Patch by Claudiu Popa.
This commit is contained in:
Benjamin Peterson 2014-04-26 16:56:52 -04:00
parent d4992dccfb
commit e3083d3ad5
3 changed files with 40 additions and 4 deletions

View File

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

View File

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

View File

@ -39,6 +39,9 @@ Core and Builtins
Library
-------
- Issue #19385: Make operations on a closed dbm.dumb database always raise the
same exception.
- Issue #21207: Detect when the os.urandom cached fd has been closed or
replaced, and open it anew.