Skip to content
Merged
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
10 changes: 10 additions & 0 deletions Lib/test/pythoninfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,15 @@ def collect_cc(info_add):
info_add('CC.version', text)


def collect_gdbm(info_add):
try:
import _gdbm
except ImportError:
return

info_add('gdbm.GDBM_VERSION', '.'.join(map(str, _gdbm._GDBM_VERSION)))


def collect_info(info):
error = False
info_add = info.add
Expand Down Expand Up @@ -552,6 +561,7 @@ def collect_info(info):
collect_testcapi,
collect_resource,
collect_cc,
collect_gdbm,

# Collecting from tests should be last as they have side effects.
collect_test_socket,
Expand Down
11 changes: 11 additions & 0 deletions Lib/test/test_dbm_gnu.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@
filename = TESTFN

class TestGdbm(unittest.TestCase):
@staticmethod
def setUpClass():
if support.verbose:
try:
import _gdbm
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe from _gdbm import _GDBM_VERSION?

version = _gdbm._GDBM_VERSION
except (ImportError, AttributeError):
pass
else:
print(f"gdbm version: {version}")

def setUp(self):
self.g = None

Expand Down
39 changes: 31 additions & 8 deletions Modules/_gdbmmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -654,20 +654,43 @@ static struct PyModuleDef _gdbmmodule = {

PyMODINIT_FUNC
PyInit__gdbm(void) {
PyObject *m, *d, *s;
PyObject *m;

if (PyType_Ready(&Dbmtype) < 0)
return NULL;
m = PyModule_Create(&_gdbmmodule);
if (m == NULL)
if (m == NULL) {
return NULL;
d = PyModule_GetDict(m);
}

DbmError = PyErr_NewException("_gdbm.error", PyExc_OSError, NULL);
if (DbmError != NULL) {
PyDict_SetItemString(d, "error", DbmError);
s = PyUnicode_FromString(dbmmodule_open_flags);
PyDict_SetItemString(d, "open_flags", s);
Py_DECREF(s);
if (DbmError == NULL) {
goto error;
}
Py_INCREF(DbmError);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this? PyErr_NewException returns a new reference.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure, but it seems like most modules do the same:

socktemodule.c:

    socket_herror = PyErr_NewException("socket.herror",
                                       PyExc_OSError, NULL);
    if (socket_herror == NULL)
        return NULL;
    Py_INCREF(socket_herror);
    PyModule_AddObject(m, "herror", socket_herror);

signalmodule.c:

    ItimerError = PyErr_NewException("signal.ItimerError",
            PyExc_OSError, NULL);
    if (ItimerError != NULL)
        PyDict_SetItemString(d, "ItimerError", ItimerError);

Note: PyModule_AddObject() is weird, it decrements the reference counter on success...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's documented to steal a reference, though from the implementation, only on success. Module init functions seem usually not written carefully about this kind error. @serhiy-storchaka

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Module init functions seem usually not written carefully about this kind error.

If you want to fix that, I would suggest to fix it in a different PR. Maybe even open a new bug to track that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an open issue for this. It is not easy. You correctly use PyModule_AddObject() (most code in the stdlib doesn't).

if (PyModule_AddObject(m, "error", DbmError) < 0) {
Py_DECREF(DbmError);
goto error;
}

if (PyModule_AddStringConstant(m, "open_flags",
dbmmodule_open_flags) < 0) {
goto error;
}

PyObject *obj = Py_BuildValue("iii", GDBM_VERSION_MAJOR,
GDBM_VERSION_MINOR, GDBM_VERSION_PATCH);
if (obj == NULL) {
goto error;
}
if (PyModule_AddObject(m, "_GDBM_VERSION", obj) < 0) {
Py_DECREF(obj);
goto error;
}

return m;

error:
Py_DECREF(m);
return NULL;
}