Skip to content

[PEP 573] bpo-38787: Module State Access from C Extension Methods #17145

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 22 commits into from
Closed

[PEP 573] bpo-38787: Module State Access from C Extension Methods #17145

wants to merge 22 commits into from

Conversation

ghost
Copy link

@ghost ghost commented Nov 13, 2019

This is a WIP pull request for PEP 573.

The purpose of this PEP is to provide a way to access per-module state from methods belonging to classes defined in extension modules.

https://bugs.python.org/issue38787

@@ -2912,6 +2922,11 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
Py_INCREF(res->ht_qualname);
type->tp_name = spec->name;

if (module) {
Py_INCREF(module);
Copy link
Contributor

Choose a reason for hiding this comment

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

Py_XINCREF()?

break;
}

type = (PyTypeObject *)PyTuple_GetItem(mro, pos);
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the guarantee that prevents the two tuple item accesses (here and below) from running out of bounds?
Could that be worth a comment, at least?

Copy link
Member

Choose a reason for hiding this comment

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

A for loop might be better: first use PyTuple_Size to also check the type, then use the faster PyTuple_GET_ITEM.

Copy link
Member

@encukou encukou left a comment

Choose a reason for hiding this comment

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

Lots of comments on first glance:

Include/object.h Outdated
Comment on lines 180 to 184
typedef struct {
Py_ssize_t dict;
Py_ssize_t weaklist;
} PyType_offsets;

Copy link
Member

Choose a reason for hiding this comment

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

This should be unnecessary.


#define PyCFunction_Check(op) (Py_TYPE(op) == &PyCFunction_Type)
#define PyCFunction_Check(op) ((Py_TYPE(op) == &PyCFunction_Type) || (PyType_IsSubtype(Py_TYPE(op), &PyCFunction_Type)))
Copy link
Member

Choose a reason for hiding this comment

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

Can we use the existing PyCFunction_Type for methods?
The METH_METHOD flag should signal that the underlying struct is PyCMethodObject; you'll also want to set tp_itemsize and the use PyObject_GC_NewVar.


PyAPI_FUNC(PyCFunction) PyCFunction_GetFunction(PyObject *);
PyAPI_FUNC(PyObject *) PyCFunction_GetSelf(PyObject *);
PyAPI_FUNC(int) PyCFunction_GetFlags(PyObject *);
PyAPI_FUNC(PyTypeObject *) PyCMethod_GetClass(PyObject *);
Copy link
Member

Choose a reason for hiding this comment

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

This looks unnecessary; the PEP only mentions PyCFunction_GET_CLASS.

@@ -197,6 +202,18 @@ PyAPI_FUNC(PyObject*) PyType_FromSpecWithBases(PyType_Spec*, PyObject*);
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03040000
PyAPI_FUNC(void*) PyType_GetSlot(struct _typeobject*, int);
#endif
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03080000
PyAPI_FUNC(PyObject*) PyType_FromModuleAndSpec(PyObject *, PyType_Spec *, PyObject *);
Copy link
Member

Choose a reason for hiding this comment

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

Oops, this is missing from the PEP's summary.

Include/object.h Outdated
Comment on lines 213 to 216
/* access macro to the members which are floating "behind" the object */
#define PyHeapType_GET_MEMBERS(etype) \
((PyMemberDef *)(((char *)etype) + Py_TYPE(etype)->tp_basicsize))
#endif
Copy link
Member

Choose a reason for hiding this comment

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

This is duplicates the definition in Include/internal/object.h.

Comment on lines 127 to 131
if (descr->d_method->ml_flags & METH_METHOD) {
return PyCMethod_New(descr->d_method, type, NULL, descr->d_common.d_type);
} else {
return PyCFunction_NewEx(descr->d_method, type, NULL);
}
Copy link
Member

Choose a reason for hiding this comment

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

This should be much simpler, since PyCFunction_NewEx(...) is defined as PyCMethod_New(..., NULL).

Comment on lines 77 to 82
if (ml->ml_flags & (METH_NOARGS | METH_O | METH_CLASS | METH_STATIC)) {
PyErr_SetString(PyExc_SystemError,
"METH_METHOD cannot be used with METH_NOARGS, "
"METH_O, METH_CLASS, nor METH_STATIC");
return NULL;
}
Copy link
Member

Choose a reason for hiding this comment

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

This looks like it would allow (METH_VARARGS | METH_METHOD) or METH_FASTCALL | METH_METHOD

break;
}

type = (PyTypeObject *)PyTuple_GetItem(mro, pos);
Copy link
Member

Choose a reason for hiding this comment

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

A for loop might be better: first use PyTuple_Size to also check the type, then use the faster PyTuple_GET_ITEM.


/*[clinic input]
_testmultiphase.StateAccessType.__init__
cls: defining_class
Copy link
Member

Choose a reason for hiding this comment

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

Could you also test with another slot, not only __init__?

fields.insert(0, normalize_snippet("""
PyTypeObject *cls;

cls = PyType_DefiningTypeFromSlotFunc(Py_TYPE(self),
Copy link
Member

Choose a reason for hiding this comment

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

Is it always named cls?

@ghost ghost closed this Jan 22, 2020
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants