-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Fix __module__
attribute for shared types
#6845
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
base: master
Are you sure you want to change the base?
Changes from all commits
a1a0be8
6f554a6
d3ff4d6
f037493
6db3e7e
7b984ef
eef099d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -1771,7 +1771,7 @@ static PyObject *__Pyx_CoroutineAwait_no_new(PyTypeObject *type, PyObject *args, | |||||
// We are applying this to all Python versions (hence the commented out version guard) | ||||||
// to make the behaviour explicit. | ||||||
// #if CYTHON_USE_TYPE_SPECS | ||||||
static PyObject *__Pyx_CoroutineAwait_reduce_ex(__pyx_CoroutineAwaitObject *self, PyObject *arg) { | ||||||
static PyObject *__Pyx_CoroutineTypes_reduce_ex(PyObject *self, PyObject *arg) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that we're renaming this function, I think it's worth stating in the function name that this is not a pickle implementation but something that intentionally prevents pickling.
Suggested change
|
||||||
CYTHON_UNUSED_VAR(arg); | ||||||
|
||||||
__Pyx_TypeName self_type_name = __Pyx_PyType_GetFullyQualifiedName(Py_TYPE((PyObject*)self)); | ||||||
|
@@ -1790,8 +1790,8 @@ static PyMethodDef __pyx_CoroutineAwait_methods[] = { | |||||
{"close", (PyCFunction) __Pyx_CoroutineAwait_Close_Method, METH_NOARGS, PyDoc_STR("close() -> raise GeneratorExit inside coroutine.")}, | ||||||
// only needed with type-specs, but included in all versions for clarity | ||||||
// #if CYTHON_USE_TYPE_SPECS | ||||||
{"__reduce_ex__", (PyCFunction) __Pyx_CoroutineAwait_reduce_ex, METH_O, 0}, | ||||||
{"__reduce__", (PyCFunction) __Pyx_CoroutineAwait_reduce_ex, METH_NOARGS, 0}, | ||||||
{"__reduce_ex__", (PyCFunction) __Pyx_CoroutineTypes_reduce_ex, METH_O, 0}, | ||||||
{"__reduce__", (PyCFunction) __Pyx_CoroutineTypes_reduce_ex, METH_NOARGS, 0}, | ||||||
// #endif | ||||||
{0, 0, 0, 0} | ||||||
}; | ||||||
|
@@ -1844,20 +1844,45 @@ static PyObject *__Pyx_Coroutine_await(PyObject *coroutine) { | |||||
return __Pyx__Coroutine_await(coroutine); | ||||||
} | ||||||
|
||||||
// Getting and setting __module__ is particular tricky since if we make __module__ a descriptor, | ||||||
// then it gets in the way of (type).__module__. Therefore intercept it in getattro/setattr | ||||||
static PyObject* __pyx_Coroutine_getattro(__pyx_CoroutineObject *self, PyObject *attr) { | ||||||
if (unlikely(PyUnicode_CompareWithASCIIString(attr, "__module__") == 0)) { | ||||||
PyObject *module; | ||||||
__Pyx_BEGIN_CRITICAL_SECTION(self); | ||||||
module = __Pyx_XNewRef(self->gi_modulename); | ||||||
__Pyx_END_CRITICAL_SECTION(); | ||||||
return module ? module : __Pyx_NewRef(Py_None); | ||||||
} | ||||||
return PyObject_GenericGetAttr((PyObject*)self, attr); | ||||||
} | ||||||
|
||||||
static int __pyx_Coroutine_setattro(__pyx_CoroutineObject *self, PyObject *attr, PyObject *value) { | ||||||
if (unlikely(PyUnicode_CompareWithASCIIString(attr, "__module__") == 0)) { | ||||||
__Pyx_BEGIN_CRITICAL_SECTION(self); | ||||||
Py_XINCREF(value); | ||||||
__Pyx_Py_XDECREF_SET(self->gi_modulename, value); | ||||||
__Pyx_END_CRITICAL_SECTION(); | ||||||
return 0; | ||||||
} | ||||||
return PyObject_GenericSetAttr((PyObject*)self, attr, value); | ||||||
} | ||||||
|
||||||
static PyMethodDef __pyx_Coroutine_methods[] = { | ||||||
{"send", (PyCFunction) __Pyx_Coroutine_Send, METH_O, | ||||||
PyDoc_STR("send(arg) -> send 'arg' into coroutine,\nreturn next iterated value or raise StopIteration.")}, | ||||||
{"throw", (PyCFunction) __Pyx_Coroutine_Throw, METH_VARARGS, | ||||||
PyDoc_STR("throw(typ[,val[,tb]]) -> raise exception in coroutine,\nreturn next iterated value or raise StopIteration.")}, | ||||||
{"close", (PyCFunction) __Pyx_Coroutine_Close_Method, METH_NOARGS, PyDoc_STR("close() -> raise GeneratorExit inside coroutine.")}, | ||||||
{"__reduce_ex__", (PyCFunction) __Pyx_CoroutineTypes_reduce_ex, METH_O, 0}, | ||||||
{"__reduce__", (PyCFunction) __Pyx_CoroutineTypes_reduce_ex, METH_NOARGS, 0}, | ||||||
{0, 0, 0, 0} | ||||||
}; | ||||||
|
||||||
static PyMemberDef __pyx_Coroutine_memberlist[] = { | ||||||
{"cr_await", T_OBJECT, offsetof(__pyx_CoroutineObject, yieldfrom), READONLY, | ||||||
PyDoc_STR("object being awaited, or None")}, | ||||||
{"cr_code", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_code), READONLY, NULL}, | ||||||
{"__module__", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_modulename), 0, 0}, | ||||||
{"__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CoroutineObject, gi_weakreflist), READONLY, 0}, | ||||||
{0, 0, 0, 0, 0} | ||||||
}; | ||||||
|
@@ -1881,7 +1906,8 @@ static PyType_Slot __pyx_CoroutineType_slots[] = { | |||||
{Py_tp_methods, (void *)__pyx_Coroutine_methods}, | ||||||
{Py_tp_members, (void *)__pyx_Coroutine_memberlist}, | ||||||
{Py_tp_getset, (void *)__pyx_Coroutine_getsets}, | ||||||
{Py_tp_getattro, (void *) PyObject_GenericGetAttr}, | ||||||
{Py_tp_getattro, (void *)__pyx_Coroutine_getattro}, | ||||||
{Py_tp_setattro, (void *)__pyx_Coroutine_setattro}, | ||||||
Comment on lines
-1884
to
+1910
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you run a quick micro-benchmark to see if this has any visible impact on the time it takes to look up and call |
||||||
#if CYTHON_USE_TP_FINALIZE | ||||||
{Py_tp_finalize, (void *)__Pyx_Coroutine_del}, | ||||||
#endif | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -409,3 +409,17 @@ def test_firstlineno_decorated_function(): | |
l1 = do_nothing.__code__.co_firstlineno | ||
l2 = test_firstlineno_decorated_function.__code__.co_firstlineno | ||
return l2 - l1 | ||
|
||
def test_module(): | ||
""" | ||
>>> test_module.__module__ | ||
'cyfunction' | ||
>>> type(test_module).__module__.startswith("_cython") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems to be a bit fragile locally, because for some reason I always end up with an older cached cyfunction implementation. It works when I manually import the module alone but not when I use runtests. I'm not sure what the CI will end up doing, but I'm fairly sure this is a caching problem and will go away when the shared lib version changes. |
||
True | ||
>>> test_module.__module__ = "something_else" | ||
>>> test_module.__module__ | ||
'something_else' 496D td> | ||
>>> del test_module.__module__ | ||
>>> test_module.__module__ | ||
""" | ||
pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For reasons I don't understand, changing the definition of
8000__module__
magically made coroutines pickleable under protocols 1 and 2. Therefore I just explicitly banned it using the same function as CoroutineAwait uses.