Skip to content
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

Cython mishandles PEP-3135 __class__ cell in methods #2912

Closed
marginalhours opened this issue Apr 3, 2019 · 1 comment · Fixed by #4094
Closed

Cython mishandles PEP-3135 __class__ cell in methods #2912

marginalhours opened this issue Apr 3, 2019 · 1 comment · Fixed by #4094

Comments

@marginalhours
Copy link
Contributor

marginalhours commented Apr 3, 2019

Hello, I am having trouble with some inconsistent behaviour round the value of __class__ in Cythonized code. This is on Python 3.6.7 with Cython 0.29.1.

Briefly, in uncythonized code __class__ inside a method on a class refers to the class object, whereas once cythonized, it seems to refer to <class 'module'>. This behaviour is a bit unintuitive, and has caused a few issues in a codebase I'm working on, but it's possible I have misunderstood the language semantics!

I have tried to search for reasons / documentation why this is the case, but I couldn't turn up anything. I apologise if there is something really obvious I'm missing here; let me know if so and I'll close the issue at once.

Example:

minimal.py:

class Something:
    def method(self):
        print(__class__)

(in an interpreter, uncythonized):

from minimal import Something
Something().method()
# prints <class 'minimal.Something'>

(after running cythonize minimal.py -3):

from minimal import Something
Something().method()
# prints <class 'module'>   

I believe there is an obvious workaround -- in instance methods, self.__class__ should still have the correct value. But I was curious if this is intended behaviour, and if so, is there something in the docs about it?

@scoder scoder added this to the 3.0 milestone Apr 5, 2019
@scoder
Copy link
Contributor

scoder commented Apr 5, 2019

I think we handle super() separately but not __class__ (as defined by PEP-3135).

PR welcome, it's probably quite easy. See TransformBuiltinMethods._inject_super() in ParseTreeTransforms.py. The NameNode with name __class__ should be replaced in methods y a ClassCellNode. Tests can go into py3k_super.pyx, although a new test file like pep3135_class_cell.py that also runs uncompiled in Python would also be nice (add a #tag: pure3.0 comment at the top of the file to prevent it from running in Python 2).

@scoder scoder changed the title Inconsistent __class__ attribute pre- and post- cythonization of a class Cython mishandles PEP3135 __class__ cell in methods Apr 6, 2019
@scoder scoder changed the title Cython mishandles PEP3135 __class__ cell in methods Cython mishandles PEP-3135 __class__ cell in methods Apr 6, 2019
@scoder scoder modified the milestones: 3.0, 3.0.x Jul 23, 2023
da-woods added a commit that referenced this issue Apr 7, 2024
Finishes up #2916 and closes #2912

Uses ClassClassNode for regular classes to get the attribute reliably at runtime (for cdef class it can be resolved at compile-time).

It essentially adds the line:

__class__ = <ClassCellNode>

at the start of the top-level function. This seems slightly clunky, but the advantage is that __class__ is automatically picked up by locals() and is also automatically captured into the scope of any inner functions. No other approach looked like it would handle inner functions particularly easily.


Co-authored-by: Tom Keefe <tom.keefe@eigentech.com>
Co-authored-by: Tom Keefe <8655118+MisterKeefe@users.noreply.github.com>
@da-woods da-woods modified the milestones: 3.0.x, 3.1 Apr 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants