question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Cython emits Python 3 code for __prepare__ in Python 2

See original GitHub issue

Cython 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:closed
  • Created 6 years ago
  • Comments:8 (7 by maintainers)

github_iconTop GitHub Comments

2reactions
scodercommented, Oct 20, 2017

Closing as “third party, not a bug in Cython”.

1reaction
scodercommented, Oct 20, 2017

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) call super().__prepare() conditionally only if the original metaclass implements it.

Read more comments on GitHub >

github_iconTop 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 >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found