diff options
author | da-woods <dw-git@d-woods.co.uk> | 2022-01-29 16:06:55 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-29 17:06:55 +0100 |
commit | 102366d162e2c54ec628023bab8b1e7f836a3b6f (patch) | |
tree | 1388d05604934a1e398999ed09e7326dbb3e64b5 /tests/errors | |
parent | 07f45205f46a6ab04e01f7c8244577fe41a0652f (diff) | |
download | cython-102366d162e2c54ec628023bab8b1e7f836a3b6f.tar.gz |
Implement cdef dataclasses (GH-3400)
New decorator/function "@cython.dataclasses.dataclass" and "cython.dataclasses.field()" to mark dataclasses and their fields.
Tries to match the interface provided by a regular dataclass as much as possible.
This means taking the types from the dataclasses module if available (so they match exactly) or a fallback Python version that just implements the core parts (executed with "PyRun_String()" in the C source).
Use of placeholders in generated "__init__" code means the code in the C file isn't hugely readable. Probably not a huge issue, but don't really see a way round that.
As part of this I've also also implemented a Cython version of "typing.ClassVar". Although really designed for use with dataclasses it behaves sensibly when used in types in a normal cdef class. This is worth documenting more thoroughly.
Closes https://github.com/cython/cython/issues/2903
Diffstat (limited to 'tests/errors')
-rw-r--r-- | tests/errors/dataclass_e1.pyx | 22 | ||||
-rw-r--r-- | tests/errors/dataclass_e2.pyx | 13 | ||||
-rw-r--r-- | tests/errors/dataclass_e3.pyx | 13 | ||||
-rw-r--r-- | tests/errors/dataclass_e4.pyx | 11 |
4 files changed, 59 insertions, 0 deletions
diff --git a/tests/errors/dataclass_e1.pyx b/tests/errors/dataclass_e1.pyx new file mode 100644 index 000000000..39337ba6d --- /dev/null +++ b/tests/errors/dataclass_e1.pyx @@ -0,0 +1,22 @@ +# mode: error + +cimport cython + +@cython.dataclasses.dataclass(1, shouldnt_be_here=True, init=5, unsafe_hash=True) +cdef class C: + a: list = [] # mutable + b: int = cython.dataclasses.field(default=5, default_factory=int) + c: int + + def __hash__(self): + pass + +_ERRORS = """ +6:5: Arguments passed to cython.dataclasses.dataclass must be True or False +6:5: Cannot overwrite attribute __hash__ in class C +6:5: cython.dataclasses.dataclass() got an unexpected keyword argument 'shouldnt_be_here' +6:5: cython.dataclasses.dataclass takes no positional arguments +7:14: mutable default <class 'list'> for field a is not allowed: use default_factory +8:37: cannot specify both default and default_factory +9:4: non-default argument 'c' follows default argument in dataclass __init__ +""" diff --git a/tests/errors/dataclass_e2.pyx b/tests/errors/dataclass_e2.pyx new file mode 100644 index 000000000..e25965938 --- /dev/null +++ b/tests/errors/dataclass_e2.pyx @@ -0,0 +1,13 @@ +# mode: error +# tag: dataclass + +import dataclasses + +@dataclasses.dataclass +cdef class C: + pass + +_ERRORS = """ +6:0: Cdef functions/classes cannot take arbitrary decorators. +6:0: Use '@cython.dataclasses.dataclass' on cdef classes to create a dataclass +""" diff --git a/tests/errors/dataclass_e3.pyx b/tests/errors/dataclass_e3.pyx new file mode 100644 index 000000000..85a900172 --- /dev/null +++ b/tests/errors/dataclass_e3.pyx @@ -0,0 +1,13 @@ +# mode: compile +# tag: dataclass, warnings + +cimport cython +from dataclass import field + +@cython.dataclasses.dataclass +cdef class E: + a: int = field() + +_WARNINGS=""" +9:18: Do you mean cython.dataclasses.field instead? +""" diff --git a/tests/errors/dataclass_e4.pyx b/tests/errors/dataclass_e4.pyx new file mode 100644 index 000000000..007487bb8 --- /dev/null +++ b/tests/errors/dataclass_e4.pyx @@ -0,0 +1,11 @@ +# mode: error + +cimport cython + +@cython.dataclasses.dataclass +cdef class C: + a: int = cython.dataclasses.field(unexpected=True) + +_ERRORS = """ +7:49: cython.dataclasses.field() got an unexpected keyword argument 'unexpected' +""" |