Cython emits Python 3 code for __prepare__ in Python 2
See original GitHub issueCython is emitting the following code in Python 2:
/* Py3ClassCreate */
static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name,
PyObject *qualname, PyObject *mkw, PyObject *modname, PyObject *doc) {
PyObject *ns;
if (metaclass) {
PyObject *prep = __Pyx_PyObject_GetAttrStr(metaclass, __pyx_n_s_prepare);
if (prep) {
PyObject *pargs = PyTuple_Pack(2, name, bases);
if (unlikely(!pargs)) {
Py_DECREF(prep);
return NULL;
}
ns = PyObject_Call(prep, pargs, mkw);
Py_DECREF(prep);
Py_DECREF(pargs);
} else {
This code finds the __prepare__
attribute, and, if it exists, calls it as if it were a function. __prepare__
does not exist in Python 2, and should not be called in Python 2, however, Cython will errantly call it.
Typically, it won’t exist, so this path is never triggered. Unfortunately, six
just added (in 1.11.0) a __prepare__
function to a dummy class that gets generated upon a call to with_metaclass
(in this commit).
That means that the following code:
import six
class SomeBase(object):
pass
class SomeMeta(type):
def __new__(cls, name, bases, dct):
new_cls = super(SomeMeta, cls).__new__(cls, name, bases, dct)
#new_cls = type.__new__(cls, name, bases, dct)
return new_cls
#import ipdb; ipdb.set_trace()
class Derived(six.with_metaclass(SomeMeta, SomeBase)):
pass
will work just fine in Python 2 on its own, but if compiled w/ cython, will result in the above stack trace, since Cython will incorrectly call __prepare__
, whereas CPython will not.
Issue Analytics
- State:
- Created 6 years ago
- Comments:8 (7 by maintainers)
Top Results From Across the Web
Cython: C-Extensions for Python
It makes writing C extensions for Python as easy as Python itself. write Python code that calls back and forth from and to...
Read more >Support Python 2 with Cython - Matthew Rocklin
The Cython compiler can convert a Python 3 codebase into a C-Extension module that is usable by both Python 2 and 3. We...
Read more >Basic Tutorial — Cython 3.0.0a11 documentation
Pure Python syntax which allows static Cython type declarations in pure Python code, following PEP-484 type hints and PEP 526 variable annotations.
Read more >From compiled code to Python - Duke People
There are 2 main reasons why interpreted Python code is slower than code in a compiled lanauge such as C (or other compiled...
Read more >Your Guide to the CPython Source Code - Real Python
The bare minimum for this tutorial is: The Python Development workload; The optional Python native development tools; Python 3 64-bit (3.7.2) ( ...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Closing as “third party, not a bug in Cython”.
Yes, it’s a bug in six that was introduced here: https://github.com/benjaminp/six/pull/178 It unconditionally calls (the equivalent of)
super().__prepare__()
, which is not always available in Py2, unless explicitly implemented by users. (That’s probably the “stack trace” that @thanatos was referring to above, but didn’t actually provide.)The correct fix on their side is to either a) implement
__prepare__
only in Py3, or b) callsuper().__prepare()
conditionally only if the original metaclass implements it.