cython: Classes lack __annotations__ (PEP-526)
With python 3.7 dataclasses were introduced. They work just fine in Cython except for their standard init function.
How to reproduce: test.pyx
from dataclasses import dataclass
@dataclass
class TestClass:
x: int
y: int
some_string: str
This file compiles to Cython code just fine. However, when ran from the python it raises an error: test2.py
import test
test_class = test.TestClass(1, 2, 'string')
This raises the following:
Traceback (most recent call last):
File ".\test2.py", line 3, in <module>
test_class = test.TestClass(1, 2, 'string')
TypeError: __init__() takes 1 positional argument but 4 were given
if you rename test.pyx to test.py and do not compile it, no such error occurs.
my current workaround: setting each property after initialization separately: test.pyx remains unchanged. test.py
import test
test_class = test.TestClass()
test_class.x = 1
test_class.y = 2
test_class.some_string = 'string'
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 18
- Comments: 24 (16 by maintainers)
Commits related to this issue
- Add support for PEP 526 `__annotations__` in class body. (GH-3829) Closes https://github.com/cython/cython/issues/2552 — committed to cython/cython by seandstewart 4 years ago
- update (#1) * Fix test in Py2. * Check for exceptions also when @returns() is used, not only for "->" return type annotations. (GH-3664) When you use Python type annotations, it would be weird ... — committed to sairam4123/cython by sairam4123 4 years ago
awesome news that this is implemented 🎉 thanks a lot
thanks for the quick reply. i will try to get some proper time to work on this. in the meantime i have tried a little workaround:
this seems to work properly. is this what you meant by "get away with building the dict in Python and adding it to the class dict "?
As always, the most important bit are tests. I would add new ones in a file
tests/run/pyclass_annotations_pep526.py(with a# tag: pure36to prevent Py<3.6 from running in uncompiled). Look at the otherpyclasstests to see how it’s done, we basically use doctests (which are executed in Python and not compiled, as opposed to the rest of the file).I first thought that this could be implemented after executing the class body, but it turns out that PEP 526 wants the
__annotations__dict to be available before that, so creating the empty dict and assigning it in__Pyx_Py3MetaclassPrepare()would be the right way.Then each
NameNodeinside of the class body (entry.is_pyclass_attr) which holds aself.annotationwill have to generate C code (ingenerate_assignment_code()) to look up the__annotations__dict in the class scope and assign its name to its annotation.py_result()on an assignment (or creation of the name). I don’t actually know if that happens before or after the assignment to the name (which might fail, but could be shadowed by a try-except). Probably something to test in CPython. Thus: tests.I’m also stumbling over this currently, especially Python 3.6-style NamedTuples not working.
I don’t have any experience with how Cython works under the hood, but I’d be willing to give fixing this a try if someone could point me where to start. Is there some relevant documentation somewhere?