summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorDong-hee Na <donghee.na92@gmail.com>2020-06-16 16:41:23 (GMT)
committerGitHub <noreply@github.com>2020-06-16 16:41:23 (GMT)
commitc4862e333ab405dd5789b4061222db1982147de4 (patch)
tree954c3f99e82f3f5ad32f87348c7c676d8cfd7628 /Modules
parent51c5896b6205911d29ac07f167ec7f3cf1cb600d (diff)
downloadcpython-c4862e333ab405dd5789b4061222db1982147de4.zip
cpython-c4862e333ab405dd5789b4061222db1982147de4.tar.gz
cpython-c4862e333ab405dd5789b4061222db1982147de4.tar.bz2
bpo-1635741: Port _gdbm module to multiphase initialization (GH-20920)
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_gdbmmodule.c374
-rw-r--r--Modules/clinic/_gdbmmodule.c.h103
2 files changed, 280 insertions, 197 deletions
diff --git a/Modules/_gdbmmodule.c b/Modules/_gdbmmodule.c
index dd4c6b1..9e843ac 100644
--- a/Modules/_gdbmmodule.c
+++ b/Modules/_gdbmmodule.c
@@ -1,5 +1,5 @@
-/* DBM module using dictionary interface */
+/* GDBM module using dictionary interface */
/* Author: Anthony Baxter, after dbmmodule.c */
/* Doc strings: Mitch Chapman */
@@ -16,11 +16,24 @@
extern const char * gdbm_strerror(gdbm_error);
#endif
+typedef struct {
+ PyTypeObject *gdbm_type;
+ PyObject *gdbm_error;
+} _gdbm_state;
+
+static inline _gdbm_state*
+get_gdbm_state(PyObject *module)
+{
+ void *state = PyModule_GetState(module);
+ assert(state != NULL);
+ return (_gdbm_state *)state;
+}
+
/*[clinic input]
module _gdbm
-class _gdbm.gdbm "dbmobject *" "&Dbmtype"
+class _gdbm.gdbm "gdbmobject *" "&Gdbmtype"
[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=113927c6170729b2]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=38ae71cedfc7172b]*/
PyDoc_STRVAR(gdbmmodule__doc__,
"This module provides an interface to the GNU DBM (GDBM) library.\n\
@@ -38,20 +51,15 @@ typedef struct {
PyObject_HEAD
Py_ssize_t di_size; /* -1 means recompute */
GDBM_FILE di_dbm;
-} dbmobject;
-
-static PyTypeObject Dbmtype;
+} gdbmobject;
#include "clinic/_gdbmmodule.c.h"
-#define is_dbmobject(v) Py_IS_TYPE(v, &Dbmtype)
-#define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
- { PyErr_SetString(DbmError, "GDBM object has already been closed"); \
- return NULL; }
-
-
-
-static PyObject *DbmError;
+#define check_gdbmobject_open(v, err) \
+ if ((v)->di_dbm == NULL) { \
+ PyErr_SetString(err, "GDBM object has already been closed"); \
+ return NULL; \
+ }
PyDoc_STRVAR(gdbm_object__doc__,
"This object represents a GDBM database.\n\
@@ -64,20 +72,21 @@ GDBM objects also support additional operations such as firstkey,\n\
nextkey, reorganize, and sync.");
static PyObject *
-newdbmobject(const char *file, int flags, int mode)
+newgdbmobject(_gdbm_state *state, const char *file, int flags, int mode)
{
- dbmobject *dp;
-
- dp = PyObject_New(dbmobject, &Dbmtype);
- if (dp == NULL)
+ gdbmobject *dp = PyObject_New(gdbmobject, state->gdbm_type);
+ if (dp == NULL) {
return NULL;
+ }
dp->di_size = -1;
errno = 0;
if ((dp->di_dbm = gdbm_open((char *)file, 0, flags, mode, NULL)) == 0) {
- if (errno != 0)
- PyErr_SetFromErrnoWithFilename(DbmError, file);
- else
- PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
+ if (errno != 0) {
+ PyErr_SetFromErrnoWithFilename(state->gdbm_error, file);
+ }
+ else {
+ PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
+ }
Py_DECREF(dp);
return NULL;
}
@@ -87,18 +96,22 @@ newdbmobject(const char *file, int flags, int mode)
/* Methods */
static void
-dbm_dealloc(dbmobject *dp)
+gdbm_dealloc(gdbmobject *dp)
{
- if (dp->di_dbm)
+ if (dp->di_dbm) {
gdbm_close(dp->di_dbm);
- PyObject_Del(dp);
+ }
+ PyTypeObject *tp = Py_TYPE(dp);
+ tp->tp_free(dp);
+ Py_DECREF(tp);
}
static Py_ssize_t
-dbm_length(dbmobject *dp)
+gdbm_length(gdbmobject *dp)
{
+ _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
if (dp->di_dbm == NULL) {
- PyErr_SetString(DbmError, "GDBM object has already been closed");
+ PyErr_SetString(state->gdbm_error, "GDBM object has already been closed");
return -1;
}
if (dp->di_size < 0) {
@@ -107,10 +120,10 @@ dbm_length(dbmobject *dp)
gdbm_count_t count;
if (gdbm_count(dp->di_dbm, &count) == -1) {
if (errno != 0) {
- PyErr_SetFromErrno(DbmError);
+ PyErr_SetFromErrno(state->gdbm_error);
}
else {
- PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
+ PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
}
return -1;
}
@@ -161,16 +174,17 @@ parse_datum(PyObject *o, datum *d, const char *failmsg)
}
static PyObject *
-dbm_subscript(dbmobject *dp, PyObject *key)
+gdbm_subscript(gdbmobject *dp, PyObject *key)
{
PyObject *v;
datum drec, krec;
+ _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
if (!parse_datum(key, &krec, NULL)) {
return NULL;
}
if (dp->di_dbm == NULL) {
- PyErr_SetString(DbmError,
+ PyErr_SetString(state->gdbm_error,
"GDBM object has already been closed");
return NULL;
}
@@ -195,12 +209,12 @@ Get the value for key, or default if not present.
[clinic start generated code]*/
static PyObject *
-_gdbm_gdbm_get_impl(dbmobject *self, PyObject *key, PyObject *default_value)
-/*[clinic end generated code: output=19b7c585ad4f554a input=a9c20423f34c17b6]*/
+_gdbm_gdbm_get_impl(gdbmobject *self, PyObject *key, PyObject *default_value)
+/*[clinic end generated code: output=92421838f3a852f4 input=a9c20423f34c17b6]*/
{
PyObject *res;
- res = dbm_subscript(self, key);
+ res = gdbm_subscript(self, key);
if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
PyErr_Clear();
Py_INCREF(default_value);
@@ -210,16 +224,17 @@ _gdbm_gdbm_get_impl(dbmobject *self, PyObject *key, PyObject *default_value)
}
static int
-dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
+gdbm_ass_sub(gdbmobject *dp, PyObject *v, PyObject *w)
{
datum krec, drec;
const char *failmsg = "gdbm mappings have bytes or string indices only";
+ _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
if (!parse_datum(v, &krec, failmsg)) {
return -1;
}
if (dp->di_dbm == NULL) {
- PyErr_SetString(DbmError,
+ PyErr_SetString(state->gdbm_error,
"GDBM object has already been closed");
return -1;
}
@@ -230,7 +245,7 @@ dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
PyErr_SetObject(PyExc_KeyError, v);
}
else {
- PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
+ PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
}
return -1;
}
@@ -242,9 +257,9 @@ dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
errno = 0;
if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) {
if (errno != 0)
- PyErr_SetFromErrno(DbmError);
+ PyErr_SetFromErrno(state->gdbm_error);
else
- PyErr_SetString(DbmError,
+ PyErr_SetString(state->gdbm_error,
gdbm_strerror(gdbm_errno));
return -1;
}
@@ -263,28 +278,22 @@ Get value for key, or set it to default and return default if not present.
[clinic start generated code]*/
static PyObject *
-_gdbm_gdbm_setdefault_impl(dbmobject *self, PyObject *key,
+_gdbm_gdbm_setdefault_impl(gdbmobject *self, PyObject *key,
PyObject *default_value)
-/*[clinic end generated code: output=88760ee520329012 input=0db46b69e9680171]*/
+/*[clinic end generated code: output=f3246e880509f142 input=0db46b69e9680171]*/
{
PyObject *res;
- res = dbm_subscript(self, key);
+ res = gdbm_subscript(self, key);
if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
PyErr_Clear();
- if (dbm_ass_sub(self, key, default_value) < 0)
+ if (gdbm_ass_sub(self, key, default_value) < 0)
return NULL;
- return dbm_subscript(self, key);
+ return gdbm_subscript(self, key);
}
return res;
}
-static PyMappingMethods dbm_as_mapping = {
- (lenfunc)dbm_length, /*mp_length*/
- (binaryfunc)dbm_subscript, /*mp_subscript*/
- (objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
-};
-
/*[clinic input]
_gdbm.gdbm.close
@@ -292,11 +301,12 @@ Close the database.
[clinic start generated code]*/
static PyObject *
-_gdbm_gdbm_close_impl(dbmobject *self)
-/*[clinic end generated code: output=23512a594598b563 input=0a203447379b45fd]*/
+_gdbm_gdbm_close_impl(gdbmobject *self)
+/*[clinic end generated code: output=f5abb4d6bb9e52d5 input=0a203447379b45fd]*/
{
- if (self->di_dbm)
+ if (self->di_dbm) {
gdbm_close(self->di_dbm);
+ }
self->di_dbm = NULL;
Py_RETURN_NONE;
}
@@ -305,22 +315,27 @@ _gdbm_gdbm_close_impl(dbmobject *self)
/*[clinic input]
_gdbm.gdbm.keys
+ cls: defining_class
+
Get a list of all keys in the database.
[clinic start generated code]*/
static PyObject *
-_gdbm_gdbm_keys_impl(dbmobject *self)
-/*[clinic end generated code: output=cb4b1776c3645dcc input=1832ee0a3132cfaf]*/
+_gdbm_gdbm_keys_impl(gdbmobject *self, PyTypeObject *cls)
+/*[clinic end generated code: output=c24b824e81404755 input=1428b7c79703d7d5]*/
{
PyObject *v, *item;
datum key, nextkey;
int err;
- if (self == NULL || !is_dbmobject(self)) {
+ _gdbm_state *state = PyType_GetModuleState(cls);
+ assert(state != NULL);
+
+ if (self == NULL || !Py_IS_TYPE(self, state->gdbm_type)) {
PyErr_BadInternalCall();
return NULL;
}
- check_dbmobject_open(self);
+ check_gdbmobject_open(self, state->gdbm_error);
v = PyList_New(0);
if (v == NULL)
@@ -349,14 +364,15 @@ _gdbm_gdbm_keys_impl(dbmobject *self)
}
static int
-dbm_contains(PyObject *self, PyObject *arg)
+gdbm_contains(PyObject *self, PyObject *arg)
{
- dbmobject *dp = (dbmobject *)self;
+ gdbmobject *dp = (gdbmobject *)self;
datum key;
Py_ssize_t size;
+ _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
if ((dp)->di_dbm == NULL) {
- PyErr_SetString(DbmError,
+ PyErr_SetString(state->gdbm_error,
"GDBM object has already been closed");
return -1;
}
@@ -379,22 +395,11 @@ dbm_contains(PyObject *self, PyObject *arg)
return gdbm_exists(dp->di_dbm, key);
}
-static PySequenceMethods dbm_as_sequence = {
- 0, /* sq_length */
- 0, /* sq_concat */
- 0, /* sq_repeat */
- 0, /* sq_item */
- 0, /* sq_slice */
- 0, /* sq_ass_item */
- 0, /* sq_ass_slice */
- dbm_contains, /* sq_contains */
- 0, /* sq_inplace_concat */
- 0, /* sq_inplace_repeat */
-};
-
/*[clinic input]
_gdbm.gdbm.firstkey
+ cls: defining_class
+
Return the starting key for the traversal.
It's possible to loop over every key in the database using this method
@@ -403,13 +408,15 @@ hash values, and won't be sorted by the key values.
[clinic start generated code]*/
static PyObject *
-_gdbm_gdbm_firstkey_impl(dbmobject *self)
-/*[clinic end generated code: output=9ff85628d84b65d2 input=0dbd6a335d69bba0]*/
+_gdbm_gdbm_firstkey_impl(gdbmobject *self, PyTypeObject *cls)
+/*[clinic end generated code: output=139275e9c8b60827 input=ed8782a029a5d299]*/
{
PyObject *v;
datum key;
+ _gdbm_state *state = PyType_GetModuleState(cls);
+ assert(state != NULL);
- check_dbmobject_open(self);
+ check_gdbmobject_open(self, state->gdbm_error);
key = gdbm_firstkey(self->di_dbm);
if (key.dptr) {
v = PyBytes_FromStringAndSize(key.dptr, key.dsize);
@@ -424,6 +431,7 @@ _gdbm_gdbm_firstkey_impl(dbmobject *self)
/*[clinic input]
_gdbm.gdbm.nextkey
+ cls: defining_class
key: str(accept={str, robuffer}, zeroes=True)
/
@@ -439,16 +447,18 @@ to create a list in memory that contains them all:
[clinic start generated code]*/
static PyObject *
-_gdbm_gdbm_nextkey_impl(dbmobject *self, const char *key,
+_gdbm_gdbm_nextkey_impl(gdbmobject *self, PyTypeObject *cls, const char *key,
Py_ssize_clean_t key_length)
-/*[clinic end generated code: output=192ab892de6eb2f6 input=1f1606943614e36f]*/
+/*[clinic end generated code: output=204964441fdbaf02 input=fcf6a51a96ce0172]*/
{
PyObject *v;
datum dbm_key, nextkey;
+ _gdbm_state *state = PyType_GetModuleState(cls);
+ assert(state != NULL);
dbm_key.dptr = (char *)key;
dbm_key.dsize = key_length;
- check_dbmobject_open(self);
+ check_gdbmobject_open(self, state->gdbm_error);
nextkey = gdbm_nextkey(self->di_dbm, dbm_key);
if (nextkey.dptr) {
v = PyBytes_FromStringAndSize(nextkey.dptr, nextkey.dsize);
@@ -463,6 +473,8 @@ _gdbm_gdbm_nextkey_impl(dbmobject *self, const char *key,
/*[clinic input]
_gdbm.gdbm.reorganize
+ cls: defining_class
+
Reorganize the database.
If you have carried out a lot of deletions and would like to shrink
@@ -473,16 +485,18 @@ kept and reused as new (key,value) pairs are added.
[clinic start generated code]*/
static PyObject *
-_gdbm_gdbm_reorganize_impl(dbmobject *self)
-/*[clinic end generated code: output=38d9624df92e961d input=f6bea85bcfd40dd2]*/
+_gdbm_gdbm_reorganize_impl(gdbmobject *self, PyTypeObject *cls)
+/*[clinic end generated code: output=d77c69e8e3dd644a input=e1359faeef844e46]*/
{
- check_dbmobject_open(self);
+ _gdbm_state *state = PyType_GetModuleState(cls);
+ assert(state != NULL);
+ check_gdbmobject_open(self, state->gdbm_error);
errno = 0;
if (gdbm_reorganize(self->di_dbm) < 0) {
if (errno != 0)
- PyErr_SetFromErrno(DbmError);
+ PyErr_SetFromErrno(state->gdbm_error);
else
- PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
+ PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
return NULL;
}
Py_RETURN_NONE;
@@ -491,6 +505,8 @@ _gdbm_gdbm_reorganize_impl(dbmobject *self)
/*[clinic input]
_gdbm.gdbm.sync
+ cls: defining_class
+
Flush the database to the disk file.
When the database has been opened in fast mode, this method forces
@@ -498,29 +514,31 @@ any unwritten data to be written to the disk.
[clinic start generated code]*/
static PyObject *
-_gdbm_gdbm_sync_impl(dbmobject *self)
-/*[clinic end generated code: output=488b15f47028f125 input=2a47d2c9e153ab8a]*/
+_gdbm_gdbm_sync_impl(gdbmobject *self, PyTypeObject *cls)
+/*[clinic end generated code: output=bb680a2035c3f592 input=3d749235f79b6f2a]*/
{
- check_dbmobject_open(self);
+ _gdbm_state *state = PyType_GetModuleState(cls);
+ assert(state != NULL);
+ check_gdbmobject_open(self, state->gdbm_error);
gdbm_sync(self->di_dbm);
Py_RETURN_NONE;
}
static PyObject *
-dbm__enter__(PyObject *self, PyObject *args)
+gdbm__enter__(PyObject *self, PyObject *args)
{
Py_INCREF(self);
return self;
}
static PyObject *
-dbm__exit__(PyObject *self, PyObject *args)
+gdbm__exit__(PyObject *self, PyObject *args)
{
_Py_IDENTIFIER(close);
return _PyObject_CallMethodIdNoArgs(self, &PyId_close);
}
-static PyMethodDef dbm_methods[] = {
+static PyMethodDef gdbm_methods[] = {
_GDBM_GDBM_CLOSE_METHODDEF
_GDBM_GDBM_KEYS_METHODDEF
_GDBM_GDBM_FIRSTKEY_METHODDEF
@@ -529,46 +547,38 @@ static PyMethodDef dbm_methods[] = {
_GDBM_GDBM_SYNC_METHODDEF
_GDBM_GDBM_GET_METHODDEF
_GDBM_GDBM_SETDEFAULT_METHODDEF
- {"__enter__", dbm__enter__, METH_NOARGS, NULL},
- {"__exit__", dbm__exit__, METH_VARARGS, NULL},
+ {"__enter__", gdbm__enter__, METH_NOARGS, NULL},
+ {"__exit__", gdbm__exit__, METH_VARARGS, NULL},
{NULL, NULL} /* sentinel */
};
-static PyTypeObject Dbmtype = {
- PyVarObject_HEAD_INIT(0, 0)
- "_gdbm.gdbm",
- sizeof(dbmobject),
- 0,
- (destructor)dbm_dealloc, /*tp_dealloc*/
- 0, /*tp_vectorcall_offset*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_as_async*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- &dbm_as_sequence, /*tp_as_sequence*/
- &dbm_as_mapping, /*tp_as_mapping*/
- 0, /*tp_hash*/
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT, /*tp_xxx4*/
- gdbm_object__doc__, /*tp_doc*/
- 0, /*tp_traverse*/
- 0, /*tp_clear*/
- 0, /*tp_richcompare*/
- 0, /*tp_weaklistoffset*/
- 0, /*tp_iter*/
- 0, /*tp_iternext*/
- dbm_methods, /*tp_methods*/
+static PyType_Slot gdbmtype_spec_slots[] = {
+ {Py_tp_dealloc, gdbm_dealloc},
+ {Py_tp_methods, gdbm_methods},
+ {Py_sq_contains, gdbm_contains},
+ {Py_mp_length, gdbm_length},
+ {Py_mp_subscript, gdbm_subscript},
+ {Py_mp_ass_subscript, gdbm_ass_sub},
+ {Py_tp_doc, (char*)gdbm_object__doc__},
+ {0, 0}
+};
+
+static PyType_Spec gdbmtype_spec = {
+ .name = "_gdbm.gdbm",
+ .basicsize = sizeof(gdbmobject),
+ // Calling PyType_GetModuleState() on a subclass is not safe.
+ // dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag
+ // which prevents to create a subclass.
+ // So calling PyType_GetModuleState() in this file is always safe.
+ .flags = Py_TPFLAGS_DEFAULT,
+ .slots = gdbmtype_spec_slots,
};
/* ----------------------------------------------------------------- */
/*[clinic input]
_gdbm.open as dbmopen
+
filename: unicode
flags: str="r"
mode: int(py_default="0o666") = 0o666
@@ -601,9 +611,11 @@ 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=812b7d74399ceb0e]*/
{
int iflags;
+ _gdbm_state *state = get_gdbm_state(module);
+ assert(state != NULL);
switch (flags[0]) {
case 'r':
@@ -619,7 +631,7 @@ dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
iflags = GDBM_NEWDB;
break;
default:
- PyErr_SetString(DbmError,
+ PyErr_SetString(state->gdbm_error,
"First flag must be one of 'r', 'w', 'c' or 'n'");
return NULL;
}
@@ -644,7 +656,7 @@ dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
default:
PyOS_snprintf(buf, sizeof(buf), "Flag '%c' is not supported.",
*flags);
- PyErr_SetString(DbmError, buf);
+ PyErr_SetString(state->gdbm_error, buf);
return NULL;
}
}
@@ -659,12 +671,12 @@ dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
PyErr_SetString(PyExc_ValueError, "embedded null character");
return NULL;
}
- PyObject *self = newdbmobject(name, iflags, mode);
+ PyObject *self = newgdbmobject(state, name, iflags, mode);
Py_DECREF(filenamebytes);
return self;
}
-static const char dbmmodule_open_flags[] = "rwcn"
+static const char gdbmmodule_open_flags[] = "rwcn"
#ifdef GDBM_FAST
"f"
#endif
@@ -676,48 +688,30 @@ static const char dbmmodule_open_flags[] = "rwcn"
#endif
;
-static PyMethodDef dbmmodule_methods[] = {
+static PyMethodDef _gdbm_module_methods[] = {
DBMOPEN_METHODDEF
{ 0, 0 },
};
-
-static struct PyModuleDef _gdbmmodule = {
- PyModuleDef_HEAD_INIT,
- "_gdbm",
- gdbmmodule__doc__,
- -1,
- dbmmodule_methods,
- NULL,
- NULL,
- NULL,
- NULL
-};
-
-PyMODINIT_FUNC
-PyInit__gdbm(void) {
- PyObject *m;
-
- if (PyType_Ready(&Dbmtype) < 0)
- return NULL;
- m = PyModule_Create(&_gdbmmodule);
- if (m == NULL) {
- return NULL;
+static int
+_gdbm_exec(PyObject *module)
+{
+ _gdbm_state *state = get_gdbm_state(module);
+ state->gdbm_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
+ &gdbmtype_spec, NULL);
+ if (state->gdbm_type == NULL) {
+ return -1;
}
-
- DbmError = PyErr_NewException("_gdbm.error", PyExc_OSError, NULL);
- if (DbmError == NULL) {
- goto error;
+ state->gdbm_error = PyErr_NewException("_gdbm.error", PyExc_OSError, NULL);
+ if (state->gdbm_error == NULL) {
+ return -1;
}
- Py_INCREF(DbmError);
- if (PyModule_AddObject(m, "error", DbmError) < 0) {
- Py_DECREF(DbmError);
- goto error;
+ if (PyModule_AddType(module, (PyTypeObject *)state->gdbm_error) < 0) {
+ return -1;
}
-
- if (PyModule_AddStringConstant(m, "open_flags",
- dbmmodule_open_flags) < 0) {
- goto error;
+ if (PyModule_AddStringConstant(module, "open_flags",
+ gdbmmodule_open_flags) < 0) {
+ return -1;
}
#if defined(GDBM_VERSION_MAJOR) && defined(GDBM_VERSION_MINOR) && \
@@ -725,17 +719,59 @@ PyInit__gdbm(void) {
PyObject *obj = Py_BuildValue("iii", GDBM_VERSION_MAJOR,
GDBM_VERSION_MINOR, GDBM_VERSION_PATCH);
if (obj == NULL) {
- goto error;
+ return -1;
}
- if (PyModule_AddObject(m, "_GDBM_VERSION", obj) < 0) {
+ if (PyModule_AddObject(module, "_GDBM_VERSION", obj) < 0) {
Py_DECREF(obj);
- goto error;
+ return -1;
}
#endif
+ return 0;
+}
- return m;
+static int
+_gdbm_module_traverse(PyObject *module, visitproc visit, void *arg)
+{
+ _gdbm_state *state = get_gdbm_state(module);
+ Py_VISIT(state->gdbm_error);
+ Py_VISIT(state->gdbm_type);
+ return 0;
+}
-error:
- Py_DECREF(m);
- return NULL;
+static int
+_gdbm_module_clear(PyObject *module)
+{
+ _gdbm_state *state = get_gdbm_state(module);
+ Py_CLEAR(state->gdbm_error);
+ Py_CLEAR(state->gdbm_type);
+ return 0;
+}
+
+static void
+_gdbm_module_free(void *module)
+{
+ _gdbm_module_clear((PyObject *)module);
+}
+
+static PyModuleDef_Slot _gdbm_module_slots[] = {
+ {Py_mod_exec, _gdbm_exec},
+ {0, NULL}
+};
+
+static struct PyModuleDef _gdbmmodule = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "_gdbm",
+ .m_doc = gdbmmodule__doc__,
+ .m_size = sizeof(_gdbm_state),
+ .m_methods = _gdbm_module_methods,
+ .m_slots = _gdbm_module_slots,
+ .m_traverse = _gdbm_module_traverse,
+ .m_clear = _gdbm_module_clear,
+ .m_free = _gdbm_module_free,
+};
+
+PyMODINIT_FUNC
+PyInit__gdbm(void)
+{
+ return PyModuleDef_Init(&_gdbmmodule);
}
diff --git a/Modules/clinic/_gdbmmodule.c.h b/Modules/clinic/_gdbmmodule.c.h
index 1951591..ffd2179 100644
--- a/Modules/clinic/_gdbmmodule.c.h
+++ b/Modules/clinic/_gdbmmodule.c.h
@@ -12,10 +12,10 @@ PyDoc_STRVAR(_gdbm_gdbm_get__doc__,
{"get", (PyCFunction)(void(*)(void))_gdbm_gdbm_get, METH_FASTCALL, _gdbm_gdbm_get__doc__},
static PyObject *
-_gdbm_gdbm_get_impl(dbmobject *self, PyObject *key, PyObject *default_value);
+_gdbm_gdbm_get_impl(gdbmobject *self, PyObject *key, PyObject *default_value);
static PyObject *
-_gdbm_gdbm_get(dbmobject *self, PyObject *const *args, Py_ssize_t nargs)
+_gdbm_gdbm_get(gdbmobject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *key;
@@ -46,11 +46,11 @@ PyDoc_STRVAR(_gdbm_gdbm_setdefault__doc__,
{"setdefault", (PyCFunction)(void(*)(void))_gdbm_gdbm_setdefault, METH_FASTCALL, _gdbm_gdbm_setdefault__doc__},
static PyObject *
-_gdbm_gdbm_setdefault_impl(dbmobject *self, PyObject *key,
+_gdbm_gdbm_setdefault_impl(gdbmobject *self, PyObject *key,
PyObject *default_value);
static PyObject *
-_gdbm_gdbm_setdefault(dbmobject *self, PyObject *const *args, Py_ssize_t nargs)
+_gdbm_gdbm_setdefault(gdbmobject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *key;
@@ -81,10 +81,10 @@ PyDoc_STRVAR(_gdbm_gdbm_close__doc__,
{"close", (PyCFunction)_gdbm_gdbm_close, METH_NOARGS, _gdbm_gdbm_close__doc__},
static PyObject *
-_gdbm_gdbm_close_impl(dbmobject *self);
+_gdbm_gdbm_close_impl(gdbmobject *self);
static PyObject *
-_gdbm_gdbm_close(dbmobject *self, PyObject *Py_UNUSED(ignored))
+_gdbm_gdbm_close(gdbmobject *self, PyObject *Py_UNUSED(ignored))
{
return _gdbm_gdbm_close_impl(self);
}
@@ -96,15 +96,26 @@ PyDoc_STRVAR(_gdbm_gdbm_keys__doc__,
"Get a list of all keys in the database.");
#define _GDBM_GDBM_KEYS_METHODDEF \
- {"keys", (PyCFunction)_gdbm_gdbm_keys, METH_NOARGS, _gdbm_gdbm_keys__doc__},
+ {"keys", (PyCFunction)(void(*)(void))_gdbm_gdbm_keys, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _gdbm_gdbm_keys__doc__},
static PyObject *
-_gdbm_gdbm_keys_impl(dbmobject *self);
+_gdbm_gdbm_keys_impl(gdbmobject *self, PyTypeObject *cls);
static PyObject *
-_gdbm_gdbm_keys(dbmobject *self, PyObject *Py_UNUSED(ignored))
+_gdbm_gdbm_keys(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
- return _gdbm_gdbm_keys_impl(self);
+ PyObject *return_value = NULL;
+ static const char * const _keywords[] = { NULL};
+ static _PyArg_Parser _parser = {":keys", _keywords, 0};
+
+ if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser
+ )) {
+ goto exit;
+ }
+ return_value = _gdbm_gdbm_keys_impl(self, cls);
+
+exit:
+ return return_value;
}
PyDoc_STRVAR(_gdbm_gdbm_firstkey__doc__,
@@ -118,15 +129,26 @@ PyDoc_STRVAR(_gdbm_gdbm_firstkey__doc__,
"hash values, and won\'t be sorted by the key values.");
#define _GDBM_GDBM_FIRSTKEY_METHODDEF \
- {"firstkey", (PyCFunction)_gdbm_gdbm_firstkey, METH_NOARGS, _gdbm_gdbm_firstkey__doc__},
+ {"firstkey", (PyCFunction)(void(*)(void))_gdbm_gdbm_firstkey, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _gdbm_gdbm_firstkey__doc__},
static PyObject *
-_gdbm_gdbm_firstkey_impl(dbmobject *self);
+_gdbm_gdbm_firstkey_impl(gdbmobject *self, PyTypeObject *cls);
static PyObject *
-_gdbm_gdbm_firstkey(dbmobject *self, PyObject *Py_UNUSED(ignored))
+_gdbm_gdbm_firstkey(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
- return _gdbm_gdbm_firstkey_impl(self);
+ PyObject *return_value = NULL;
+ static const char * const _keywords[] = { NULL};
+ static _PyArg_Parser _parser = {":firstkey", _keywords, 0};
+
+ if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser
+ )) {
+ goto exit;
+ }
+ return_value = _gdbm_gdbm_firstkey_impl(self, cls);
+
+exit:
+ return return_value;
}
PyDoc_STRVAR(_gdbm_gdbm_nextkey__doc__,
@@ -144,23 +166,26 @@ PyDoc_STRVAR(_gdbm_gdbm_nextkey__doc__,
" k = db.nextkey(k)");
#define _GDBM_GDBM_NEXTKEY_METHODDEF \
- {"nextkey", (PyCFunction)_gdbm_gdbm_nextkey, METH_O, _gdbm_gdbm_nextkey__doc__},
+ {"nextkey", (PyCFunction)(void(*)(void))_gdbm_gdbm_nextkey, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _gdbm_gdbm_nextkey__doc__},
static PyObject *
-_gdbm_gdbm_nextkey_impl(dbmobject *self, const char *key,
+_gdbm_gdbm_nextkey_impl(gdbmobject *self, PyTypeObject *cls, const char *key,
Py_ssize_clean_t key_length);
static PyObject *
-_gdbm_gdbm_nextkey(dbmobject *self, PyObject *arg)
+_gdbm_gdbm_nextkey(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
+ static const char * const _keywords[] = {"", NULL};
+ static _PyArg_Parser _parser = {"s#:nextkey", _keywords, 0};
const char *key;
Py_ssize_clean_t key_length;
- if (!PyArg_Parse(arg, "s#:nextkey", &key, &key_length)) {
+ if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
+ &key, &key_length)) {
goto exit;
}
- return_value = _gdbm_gdbm_nextkey_impl(self, key, key_length);
+ return_value = _gdbm_gdbm_nextkey_impl(self, cls, key, key_length);
exit:
return return_value;
@@ -179,15 +204,26 @@ PyDoc_STRVAR(_gdbm_gdbm_reorganize__doc__,
"kept and reused as new (key,value) pairs are added.");
#define _GDBM_GDBM_REORGANIZE_METHODDEF \
- {"reorganize", (PyCFunction)_gdbm_gdbm_reorganize, METH_NOARGS, _gdbm_gdbm_reorganize__doc__},
+ {"reorganize", (PyCFunction)(void(*)(void))_gdbm_gdbm_reorganize, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _gdbm_gdbm_reorganize__doc__},
static PyObject *
-_gdbm_gdbm_reorganize_impl(dbmobject *self);
+_gdbm_gdbm_reorganize_impl(gdbmobject *self, PyTypeObject *cls);
static PyObject *
-_gdbm_gdbm_reorganize(dbmobject *self, PyObject *Py_UNUSED(ignored))
+_gdbm_gdbm_reorganize(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
- return _gdbm_gdbm_reorganize_impl(self);
+ PyObject *return_value = NULL;
+ static const char * const _keywords[] = { NULL};
+ static _PyArg_Parser _parser = {":reorganize", _keywords, 0};
+
+ if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser
+ )) {
+ goto exit;
+ }
+ return_value = _gdbm_gdbm_reorganize_impl(self, cls);
+
+exit:
+ return return_value;
}
PyDoc_STRVAR(_gdbm_gdbm_sync__doc__,
@@ -200,15 +236,26 @@ PyDoc_STRVAR(_gdbm_gdbm_sync__doc__,
"any unwritten data to be written to the disk.");
#define _GDBM_GDBM_SYNC_METHODDEF \
- {"sync", (PyCFunction)_gdbm_gdbm_sync, METH_NOARGS, _gdbm_gdbm_sync__doc__},
+ {"sync", (PyCFunction)(void(*)(void))_gdbm_gdbm_sync, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _gdbm_gdbm_sync__doc__},
static PyObject *
-_gdbm_gdbm_sync_impl(dbmobject *self);
+_gdbm_gdbm_sync_impl(gdbmobject *self, PyTypeObject *cls);
static PyObject *
-_gdbm_gdbm_sync(dbmobject *self, PyObject *Py_UNUSED(ignored))
+_gdbm_gdbm_sync(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
- return _gdbm_gdbm_sync_impl(self);
+ PyObject *return_value = NULL;
+ static const char * const _keywords[] = { NULL};
+ static _PyArg_Parser _parser = {":sync", _keywords, 0};
+
+ if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser
+ )) {
+ goto exit;
+ }
+ return_value = _gdbm_gdbm_sync_impl(self, cls);
+
+exit:
+ return return_value;
}
PyDoc_STRVAR(dbmopen__doc__,
@@ -293,4 +340,4 @@ skip_optional:
exit:
return return_value;
}
-/*[clinic end generated code: output=c9d43f42677f4efb input=a9049054013a1b77]*/
+/*[clinic end generated code: output=e84bc6ac82fcb6d4 input=a9049054013a1b77]*/