Issue #21708: Deprecated dbm.dumb behavior that differs from common dbm

behavior: creating a database in 'r' and 'w' modes and modifying a database
in 'r' mode.
This commit is contained in:
Serhiy Storchaka 2016-07-06 12:21:58 +03:00
parent 9862b5194d
commit 0122ae9ac8
5 changed files with 57 additions and 1 deletions

View File

@ -351,6 +351,10 @@ The module defines the following:
:func:`.open` always creates a new database when the flag has the value :func:`.open` always creates a new database when the flag has the value
``'n'``. ``'n'``.
.. deprecated-removed:: 3.6 3.8
Creating database in ``'r'`` and ``'w'`` modes. Modifying database in
``'r'`` mode.
In addition to the methods provided by the In addition to the methods provided by the
:class:`collections.abc.MutableMapping` class, :class:`dumbdbm` objects :class:`collections.abc.MutableMapping` class, :class:`dumbdbm` objects
provide the following methods: provide the following methods:

View File

@ -604,6 +604,11 @@ Deprecated features
``__package__`` are not defined now raises an :exc:`ImportWarning`. ``__package__`` are not defined now raises an :exc:`ImportWarning`.
(Contributed by Rose Ames in :issue:`25791`.) (Contributed by Rose Ames in :issue:`25791`.)
* Unlike to other :mod:`dbm` implementations, the :mod:`dbm.dumb` module
creates database in ``'r'`` and ``'w'`` modes if it doesn't exist and
allows modifying database in ``'r'`` mode. This behavior is now deprecated
and will be removed in 3.8.
(Contributed by Serhiy Storchaka in :issue:`21708`.)
Deprecated Python behavior Deprecated Python behavior
-------------------------- --------------------------

View File

@ -47,6 +47,7 @@ class _Database(collections.MutableMapping):
def __init__(self, filebasename, mode, flag='c'): def __init__(self, filebasename, mode, flag='c'):
self._mode = mode self._mode = mode
self._readonly = (flag == 'r')
# The directory file is a text file. Each line looks like # The directory file is a text file. Each line looks like
# "%r, (%d, %d)\n" % (key, pos, siz) # "%r, (%d, %d)\n" % (key, pos, siz)
@ -80,6 +81,11 @@ class _Database(collections.MutableMapping):
try: try:
f = _io.open(self._datfile, 'r', encoding="Latin-1") f = _io.open(self._datfile, 'r', encoding="Latin-1")
except OSError: except OSError:
if flag not in ('c', 'n'):
import warnings
warnings.warn("The database file is missing, the "
"semantics of the 'c' flag will be used.",
DeprecationWarning, stacklevel=4)
with _io.open(self._datfile, 'w', encoding="Latin-1") as f: with _io.open(self._datfile, 'w', encoding="Latin-1") as f:
self._chmod(self._datfile) self._chmod(self._datfile)
else: else:
@ -178,6 +184,10 @@ class _Database(collections.MutableMapping):
f.write("%r, %r\n" % (key.decode("Latin-1"), pos_and_siz_pair)) f.write("%r, %r\n" % (key.decode("Latin-1"), pos_and_siz_pair))
def __setitem__(self, key, val): def __setitem__(self, key, val):
if self._readonly:
import warnings
warnings.warn('The database is opened for reading only',
DeprecationWarning, stacklevel=2)
if isinstance(key, str): if isinstance(key, str):
key = key.encode('utf-8') key = key.encode('utf-8')
elif not isinstance(key, (bytes, bytearray)): elif not isinstance(key, (bytes, bytearray)):
@ -212,6 +222,10 @@ class _Database(collections.MutableMapping):
# (so that _commit() never gets called). # (so that _commit() never gets called).
def __delitem__(self, key): def __delitem__(self, key):
if self._readonly:
import warnings
warnings.warn('The database is opened for reading only',
DeprecationWarning, stacklevel=2)
if isinstance(key, str): if isinstance(key, str):
key = key.encode('utf-8') key = key.encode('utf-8')
self._verify_open() self._verify_open()
@ -300,4 +314,8 @@ def open(file, flag='c', mode=0o666):
else: else:
# Turn off any bits that are set in the umask # Turn off any bits that are set in the umask
mode = mode & (~um) mode = mode & (~um)
if flag not in ('r', 'w', 'c', 'n'):
import warnings
warnings.warn("Flag must be one of 'r', 'w', 'c', or 'n'",
DeprecationWarning, stacklevel=2)
return _Database(file, mode, flag=flag) return _Database(file, mode, flag=flag)

View File

@ -6,6 +6,7 @@ import io
import operator import operator
import os import os
import unittest import unittest
import warnings
import dbm.dumb as dumbdbm import dbm.dumb as dumbdbm
from test import support from test import support
from functools import partial from functools import partial
@ -78,6 +79,12 @@ class DumbDBMTestCase(unittest.TestCase):
self.init_db() self.init_db()
f = dumbdbm.open(_fname, 'r') f = dumbdbm.open(_fname, 'r')
self.read_helper(f) self.read_helper(f)
with self.assertWarnsRegex(DeprecationWarning,
'The database is opened for reading only'):
f[b'g'] = b'x'
with self.assertWarnsRegex(DeprecationWarning,
'The database is opened for reading only'):
del f[b'a']
f.close() f.close()
def test_dumbdbm_keys(self): def test_dumbdbm_keys(self):
@ -148,7 +155,7 @@ class DumbDBMTestCase(unittest.TestCase):
self.assertEqual(self._dict[key], f[key]) self.assertEqual(self._dict[key], f[key])
def init_db(self): def init_db(self):
f = dumbdbm.open(_fname, 'w') f = dumbdbm.open(_fname, 'n')
for k in self._dict: for k in self._dict:
f[k] = self._dict[k] f[k] = self._dict[k]
f.close() f.close()
@ -234,6 +241,24 @@ class DumbDBMTestCase(unittest.TestCase):
pass pass
self.assertEqual(stdout.getvalue(), '') self.assertEqual(stdout.getvalue(), '')
def test_warn_on_ignored_flags(self):
for value in ('r', 'w'):
_delete_files()
with self.assertWarnsRegex(DeprecationWarning,
"The database file is missing, the "
"semantics of the 'c' flag will "
"be used."):
f = dumbdbm.open(_fname, value)
f.close()
def test_invalid_flag(self):
for flag in ('x', 'rf', None):
with self.assertWarnsRegex(DeprecationWarning,
"Flag must be one of "
"'r', 'w', 'c', or 'n'"):
f = dumbdbm.open(_fname, flag)
f.close()
def tearDown(self): def tearDown(self):
_delete_files() _delete_files()

View File

@ -24,6 +24,10 @@ Core and Builtins
Library Library
------- -------
- Issue #21708: Deprecated dbm.dumb behavior that differs from common dbm
behavior: creating a database in 'r' and 'w' modes and modifying a database
in 'r' mode.
- Issue #26721: Change the socketserver.StreamRequestHandler.wfile attribute - Issue #26721: Change the socketserver.StreamRequestHandler.wfile attribute
to implement BufferedIOBase. In particular, the write() method no longer to implement BufferedIOBase. In particular, the write() method no longer
does partial writes. does partial writes.