-
Notifications
You must be signed in to change notification settings - Fork 170
Support syntax for passing struct in CPython #1814
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
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.