Issue #28847: dbm.dumb now supports reading read-only files and no longer

writes the index file when it is not changed.
This commit is contained in:
Serhiy Storchaka 2016-12-07 11:02:18 +02:00
commit 43153e4d49
4 changed files with 26 additions and 4 deletions

View File

@ -97,8 +97,9 @@ class _Database(collections.MutableMapping):
try: try:
f = _io.open(self._dirfile, 'r', encoding="Latin-1") f = _io.open(self._dirfile, 'r', encoding="Latin-1")
except OSError: except OSError:
pass self._modified = not self._readonly
else: else:
self._modified = False
with f: with f:
for line in f: for line in f:
line = line.rstrip() line = line.rstrip()
@ -113,7 +114,7 @@ class _Database(collections.MutableMapping):
# CAUTION: It's vital that _commit() succeed, and _commit() can # CAUTION: It's vital that _commit() succeed, and _commit() can
# be called from __del__(). Therefore we must never reference a # be called from __del__(). Therefore we must never reference a
# global in this routine. # global in this routine.
if self._index is None: if self._index is None or not self._modified:
return # nothing to do return # nothing to do
try: try:
@ -197,6 +198,7 @@ class _Database(collections.MutableMapping):
elif not isinstance(val, (bytes, bytearray)): elif not isinstance(val, (bytes, bytearray)):
raise TypeError("values must be bytes or strings") raise TypeError("values must be bytes or strings")
self._verify_open() self._verify_open()
self._modified = True
if key not in self._index: if key not in self._index:
self._addkey(key, self._addval(val)) self._addkey(key, self._addval(val))
else: else:
@ -229,6 +231,7 @@ class _Database(collections.MutableMapping):
if isinstance(key, str): if isinstance(key, str):
key = key.encode('utf-8') key = key.encode('utf-8')
self._verify_open() self._verify_open()
self._modified = True
# The blocks used by the associated value are lost. # The blocks used by the associated value are lost.
del self._index[key] del self._index[key]
# XXX It's unclear why we do a _commit() here (the code always # XXX It's unclear why we do a _commit() here (the code always

View File

@ -360,9 +360,9 @@ if sys.platform.startswith("win"):
mode = 0 mode = 0
if stat.S_ISDIR(mode): if stat.S_ISDIR(mode):
_waitfor(_rmtree_inner, fullname, waitall=True) _waitfor(_rmtree_inner, fullname, waitall=True)
_force_run(path, os.rmdir, fullname) _force_run(fullname, os.rmdir, fullname)
else: else:
_force_run(path, os.unlink, fullname) _force_run(fullname, os.unlink, fullname)
_waitfor(_rmtree_inner, path, waitall=True) _waitfor(_rmtree_inner, path, waitall=True)
_waitfor(lambda p: _force_run(p, os.rmdir, p), path) _waitfor(lambda p: _force_run(p, os.rmdir, p), path)
else: else:

View File

@ -5,6 +5,7 @@
import io import io
import operator import operator
import os import os
import stat
import unittest import unittest
import warnings import warnings
import dbm.dumb as dumbdbm import dbm.dumb as dumbdbm
@ -259,6 +260,21 @@ class DumbDBMTestCase(unittest.TestCase):
f = dumbdbm.open(_fname, flag) f = dumbdbm.open(_fname, flag)
f.close() f.close()
@unittest.skipUnless(hasattr(os, 'chmod'), 'test needs os.chmod()')
def test_readonly_files(self):
with support.temp_dir() as dir:
fname = os.path.join(dir, 'db')
with dumbdbm.open(fname, 'n') as f:
self.assertEqual(list(f.keys()), [])
for key in self._dict:
f[key] = self._dict[key]
os.chmod(fname + ".dir", stat.S_IRUSR)
os.chmod(fname + ".dat", stat.S_IRUSR)
os.chmod(dir, stat.S_IRUSR|stat.S_IXUSR)
with dumbdbm.open(fname, 'r') as f:
self.assertEqual(sorted(f.keys()), sorted(self._dict))
f.close() # don't write
def tearDown(self): def tearDown(self):
_delete_files() _delete_files()

View File

@ -165,6 +165,9 @@ Core and Builtins
Library Library
------- -------
- Issue #28847: dbm.dumb now supports reading read-only files and no longer
writes the index file when it is not changed.
- Issue #27030: Unknown escapes consisting of ``'\'`` and an ASCII letter in - Issue #27030: Unknown escapes consisting of ``'\'`` and an ASCII letter in
re.sub() replacement templates regular expressions now are errors. re.sub() replacement templates regular expressions now are errors.