Support syntax for passing struct in CPython#1814
Conversation
5e69ae7 to
45f2e63
Compare
|
I am not sure if it fixes #1799 entirely. Could you please add tests from that issue to actually see if they work with your change? |
|
@czgdp1807 do you mean to add the example in #1799 (comment) as an integration_test? |
e74a622 to
1988299
Compare
|
Yes. |
1988299 to
da37514
Compare
@czgdp1807 added it. Thank you for the guidance. |
| foos[0] = Foo(5, 21) | ||
|
|
||
| def main0() -> None: | ||
| foos: Foo[1] = empty(1, dtype=Foo) |
There was a problem hiding this comment.
I would just support the Array[] syntax for arrays of structs, like this:
| foos: Foo[1] = empty(1, dtype=Foo) | |
| foos: Array[Foo, 1] = empty(1, dtype=Foo) |
Then it should be possible to implement this cleanly in lpython.py as well as LPython.
certik
left a comment
There was a problem hiding this comment.
I think as a quick fix it is fine. I think it might break if Foo already defines __class_getitem__ or if it supports the [] like syntax. Right now LPython doesn't support it, so it's fine. But in the long run I think we will have to support the Array[Foo] syntax.
|
This does not work in CPython, right now, because |
Please, could you share an example which fails? |
|
Sure, this reminds me of a bug I need to report that I worked around: #1817 With the workaround above, the following fails with the message above: from lpython import CPtr, c_p_pointer, p_c_pointer, dataclass, empty_c_void_p, pointer, Pointer
from numpy import empty
@dataclass
class Foo:
pass
def bar(foos_ptr: CPtr) -> None:
foos: Pointer[Foo[:]] = c_p_pointer(foos_ptr, Foo[:])
def main() -> None:
foos: Foo[1] = empty(1, dtype=Foo)
foos_ptr: CPtr = empty_c_void_p()
p_c_pointer(pointer(foos), foos_ptr)
bar(foos_ptr)
main() |
|
It's weird that it works at our CI. I wonder if it is Python version dependent. Or our CI is broken? |
|
This almost works, but leads to another bug (again, branching off my workaround from above): #1818 def dataclass(arg):
def __class_getitem__(idxs):
return Array(arg, idxs)
arg.__class_getitem__ = __class_getitem__
return py_dataclass(arg) |
|
I created a dedicated issue for all the bugs reported in the last few comments above: #1819, so that we don't forget about this. We'll investigate and fix it. |
|
The code posted in #1814 (comment) will not work with CPython because for dataclasses because numpy just creates an array of Python objects. See below, from lpython import dataclass, i32
from numpy import empty
@dataclass
class Foo:
x: i32
y: i32
@dataclass
class Foe:
x: i32
y: i32
z: i32
def main() -> None:
foos = empty(2, dtype=Foo)
print(foos.dtype)
foos[0] = Foo(1, 2)
foos[1] = Foe(3, 4, 5)
print(foos[0], foos[1])
main()(lp) 15:11:37:~/lpython_project/lpython % python /Users/czgdp1807/lpython_project/debug.py
object
Foo(x=1, y=2) Foe(x=3, y=4, z=5)So we won't be able to use from lpython import CPtr, c_p_pointer, p_c_pointer, dataclass, empty_c_void_p, pointer, Pointer
from numpy import empty
@dataclass
class Foo:
pass
def bar(foos_ptr: CPtr) -> None:
foos: Pointer[Foo[:]] = c_p_pointer(foos_ptr, Foo[:])
def main() -> None:
foos: Foo[1] = empty(1, dtype=Foo)
foos_ptr: CPtr = empty_c_void_p()
p_c_pointer(pointer(foos, Foo), foos_ptr)
bar(foos_ptr)
main()with the following diff, diff --git a/src/runtime/lpython/lpython.py b/src/runtime/lpython/lpython.py
index c6c53cf31..a82a190f8 100644
--- a/src/runtime/lpython/lpython.py
+++ b/src/runtime/lpython/lpython.py
@@ -448,6 +448,8 @@ def pointer(x, type_=None):
type_ = type(x)
from numpy import ndarray
if isinstance(x, ndarray):
+ if py_is_dataclass(type_):
+ return x
return x.ctypes.data_as(ctypes.POINTER(convert_numpy_dtype_to_ctype(x.dtype)))
else:
if type_ == i8: |
|
Also see #1822. Luck by chance I also ended up with #1814 (comment). |
Related - #1799.