diff -r 9c724c428e1f Doc/library/dbm.rst --- a/Doc/library/dbm.rst Mon Jun 09 13:35:43 2014 +0300 +++ b/Doc/library/dbm.rst Tue Jun 10 11:46:46 2014 +0300 @@ -316,13 +316,17 @@ dumbdbm database is created, files with :file:`.dat` and :file:`.dir` extensions are created. - The optional *flag* argument is currently ignored; the database is always opened - for update, and will be created if it does not exist. + The optional *flag* argument supports only the semantics of ``'c'`` + and ``'n`` values. Other values will default to database being always + opened for update, and will be created if it does not exist. The optional *mode* argument is the Unix mode of the file, used only when the database has to be created. It defaults to octal ``0o666`` (and will be modified by the prevailing umask). + .. versionchanged:: 3.5 + :func:`.open` always creates a new database when the flag has the value ``'n'``. + In addition to the methods provided by the :class:`collections.abc.MutableMapping` class, :class:`dumbdbm` objects provide the following method: diff -r 9c724c428e1f Lib/dbm/dumb.py --- a/Lib/dbm/dumb.py Mon Jun 09 13:35:43 2014 +0300 +++ b/Lib/dbm/dumb.py Tue Jun 10 11:46:46 2014 +0300 @@ -44,7 +44,7 @@ _os = _os # for _commit() _io = _io # for _commit() - def __init__(self, filebasename, mode): + def __init__(self, filebasename, mode, flag=None): self._mode = mode # The directory file is a text file. Each line looks like @@ -64,14 +64,30 @@ # The index is an in-memory dict, mirroring the directory file. self._index = None # maps keys to (pos, siz) pairs + # Handle the creation + self._create(flag) + self._update() + + def _create(self, flag): + if flag == 'n': + for filename in (self._datfile, self._bakfile, self._dirfile): + try: + _os.remove(filename) + except OSError: + pass # Mod by Jack: create data file if needed try: f = _io.open(self._datfile, 'r', encoding="Latin-1") except OSError: + if flag and flag in 'rw': + import warnings + warnings.warn("The database file is missing, the " + "semantics of the 'c' flag will be used.", + stacklevel=4) f = _io.open(self._datfile, 'w', encoding="Latin-1") self._chmod(self._datfile) f.close() - self._update() + # Read directory file into the in-memory index dict. def _update(self): @@ -270,16 +286,15 @@ """Open the database file, filename, and return corresponding object. The flag argument, used to control how the database is opened in the - other DBM implementations, is ignored in the dbm.dumb module; the - database is always opened for update, and will be created if it does - not exist. + other DBM implementations, supports only the semantics of + ``'c'`` and ``'n`` values. Other values will default to database being + always opened for update, and will be created if it does not exist. The optional mode argument is the UNIX mode of the file, used only when the database has to be created. It defaults to octal code 0o666 (and will be modified by the prevailing umask). """ - # flag argument is currently ignored # Modify mode depending on the umask try: @@ -290,5 +305,6 @@ else: # Turn off any bits that are set in the umask mode = mode & (~um) - - return _Database(file, mode) + if flag and flag not in 'rwcn': + raise error("First flag must be one of 'r', 'w', 'c' or 'n'") + return _Database(file, mode, flag=flag) diff -r 9c724c428e1f Lib/test/test_dbm_dumb.py --- a/Lib/test/test_dbm_dumb.py Mon Jun 09 13:35:43 2014 +0300 +++ b/Lib/test/test_dbm_dumb.py Tue Jun 10 11:46:46 2014 +0300 @@ -69,7 +69,8 @@ def test_dumbdbm_modification(self): self.init_db() - f = dumbdbm.open(_fname, 'w') + with support.check_warnings(): + f = dumbdbm.open(_fname, 'w') self._dict[b'g'] = f[b'g'] = b"indented" self.read_helper(f) f.close() @@ -148,7 +149,8 @@ self.assertEqual(self._dict[key], f[key]) def init_db(self): - f = dumbdbm.open(_fname, 'w') + with support.check_warnings(): + f = dumbdbm.open(_fname, 'w') for k in self._dict: f[k] = self._dict[k] f.close() @@ -217,6 +219,31 @@ self.assertEqual(str(cm.exception), "DBM object has already been closed") + def test_create_new(self): + with dumbdbm.open(_fname, 'n') as f: + for k in self._dict: + f[k] = self._dict[k] + + with dumbdbm.open(_fname, 'n') as f: + self.assertEqual(f.keys(), []) + + def test_warn_on_ignored_flags(self): + for value in ('r', 'w'): + _delete_files() + with self.assertWarnsRegex(UserWarning, + "The database file is missing, the " + "semantics of the 'c' flag will " + "be used."): + with dumbdbm.open(_fname, value): + pass + + def test_invalid_flags(self): + for flag in 'abd': + with self.assertRaisesRegex(dumbdbm.error, + "First flag must be one of 'r', 'w', " + "'c' or 'n'"): + dumbdbm.open(_fname, flag) + def tearDown(self): _delete_files()