bpo-32922: dbm.open() now encodes filename with the filesystem encoding. (GH-5832)
This commit is contained in:
parent
973cae07d6
commit
6f600ff173
|
@ -281,6 +281,21 @@ class DumbDBMTestCase(unittest.TestCase):
|
||||||
self.assertEqual(sorted(f.keys()), sorted(self._dict))
|
self.assertEqual(sorted(f.keys()), sorted(self._dict))
|
||||||
f.close() # don't write
|
f.close() # don't write
|
||||||
|
|
||||||
|
@unittest.skipUnless(support.TESTFN_NONASCII,
|
||||||
|
'requires OS support of non-ASCII encodings')
|
||||||
|
def test_nonascii_filename(self):
|
||||||
|
filename = support.TESTFN_NONASCII
|
||||||
|
for suffix in ['.dir', '.dat', '.bak']:
|
||||||
|
self.addCleanup(support.unlink, filename + suffix)
|
||||||
|
with dumbdbm.open(filename, 'c') as db:
|
||||||
|
db[b'key'] = b'value'
|
||||||
|
self.assertTrue(os.path.exists(filename + '.dat'))
|
||||||
|
self.assertTrue(os.path.exists(filename + '.dir'))
|
||||||
|
with dumbdbm.open(filename, 'r') as db:
|
||||||
|
self.assertEqual(list(db.keys()), [b'key'])
|
||||||
|
self.assertTrue(b'key' in db)
|
||||||
|
self.assertEqual(db[b'key'], b'value')
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
_delete_files()
|
_delete_files()
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ from test import support
|
||||||
gdbm = support.import_module("dbm.gnu") #skip if not supported
|
gdbm = support.import_module("dbm.gnu") #skip if not supported
|
||||||
import unittest
|
import unittest
|
||||||
import os
|
import os
|
||||||
from test.support import TESTFN, unlink
|
from test.support import TESTFN, TESTFN_NONASCII, unlink
|
||||||
|
|
||||||
|
|
||||||
filename = TESTFN
|
filename = TESTFN
|
||||||
|
@ -93,5 +93,39 @@ class TestGdbm(unittest.TestCase):
|
||||||
self.assertEqual(str(cm.exception),
|
self.assertEqual(str(cm.exception),
|
||||||
"GDBM object has already been closed")
|
"GDBM object has already been closed")
|
||||||
|
|
||||||
|
def test_bytes(self):
|
||||||
|
with gdbm.open(filename, 'c') as db:
|
||||||
|
db[b'bytes key \xbd'] = b'bytes value \xbd'
|
||||||
|
with gdbm.open(filename, 'r') as db:
|
||||||
|
self.assertEqual(list(db.keys()), [b'bytes key \xbd'])
|
||||||
|
self.assertTrue(b'bytes key \xbd' in db)
|
||||||
|
self.assertEqual(db[b'bytes key \xbd'], b'bytes value \xbd')
|
||||||
|
|
||||||
|
def test_unicode(self):
|
||||||
|
with gdbm.open(filename, 'c') as db:
|
||||||
|
db['Unicode key \U0001f40d'] = 'Unicode value \U0001f40d'
|
||||||
|
with gdbm.open(filename, 'r') as db:
|
||||||
|
self.assertEqual(list(db.keys()), ['Unicode key \U0001f40d'.encode()])
|
||||||
|
self.assertTrue('Unicode key \U0001f40d'.encode() in db)
|
||||||
|
self.assertTrue('Unicode key \U0001f40d' in db)
|
||||||
|
self.assertEqual(db['Unicode key \U0001f40d'.encode()],
|
||||||
|
'Unicode value \U0001f40d'.encode())
|
||||||
|
self.assertEqual(db['Unicode key \U0001f40d'],
|
||||||
|
'Unicode value \U0001f40d'.encode())
|
||||||
|
|
||||||
|
@unittest.skipUnless(TESTFN_NONASCII,
|
||||||
|
'requires OS support of non-ASCII encodings')
|
||||||
|
def test_nonascii_filename(self):
|
||||||
|
filename = TESTFN_NONASCII
|
||||||
|
self.addCleanup(unlink, filename)
|
||||||
|
with gdbm.open(filename, 'c') as db:
|
||||||
|
db[b'key'] = b'value'
|
||||||
|
self.assertTrue(os.path.exists(filename))
|
||||||
|
with gdbm.open(filename, 'r') as db:
|
||||||
|
self.assertEqual(list(db.keys()), [b'key'])
|
||||||
|
self.assertTrue(b'key' in db)
|
||||||
|
self.assertEqual(db[b'key'], b'value')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from test import support
|
from test import support
|
||||||
support.import_module("dbm.ndbm") #skip if not supported
|
support.import_module("dbm.ndbm") #skip if not supported
|
||||||
|
import os
|
||||||
import unittest
|
import unittest
|
||||||
import dbm.ndbm
|
import dbm.ndbm
|
||||||
from dbm.ndbm import error
|
from dbm.ndbm import error
|
||||||
|
@ -47,6 +48,42 @@ class DbmTestCase(unittest.TestCase):
|
||||||
self.assertEqual(str(cm.exception),
|
self.assertEqual(str(cm.exception),
|
||||||
"DBM object has already been closed")
|
"DBM object has already been closed")
|
||||||
|
|
||||||
|
def test_bytes(self):
|
||||||
|
with dbm.ndbm.open(self.filename, 'c') as db:
|
||||||
|
db[b'bytes key \xbd'] = b'bytes value \xbd'
|
||||||
|
with dbm.ndbm.open(self.filename, 'r') as db:
|
||||||
|
self.assertEqual(list(db.keys()), [b'bytes key \xbd'])
|
||||||
|
self.assertTrue(b'bytes key \xbd' in db)
|
||||||
|
self.assertEqual(db[b'bytes key \xbd'], b'bytes value \xbd')
|
||||||
|
|
||||||
|
def test_unicode(self):
|
||||||
|
with dbm.ndbm.open(self.filename, 'c') as db:
|
||||||
|
db['Unicode key \U0001f40d'] = 'Unicode value \U0001f40d'
|
||||||
|
with dbm.ndbm.open(self.filename, 'r') as db:
|
||||||
|
self.assertEqual(list(db.keys()), ['Unicode key \U0001f40d'.encode()])
|
||||||
|
self.assertTrue('Unicode key \U0001f40d'.encode() in db)
|
||||||
|
self.assertTrue('Unicode key \U0001f40d' in db)
|
||||||
|
self.assertEqual(db['Unicode key \U0001f40d'.encode()],
|
||||||
|
'Unicode value \U0001f40d'.encode())
|
||||||
|
self.assertEqual(db['Unicode key \U0001f40d'],
|
||||||
|
'Unicode value \U0001f40d'.encode())
|
||||||
|
|
||||||
|
@unittest.skipUnless(support.TESTFN_NONASCII,
|
||||||
|
'requires OS support of non-ASCII encodings')
|
||||||
|
def test_nonascii_filename(self):
|
||||||
|
filename = support.TESTFN_NONASCII
|
||||||
|
for suffix in ['', '.pag', '.dir', '.db']:
|
||||||
|
self.addCleanup(support.unlink, filename + suffix)
|
||||||
|
with dbm.ndbm.open(filename, 'c') as db:
|
||||||
|
db[b'key'] = b'value'
|
||||||
|
self.assertTrue(any(os.path.exists(filename + suffix)
|
||||||
|
for suffix in ['', '.pag', '.dir', '.db']))
|
||||||
|
with dbm.ndbm.open(filename, 'r') as db:
|
||||||
|
self.assertEqual(list(db.keys()), [b'key'])
|
||||||
|
self.assertTrue(b'key' in db)
|
||||||
|
self.assertEqual(db[b'key'], b'value')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
dbm.open() now encodes filename with the filesystem encoding rather than
|
||||||
|
default encoding.
|
|
@ -412,7 +412,7 @@ static PyTypeObject Dbmtype = {
|
||||||
|
|
||||||
_dbm.open as dbmopen
|
_dbm.open as dbmopen
|
||||||
|
|
||||||
filename: str
|
filename: unicode
|
||||||
The filename to open.
|
The filename to open.
|
||||||
|
|
||||||
flags: str="r"
|
flags: str="r"
|
||||||
|
@ -429,9 +429,9 @@ Return a database object.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
dbmopen_impl(PyObject *module, const char *filename, const char *flags,
|
dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
|
||||||
int mode)
|
int mode)
|
||||||
/*[clinic end generated code: output=5fade8cf16e0755f input=226334bade5764e6]*/
|
/*[clinic end generated code: output=9527750f5df90764 input=376a9d903a50df59]*/
|
||||||
{
|
{
|
||||||
int iflags;
|
int iflags;
|
||||||
|
|
||||||
|
@ -450,7 +450,20 @@ dbmopen_impl(PyObject *module, const char *filename, const char *flags,
|
||||||
"arg 2 to open should be 'r', 'w', 'c', or 'n'");
|
"arg 2 to open should be 'r', 'w', 'c', or 'n'");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return newdbmobject(filename, iflags, mode);
|
|
||||||
|
PyObject *filenamebytes = PyUnicode_EncodeFSDefault(filename);
|
||||||
|
if (filenamebytes == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
const char *name = PyBytes_AS_STRING(filenamebytes);
|
||||||
|
if (strlen(name) != (size_t)PyBytes_GET_SIZE(filenamebytes)) {
|
||||||
|
Py_DECREF(filenamebytes);
|
||||||
|
PyErr_SetString(PyExc_ValueError, "embedded null character");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyObject *self = newdbmobject(name, iflags, mode);
|
||||||
|
Py_DECREF(filenamebytes);
|
||||||
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyMethodDef dbmmodule_methods[] = {
|
static PyMethodDef dbmmodule_methods[] = {
|
||||||
|
|
|
@ -527,7 +527,7 @@ static PyTypeObject Dbmtype = {
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
_gdbm.open as dbmopen
|
_gdbm.open as dbmopen
|
||||||
filename as name: str
|
filename: unicode
|
||||||
flags: str="r"
|
flags: str="r"
|
||||||
mode: int(py_default="0o666") = 0o666
|
mode: int(py_default="0o666") = 0o666
|
||||||
/
|
/
|
||||||
|
@ -557,8 +557,9 @@ when the database has to be created. It defaults to octal 0o666.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
dbmopen_impl(PyObject *module, const char *name, const char *flags, int mode)
|
dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
|
||||||
/*[clinic end generated code: output=31aa1bafdf5da688 input=55563cd60e51984a]*/
|
int mode)
|
||||||
|
/*[clinic end generated code: output=9527750f5df90764 input=3be0b0875974b928]*/
|
||||||
{
|
{
|
||||||
int iflags;
|
int iflags;
|
||||||
|
|
||||||
|
@ -606,7 +607,19 @@ dbmopen_impl(PyObject *module, const char *name, const char *flags, int mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return newdbmobject(name, iflags, mode);
|
PyObject *filenamebytes = PyUnicode_EncodeFSDefault(filename);
|
||||||
|
if (filenamebytes == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
const char *name = PyBytes_AS_STRING(filenamebytes);
|
||||||
|
if (strlen(name) != (size_t)PyBytes_GET_SIZE(filenamebytes)) {
|
||||||
|
Py_DECREF(filenamebytes);
|
||||||
|
PyErr_SetString(PyExc_ValueError, "embedded null character");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyObject *self = newdbmobject(name, iflags, mode);
|
||||||
|
Py_DECREF(filenamebytes);
|
||||||
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char dbmmodule_open_flags[] = "rwcn"
|
static const char dbmmodule_open_flags[] = "rwcn"
|
||||||
|
|
|
@ -121,18 +121,18 @@ PyDoc_STRVAR(dbmopen__doc__,
|
||||||
{"open", (PyCFunction)dbmopen, METH_FASTCALL, dbmopen__doc__},
|
{"open", (PyCFunction)dbmopen, METH_FASTCALL, dbmopen__doc__},
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
dbmopen_impl(PyObject *module, const char *filename, const char *flags,
|
dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
|
||||||
int mode);
|
int mode);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
dbmopen(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
dbmopen(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
||||||
{
|
{
|
||||||
PyObject *return_value = NULL;
|
PyObject *return_value = NULL;
|
||||||
const char *filename;
|
PyObject *filename;
|
||||||
const char *flags = "r";
|
const char *flags = "r";
|
||||||
int mode = 438;
|
int mode = 438;
|
||||||
|
|
||||||
if (!_PyArg_ParseStack(args, nargs, "s|si:open",
|
if (!_PyArg_ParseStack(args, nargs, "U|si:open",
|
||||||
&filename, &flags, &mode)) {
|
&filename, &flags, &mode)) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
@ -141,4 +141,4 @@ dbmopen(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=8ce71abac849155f input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=5c858b4080a011a4 input=a9049054013a1b77]*/
|
||||||
|
|
|
@ -234,23 +234,24 @@ PyDoc_STRVAR(dbmopen__doc__,
|
||||||
{"open", (PyCFunction)dbmopen, METH_FASTCALL, dbmopen__doc__},
|
{"open", (PyCFunction)dbmopen, METH_FASTCALL, dbmopen__doc__},
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
dbmopen_impl(PyObject *module, const char *name, const char *flags, int mode);
|
dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
|
||||||
|
int mode);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
dbmopen(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
dbmopen(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
||||||
{
|
{
|
||||||
PyObject *return_value = NULL;
|
PyObject *return_value = NULL;
|
||||||
const char *name;
|
PyObject *filename;
|
||||||
const char *flags = "r";
|
const char *flags = "r";
|
||||||
int mode = 438;
|
int mode = 438;
|
||||||
|
|
||||||
if (!_PyArg_ParseStack(args, nargs, "s|si:open",
|
if (!_PyArg_ParseStack(args, nargs, "U|si:open",
|
||||||
&name, &flags, &mode)) {
|
&filename, &flags, &mode)) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
return_value = dbmopen_impl(module, name, flags, mode);
|
return_value = dbmopen_impl(module, filename, flags, mode);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=dc0aca8c00055d02 input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=dec05ff9c5aeaeae input=a9049054013a1b77]*/
|
||||||
|
|
Loading…
Reference in New Issue