Skip to main content

Lib/dbm/__init__.py

cpython 3.14 @ ab2d84fe1023/Lib/dbm/__init__.py

The dbm package presents a single, consistent interface over several underlying key-value database implementations that may or may not be present on a given platform. A caller can open a database with dbm.open() without knowing which backend is installed, and the module handles discovery and dispatch automatically. The three possible backends are dbm.gnu (GNU gdbm), dbm.ndbm (the classic ndbm API, often provided by Berkeley DB), and dbm.dumb (a portable pure-Python fallback that never fails to import).

Backend priority runs from fastest to most portable. When more than one backend is available, gnu is tried first, then ndbm, then dumb. The whichdb(filename) function performs the reverse operation: given a path to an existing database file, it reads the file header and returns the name of the module that originally created it, or None if the file cannot be identified.

All three backends expose the same minimal dict-like interface. Keys and values must be byte strings or objects that implement the buffer protocol. The returned object supports __getitem__, __setitem__, __delitem__, __contains__, keys(), and the context manager protocol. Iteration and values() are intentionally absent from the base specification to match the lowest-common-denominator guarantee of the C-level ndbm interface.

Map

LinesSymbolRolegopy
1-30module headerImports, __all__, error alias tuple
31-70whichdb(filename)Reads file magic bytes to identify the backend module
71-100_defaultmod, _modulesBackend discovery, builds ordered list at import time
101-140open(file, flag, mode)Dispatches to the appropriate backend open()
141-155_Database abstract notesDocuments the expected interface for backend objects
156-170__init__ re-exportsExposes error, open, whichdb at package level

Reading

Backend discovery (lines 71 to 100)

cpython 3.14 @ ab2d84fe1023/Lib/dbm/__init__.py#L71-100

At import time the module attempts to import each backend in priority order and records those that succeed. _defaultmod is set to the first backend that imports successfully. _modules is a dict mapping module name strings to module objects for all available backends. This eager-import strategy means backend availability is checked once at startup rather than on every call to open().

_names = ['dbm.gnu', 'dbm.ndbm', 'dbm.dumb']
_defaultmod = None
_modules = {}

for _name in _names:
try:
_mod = __import__(_name, fromlist=['open'])
except ImportError:
continue
if _defaultmod is None:
_defaultmod = _mod
_modules[_name] = _mod

whichdb (lines 31 to 70)

cpython 3.14 @ ab2d84fe1023/Lib/dbm/__init__.py#L31-70

whichdb opens the database file in binary mode and reads enough bytes to recognise the magic number of each known format. GNU gdbm files start with the bytes \x13\x57\x9a\xce (big-endian) or their byte-swapped equivalent. Berkeley DB files carry a different four-byte magic. If the file matches none of the known headers, whichdb returns None. If the file does not exist or cannot be read, it raises OSError.

def whichdb(filename):
# Try dbm.gnu magic
with open(filename + '.db', 'rb') as f:
...
# Fall back to inspecting raw file
...
return None

open (lines 101 to 140)

cpython 3.14 @ ab2d84fe1023/Lib/dbm/__init__.py#L101-140

open(file, flag='r', mode=0o666) is the main entry point. For an existing file it calls whichdb to identify the correct backend, then delegates to that backend's own open(). For a new file it uses _defaultmod. The flag argument mirrors the conventions of the C open() call: 'r' for read-only, 'w' for read-write, 'c' for create-or-open, and 'n' for a fresh database. Passing an unrecognised flag raises error.

def open(file, flag='r', mode=0o666):
if flag[0] == 'n':
mod = _defaultmod
else:
result = whichdb(file)
if result is None:
...
mod = _modules.get(result, _defaultmod)
return mod.open(file, flag, mode)

error alias (lines 1 to 30)

cpython 3.14 @ ab2d84fe1023/Lib/dbm/__init__.py#L1-30

dbm.error is a tuple of exception classes, one per backend plus the base OSError. This allows a single except dbm.error clause to catch errors raised by any backend without the caller knowing which one is active. The pattern mirrors how socket.error works as a compatibility alias for OSError.

error = (OSError,)
for _mod in _modules.values():
if hasattr(_mod, 'error') and _mod.error not in error:
error = error + (_mod.error,)

Context manager support (lines 141 to 155)

cpython 3.14 @ ab2d84fe1023/Lib/dbm/__init__.py#L141-155

The module documents, but does not implement, the __enter__ and __exit__ methods that each backend is expected to provide. This section exists as a contract note: backend objects must support with dbm.open(...) as db: so that the database is closed automatically. The dumb backend implements this as a wrapper around its close() method, while the C-backed modules handle it natively.

gopy mirror

Not yet ported.