8000 gh-83383: Always mark the dbm.dumb database as unmodified after open() and sync() by serhiy-storchaka · Pull Request #114560 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-83383: Always mark the dbm.dumb database as unmodified after open() and sync() #114560

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Lib/dbm/dumb.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ def _update(self, flag):
except OSError:
if flag not in ('c', 'n'):
raise
self._modified = True
with self._io.open(self._dirfile, 'w', encoding="Latin-1") as f:
self._chmod(self._dirfile)
else:
with f:
for line in f:
Expand Down Expand Up @@ -134,6 +135,7 @@ def _commit(self):
# position; UTF-8, though, does care sometimes.
entry = "%r, %r\n" % (key.decode('Latin-1'), pos_and_siz_pair)
f.write(entry)
self._modified = False

sync = _commit

Expand Down
72 changes: 72 additions & 0 deletions Lib/test/test_dbm_dumb.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,27 @@ def test_missing_data(self):
_delete_files()
with self.assertRaises(FileNotFoundError):
dumbdbm.open(_fname, value)
self.assertFalse(os.path.exists(_fname + '.dat'))
self.assertFalse(os.path.exists(_fname + '.dir'))
self.assertFalse(os.path.exists(_fname + '.bak'))

for value in ('c', 'n'):
_delete_files()
with dumbdbm.open(_fname, value) as f:
self.assertTrue(os.path.exists(_fname + '.dat'))
self.assertTrue(os.path.exists(_fname + '.dir'))
self.assertFalse(os.path.exists(_fname + '.bak'))
self.assertFalse(os.path.exists(_fname + '.bak'))

for value in ('c', 'n'):
_delete_files()
with dumbdbm.open(_fname, value) as f:
f['key'] = 'value'
self.assertTrue(os.path.exists(_fname + '.dat'))
self.assertTrue(os.path.exists(_fname + '.dir'))
self.assertFalse(os.path.exists(_fname + '.bak'))
self.assertTrue(os.path.exists(_fname + '.bak'))

def test_missing_index(self):
with dumbdbm.open(_fname, 'n') as f:
pass
Expand All @@ -259,6 +277,60 @@ def test_missing_index(self):
self.assertFalse(os.path.exists(_fname + '.dir'))
self.assertFalse(os.path.exists(_fname + '.bak'))

for value in ('c', 'n'):
with dumbdbm.open(_fname, value) as f:
self.assertTrue(os.path.exists(_fname + '.dir'))
self.assertFalse(os.path.exists(_fname + '.bak'))
self.assertFalse(os.path.exists(_fname + '.bak'))
os.unlink(_fname + '.dir')

for value in ('c', 'n'):
with dumbdbm.open(_fname, value) as f:
f['key'] = 'value'
self.assertTrue(os.path.exists(_fname + '.dir'))
self.assertFalse(os.path.exists(_fname + '.bak'))
self.assertTrue(os.path.exists(_fname + '.bak'))
os.unlink(_fname + '.dir')
os.unlink(_fname + '.bak')

def test_sync_empty_unmodified(self):
with dumbdbm.open(_fname, 'n') as f:
pass
os.unlink(_fname + '.dir')
for value in ('c', 'n'):
with dumbdbm.open(_fname, value) as f:
self.assertTrue(os.path.exists(_fname + '.dir'))
self.assertFalse(os.path.exists(_fname + '.bak'))
f.sync()
self.assertTrue(os.path.exists(_fname + '.dir'))
self.assertFalse(os.path.exists(_fname + '.bak'))
os.unlink(_fname + '.dir')
f.sync()
self.assertFalse(os.path.exists(_fname + '.dir'))
self.assertFalse(os.path.exists(_fname + '.bak'))
self.assertFalse(os.path.exists(_fname + '.dir'))
self.assertFalse(os.path.exists(_fname + '.bak'))

def test_sync_nonempty_unmodified(self):
with dumbdbm.open(_fname, 'n') as f:
pass
os.unlink(_fname + '.dir')
for value in ('c', 'n'):
with dumbdbm.open(_fname, value) as f:
f['key'] = 'value'
self.assertTrue(os.path.exists(_fname + '.dir'))
self.assertFalse(os.path.exists(_fname + '.bak'))
f.sync()
self.assertTrue(os.path.exists(_fname + '.dir'))
self.assertTrue(os.path.exists(_fname + '.bak'))
os.unlink(_fname + '.dir')
os.unlink(_fname + '.bak')
f.sync()
self.assertFalse(os.path.exists(_fname + '.dir'))
self.assertFalse(os.path.exists(_fname + '.bak'))
self.assertFalse(os.path.exists(_fname + '.dir'))
self.assertFalse(os.path.exists(_fname + '.bak'))

def test_invalid_flag(self):
for flag in ('x', 'rf', None):
with self.assertRaisesRegex(ValueError,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Synchronization of the :mod:`dbm.dumb` database is now no-op if there was no
modification since opening or last synchronization.
The directory file for a newly created empty :mod:`dbm.dumb` database is now
created immediately after opening instead of deferring this until
synchronizing or closing.
0