Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Closed
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
14 changes: 14 additions & 0 deletions 14 Doc/library/dbm.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ the Oracle Berkeley DB.
file's format can't be guessed; or a string containing the required module
name, such as ``'dbm.ndbm'`` or ``'dbm.gnu'``.

.. versionchanged:: 3.10
Accepts :term:`path-like object` for filename.

.. function:: open(file, flag='r', mode=0o666)

Expand Down Expand Up @@ -77,6 +79,9 @@ available, as well as :meth:`get` and :meth:`setdefault`.
Deleting a key from a read-only database raises database module specific error
instead of :exc:`KeyError`.

.. versionchanged:: 3.10
Accepts :term:`path-like object` for file.

Key and values are always stored as bytes. This means that when
strings are used they are implicitly converted to the default encoding before
being stored.
Expand Down Expand Up @@ -202,6 +207,9 @@ supported.
In addition to the dictionary-like methods, ``gdbm`` objects have the
following methods:

.. versionchanged:: 3.10
Accepts :term:`path-like object` for filename.

.. method:: gdbm.firstkey()

It's possible to loop over every key in the database using this method and the
Expand Down Expand Up @@ -298,6 +306,9 @@ to locate the appropriate header file to simplify building this module.
In addition to the dictionary-like methods, ``ndbm`` objects
provide the following method:

.. versionchanged:: 3.10
Accepts :term:`path-like object` for filename.

.. method:: ndbm.close()

Close the ``ndbm`` database.
Expand Down Expand Up @@ -379,6 +390,9 @@ The module defines the following:
flags ``'r'`` and ``'w'`` no longer creates a database if it does not
exist.

.. versionchanged:: 3.10
Accepts :term:`path-like object` for filename.

In addition to the methods provided by the
:class:`collections.abc.MutableMapping` class, :class:`dumbdbm` objects
provide the following methods:
Expand Down
2 changes: 2 additions & 0 deletions 2 Lib/dbm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def open(file, flag='r', mode=0o666):
raise ImportError("no dbm clone found; tried %s" % _names)

# guess the type of an existing database, if not creating a new one
file = os.fspath(file)
result = whichdb(file) if 'n' not in flag else None
if result is None:
# db doesn't exist or 'n' flag was specified to create a new db
Expand Down Expand Up @@ -109,6 +110,7 @@ def whichdb(filename):
"""

# Check for ndbm first -- this has a .pag and a .dir file
filename = os.fspath(filename)
try:
f = io.open(filename + ".pag", "rb")
f.close()
Expand Down
1 change: 1 addition & 0 deletions 1 Lib/dbm/dumb.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class _Database(collections.abc.MutableMapping):
_io = _io # for _commit()

def __init__(self, filebasename, mode, flag='c'):
filebasename = self._os.fspath(filebasename)
self._mode = mode
self._readonly = (flag == 'r')

Expand Down
52 changes: 29 additions & 23 deletions 52 Lib/test/test_dbm.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import unittest
import glob
import test.support
from pathlib import Path

# Skip tests if dbm module doesn't exist.
dbm = test.support.import_module('dbm')
Expand Down Expand Up @@ -128,6 +129,9 @@ def test_anydbm_access(self):
assert(f[key] == b"Python:")
f.close()

def test_open_with_patlib_path(self):
dbm.open(Path(_fname), "c").close()

def read_helper(self, f):
keys = self.keys_helper(f)
for key in self._dict:
Expand All @@ -143,34 +147,36 @@ def setUp(self):

class WhichDBTestCase(unittest.TestCase):
def test_whichdb(self):
for module in dbm_iterator():
# Check whether whichdb correctly guesses module name
# for databases opened with "module" module.
# Try with empty files first
name = module.__name__
if name == 'dbm.dumb':
continue # whichdb can't support dbm.dumb
delete_files()
f = module.open(_fname, 'c')
f.close()
self.assertEqual(name, self.dbm.whichdb(_fname))
# Now add a key
f = module.open(_fname, 'w')
f[b"1"] = b"1"
# and test that we can find it
self.assertIn(b"1", f)
# and read it
self.assertEqual(f[b"1"], b"1")
f.close()
self.assertEqual(name, self.dbm.whichdb(_fname))
for path in [_fname, Path(_fname)]:
for module in dbm_iterator():
# Check whether whichdb correctly guesses module name
# for databases opened with "module" module.
# Try with empty files first
name = module.__name__
if name == 'dbm.dumb':
continue # whichdb can't support dbm.dumb
delete_files()
f = module.open(path, 'c')
f.close()
self.assertEqual(name, self.dbm.whichdb(path))
# Now add a key
f = module.open(path, 'w')
f[b"1"] = b"1"
# and test that we can find it
self.assertIn(b"1", f)
# and read it
self.assertEqual(f[b"1"], b"1")
f.close()
self.assertEqual(name, self.dbm.whichdb(path))

@unittest.skipUnless(ndbm, reason='Test requires ndbm')
def test_whichdb_ndbm(self):
# Issue 17198: check that ndbm which is referenced in whichdb is defined
db_file = '{}_ndbm.db'.format(_fname)
with open(db_file, 'w'):
self.addCleanup(test.support.unlink, db_file)
self.assertIsNone(self.dbm.whichdb(db_file[:-3]))
for path in [db_file, Path(db_file)]:
with open(path, 'w'):
self.addCleanup(test.support.unlink, path)
self.assertIsNone(self.dbm.whichdb(path[:-3]))

def tearDown(self):
delete_files()
Expand Down
4 changes: 4 additions & 0 deletions 4 Lib/test/test_dbm_dumb.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,10 @@ def test_nonascii_filename(self):
self.assertTrue(b'key' in db)
self.assertEqual(db[b'key'], b'value')

def test_open_with_patlib_path(self):
from pathlib import Path
dumbdbm.open(Path(_fname), "c").close()

def tearDown(self):
_delete_files()

Expand Down
4 changes: 4 additions & 0 deletions 4 Lib/test/test_dbm_gnu.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ def test_nonexisting_file(self):
self.assertIn(nonexisting_file, str(cm.exception))
self.assertEqual(cm.exception.filename, nonexisting_file)

def test_open_with_patlib_path(self):
from pathlib import Path
gdbm.open(Path(filename), "c").close()


if __name__ == '__main__':
unittest.main()
4 changes: 4 additions & 0 deletions 4 Lib/test/test_dbm_ndbm.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ def test_nonexisting_file(self):
self.assertIn(nonexisting_file, str(cm.exception))
self.assertEqual(cm.exception.filename, nonexisting_file)

def test_open_with_patlib_path(self):
from pathlib import Path
dbm.ndbm.open(Path(self.filename), "c").close()


if __name__ == '__main__':
unittest.main()
31 changes: 17 additions & 14 deletions 31 Lib/test/test_shelve.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,29 +62,32 @@ def test_close(self):
else:
self.fail('Closed shelf should not find a key')

def test_ascii_file_shelf(self):
s = shelve.open(self.fn, protocol=0)
def test_open_template(self, filename=None, protocol=None):
kwargs = {
"filename": filename or self.fn,
}
if protocol:
kwargs["protocol"] = protocol
s = shelve.open(**kwargs)
try:
s['key1'] = (1,2,3,4)
self.assertEqual(s['key1'], (1,2,3,4))
finally:
s.close()

def test_ascii_file_shelf(self):
self.test_open_template(protocol=0)

def test_binary_file_shelf(self):
s = shelve.open(self.fn, protocol=1)
try:
s['key1'] = (1,2,3,4)
self.assertEqual(s['key1'], (1,2,3,4))
finally:
s.close()
self.test_open_template(protocol=1)

def test_proto2_file_shelf(self):
s = shelve.open(self.fn, protocol=2)
try:
s['key1'] = (1,2,3,4)
self.assertEqual(s['key1'], (1,2,3,4))
finally:
s.close()
self.test_open_template(protocol=2)

def test_patlib_path_file_shelf(self):
from pathlib import Path
self.test_open_template(filename=Path(self.fn))


def test_in_memory_shelf(self):
d1 = byteskeydict()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support pathlike objects on dbm/shelve. Patch by Hakan Çelik.
10 changes: 10 additions & 0 deletions 10 Modules/_dbmmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,16 @@ dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
return NULL;
}

PyObject *filenamebytes = PyOS_FSPath(filename);
if (filenamebytes == NULL)
return NULL;
if (PyUnicode_Check(filenamebytes)) {
PyObject *tmp = PyUnicode_EncodeFSDefault(filenamebytes);
Py_DECREF(filenamebytes);
filenamebytes = tmp;
if (tmp == NULL)
return NULL;
}
PyObject *filenamebytes = PyUnicode_EncodeFSDefault(filename);
if (filenamebytes == NULL) {
return NULL;
Expand Down
14 changes: 12 additions & 2 deletions 14 Modules/_gdbmmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ static PyTypeObject Dbmtype = {

/*[clinic input]
_gdbm.open as dbmopen
filename: unicode
filename: object
flags: str="r"
mode: int(py_default="0o666") = 0o666
/
Expand Down Expand Up @@ -601,7 +601,7 @@ when the database has to be created. It defaults to octal 0o666.
static PyObject *
dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
int mode)
/*[clinic end generated code: output=9527750f5df90764 input=3be0b0875974b928]*/
/*[clinic end generated code: output=9527750f5df90764 input=0bf3159ce7952fee]*/
{
int iflags;

Expand Down Expand Up @@ -649,6 +649,16 @@ dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
}
}

PyObject *filenamebytes = PyOS_FSPath(filename);
if (filenamebytes == NULL)
return NULL;
if (PyUnicode_Check(filenamebytes)) {
PyObject *tmp = PyUnicode_EncodeFSDefault(filenamebytes);
Py_DECREF(filenamebytes);
filenamebytes = tmp;
if (tmp == NULL)
return NULL;
}
PyObject *filenamebytes = PyUnicode_EncodeFSDefault(filename);
if (filenamebytes == NULL) {
return NULL;
Expand Down
9 changes: 1 addition & 8 deletions 9 Modules/clinic/_gdbmmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Morty Proxy This is a proxified and sanitized view of the page, visit original site.