Index: Misc/NEWS =================================================================== --- Misc/NEWS (revision 67310) +++ Misc/NEWS (working copy) @@ -56,6 +56,12 @@ - Issue #1656675: Register a drop handler for .py* files on Windows. +Docs +----- + +- Document that the various modules in the dbm package store keys and values as + bytes, converting to the default encoding when strings are used. + Tools/Demos ----------- Index: Doc/library/dbm.rst =================================================================== --- Doc/library/dbm.rst (revision 67308) +++ Doc/library/dbm.rst (working copy) @@ -52,7 +52,9 @@ The object returned by :func:`open` supports most of the same functionality as dictionaries; keys and their corresponding values can be stored, retrieved, and deleted, and the :keyword:`in` operator and the :meth:`keys` method are -available. Keys and values must always be strings. +available. 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. The following example records some hostnames and a corresponding title, and then prints out the contents of the database:: @@ -63,9 +65,15 @@ db = dbm.open('cache', 'c') # Record some values + db[b'hello'] = b'there' db['www.python.org'] = 'Python Website' db['www.cnn.com'] = 'Cable News Network' + # Note that the keys are considered bytes now. + assert db[b'www.python.org'] == b'Python Website' + # Notice how the value is now in bytes. + assert db['www.cnn.com'] == b'Cable News Network' + # Loop through contents. Other dictionary methods # such as .keys(), .values() also work. for k, v in db.iteritems(): @@ -102,7 +110,8 @@ The :mod:`dbm.gnu` module provides an interface to the GNU DBM library. ``gdbm`` objects behave like mappings (dictionaries), except that keys and -values are always strings. Printing a :mod:`dbm.gnu` object doesn't print the +values are always converted to bytes before storing. Printing a :mod:`dbm.gnu` +object doesn't print the keys and values, and the :meth:`items` and :meth:`values` methods are not supported. @@ -203,8 +212,8 @@ The :mod:`dbm.ndbm` module provides an interface to the Unix "(n)dbm" library. Dbm objects behave like mappings (dictionaries), except that keys and values are -always strings. Printing a dbm object doesn't print the keys and values, and the -:meth:`items` and :meth:`values` methods are not supported. +always stored as bytes. Printing a dbm object doesn't print the keys and +values, and the :meth:`items` and :meth:`values` methods are not supported. This module can be used with the "classic" ndbm interface, the BSD DB compatibility interface, or the GNU GDBM compatibility interface. On Unix, the @@ -271,7 +280,7 @@ The :mod:`dbm.dumb` module provides a persistent dictionary-like interface which is written entirely in Python. Unlike other modules such as :mod:`gdbm` no external library is required. As with other persistent mappings, the keys and -values must always be strings. +values are always stored as bytes. The module defines the following: Index: Lib/dbm/dumb.py =================================================================== --- Lib/dbm/dumb.py (revision 67310) +++ Lib/dbm/dumb.py (working copy) @@ -169,8 +169,10 @@ key = key.encode('utf-8') elif not isinstance(key, (bytes, bytearray)): raise TypeError("keys must be bytes or strings") - if not isinstance(val, (bytes, bytearray)): - raise TypeError("values must be bytes") + if isinstance(val, str): + val = val.encode('utf-8') + elif not isinstance(val, (bytes, bytearray)): + raise TypeError("values must be bytes or strings") if key not in self._index: self._addkey(key, self._addval(val)) else: Index: Lib/test/test_dbm_dumb.py =================================================================== --- Lib/test/test_dbm_dumb.py (revision 67310) +++ Lib/test/test_dbm_dumb.py (working copy) @@ -115,6 +115,7 @@ self.init_db() f = dumbdbm.open(_fname) f['\u00fc'] = b'!' + f['1'] = 'a' f.close() f = dumbdbm.open(_fname, 'r') self.assert_('\u00fc' in f) Index: Lib/test/test_dbm_gnu.py =================================================================== --- Lib/test/test_dbm_gnu.py (revision 67308) +++ Lib/test/test_dbm_gnu.py (working copy) @@ -20,9 +20,11 @@ self.assertEqual(self.g.keys(), []) self.g['a'] = 'b' self.g['12345678910'] = '019237410982340912840198242' + self.g[b'bytes'] = b'data' key_set = set(self.g.keys()) self.assertEqual(key_set, set([b'a', b'12345678910'])) self.assert_(b'a' in self.g) + self.assertEqual(self.g[b'bytes'], b'data') key = self.g.firstkey() while key: self.assert_(key in key_set) Index: Lib/test/test_dbm_ndbm.py =================================================================== --- Lib/test/test_dbm_ndbm.py (revision 67308) +++ Lib/test/test_dbm_ndbm.py (working copy) @@ -20,9 +20,11 @@ self.d = dbm.ndbm.open(self.filename, 'c') self.assert_(self.d.keys() == []) self.d['a'] = 'b' + self.d[b'bytes'] = b'data' self.d['12345678910'] = '019237410982340912840198242' self.d.keys() self.assert_(b'a' in self.d) + self.assertEqual(self.d[b'bytes'], b'data') self.d.close() def test_modes(self): Index: Modules/_gdbmmodule.c =================================================================== --- Modules/_gdbmmodule.c (revision 67308) +++ Modules/_gdbmmodule.c (working copy) @@ -142,7 +142,7 @@ if (!PyArg_Parse(v, "s#", &krec.dptr, &krec.dsize) ) { PyErr_SetString(PyExc_TypeError, - "gdbm mappings have string indices only"); + "gdbm mappings have bytes or string indices only"); return -1; } if (dp->di_dbm == NULL) { @@ -160,7 +160,7 @@ else { if (!PyArg_Parse(w, "s#", &drec.dptr, &drec.dsize)) { PyErr_SetString(PyExc_TypeError, - "gdbm mappings have byte string elements only"); + "gdbm mappings have byte or string elements only"); return -1; } errno = 0; Index: Modules/_dbmmodule.c =================================================================== --- Modules/_dbmmodule.c (revision 67308) +++ Modules/_dbmmodule.c (working copy) @@ -122,7 +122,7 @@ if ( !PyArg_Parse(v, "s#", &krec.dptr, &tmp_size) ) { PyErr_SetString(PyExc_TypeError, - "dbm mappings have string keys only"); + "dbm mappings have bytes or string keys only"); return -1; } krec.dsize = tmp_size; @@ -140,7 +140,7 @@ } else { if ( !PyArg_Parse(w, "s#", &drec.dptr, &tmp_size) ) { PyErr_SetString(PyExc_TypeError, - "dbm mappings have byte string elements only"); + "dbm mappings have byte or string elements only"); return -1; } drec.dsize = tmp_size;