From: Serhiy Storchaka Date: Fri, 2 Dec 2016 05:58:42 +0000 (+0200) Subject: Issue #28847: dubmdbm no longer writes the index file in when it is not X-Git-Tag: v2.7.13rc1~15 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9bd44d6dab214ab17c5505aa445388ccf8695c87;p=python Issue #28847: dubmdbm no longer writes the index file in when it is not changed and supports reading read-only files. --- diff --git a/Lib/dumbdbm.py b/Lib/dumbdbm.py index 8ef7e79582..ac73b89c88 100644 --- a/Lib/dumbdbm.py +++ b/Lib/dumbdbm.py @@ -45,8 +45,9 @@ class _Database(UserDict.DictMixin): _os = _os # for _commit() _open = _open # for _commit() - def __init__(self, filebasename, mode): + def __init__(self, filebasename, mode, flag='c'): self._mode = mode + self._readonly = (flag == 'r') # The directory file is a text file. Each line looks like # "%r, (%d, %d)\n" % (key, pos, siz) @@ -81,8 +82,9 @@ class _Database(UserDict.DictMixin): try: f = _open(self._dirfile) except IOError: - pass + self._modified = not self._readonly else: + self._modified = False with f: for line in f: line = line.rstrip() @@ -96,7 +98,7 @@ class _Database(UserDict.DictMixin): # CAUTION: It's vital that _commit() succeed, and _commit() can # be called from __del__(). Therefore we must never reference a # global in this routine. - if self._index is None: + if self._index is None or not self._modified: return # nothing to do try: @@ -159,6 +161,7 @@ class _Database(UserDict.DictMixin): def __setitem__(self, key, val): if not type(key) == type('') == type(val): raise TypeError, "keys and values must be strings" + self._modified = True if key not in self._index: self._addkey(key, self._addval(val)) else: @@ -184,6 +187,7 @@ class _Database(UserDict.DictMixin): # (so that _commit() never gets called). def __delitem__(self, key): + self._modified = True # 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 @@ -246,4 +250,4 @@ def open(file, flag=None, mode=0666): # Turn off any bits that are set in the umask mode = mode & (~um) - return _Database(file, mode) + return _Database(file, mode, flag) diff --git a/Lib/test/test_dumbdbm.py b/Lib/test/test_dumbdbm.py index 6520efdb83..024ddda4df 100644 --- a/Lib/test/test_dumbdbm.py +++ b/Lib/test/test_dumbdbm.py @@ -3,6 +3,7 @@ """ import os +import stat import unittest import dumbdbm from test import test_support @@ -168,6 +169,26 @@ class DumbDBMTestCase(unittest.TestCase): dumbdbm.open(_fname).close() self.assertEqual(stdout.getvalue(), '') + @unittest.skipUnless(hasattr(os, 'chmod'), 'test needs os.chmod()') + def test_readonly_files(self): + dir = _fname + os.mkdir(dir) + try: + fname = os.path.join(dir, 'db') + f = dumbdbm.open(fname, 'n') + self.assertEqual(list(f.keys()), []) + for key in self._dict: + f[key] = self._dict[key] + f.close() + os.chmod(fname + ".dir", stat.S_IRUSR) + os.chmod(fname + ".dat", stat.S_IRUSR) + os.chmod(dir, stat.S_IRUSR|stat.S_IXUSR) + f = dumbdbm.open(fname, 'r') + self.assertEqual(sorted(f.keys()), sorted(self._dict)) + f.close() # don't write + finally: + test_support.rmtree(dir) + def tearDown(self): _delete_files() diff --git a/Misc/NEWS b/Misc/NEWS index c7344a2629..cc2ab92604 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ What's New in Python 2.7.13? Core and Builtins ----------------- +- Issue #28847: dubmdbm no longer writes the index file in when it is not + changed and supports reading read-only files. + - Issue #11145: Fixed miscellaneous issues with C-style formatting of types with custom __oct__ and __hex__.