Skip to content

setindex! not defined for np arrays of non-conventional (isbits) types #217

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

Closed
lmiq opened this issue Sep 6, 2022 · 2 comments
Closed

Comments

@lmiq
Copy link

lmiq commented Sep 6, 2022

Minimum example (using ipython3).

I have a list of tuples Tuple{Int,Int,Float64}, and I can copy the values from the julia array to a np.array of the same type on the python side, but I can't perform this copy of elements on the Julia side, because setindex! is not defined.

Would it be possible to support any isbits type?

In [6]: from juliacall import Main as jl

In [7]: jl.seval("""
   ...: function copy_value(python_list, julia_list)
   ...:     python_list[1] = julia_list[1]
   ...: end
   ...: """)
Out[7]: copy_value (generic function with 1 method)

In [8]: import numpy as np

In [9]: python_list = np.array([(0,0.0)], dtype='i,f')

In [10]: julia_list = jl.seval("[(0,0.0)]")

In [11]: python_list[0] = julia_list[0] # works!

In [12]: jl.copy_value(python_list, julia_list)
---------------------------------------------------------------------------
JuliaError                                Traceback (most recent call last)
<ipython-input-12-e89b29633981> in <module>
----> 1 jl.copy_value(python_list, julia_list)

~/.local/lib/python3.10/site-packages/juliacall/__init__.py in __call__(self, *args, **kwargs)
    199             return ValueBase.__dir__(self) + self._jl_callmethod($(pyjl_methodnum(pyjlany_dir)))
    200         def __call__(self, *args, **kwargs):
--> 201             return self._jl_callmethod($(pyjl_methodnum(pyjlany_call)), args, kwargs)
    202         def __len__(self):
    203             return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(length))))

JuliaError: MethodError: no method matching setindex!(::PythonCall.PyIterable{PythonCall.Py}, ::Tuple{Int64, Float64}, ::Int64)
Stacktrace:
 [1] copy_value(python_list::PythonCall.PyIterable{PythonCall.Py}, julia_list::Vector{Tuple{Int64, Float64}})
   @ Main ./none:3
 [2] pyjlany_call(self::typeof(copy_value), args_::PythonCall.Py, kwargs_::PythonCall.Py)
   @ PythonCall ~/.julia/packages/PythonCall/2Y5CR/src/jlwrap/any.jl:31
 [3] _pyjl_callmethod(f::Any, self_::Ptr{PythonCall.C.PyObject}, args_::Ptr{PythonCall.C.PyObject}, nargs::Int64)
   @ PythonCall ~/.julia/packages/PythonCall/2Y5CR/src/jlwrap/base.jl:69
 [4] _pyjl_callmethod(o::Ptr{PythonCall.C.PyObject}, args::Ptr{PythonCall.C.PyObject})
   @ PythonCall.C ~/.julia/packages/PythonCall/2Y5CR/src/cpython/jlwrap.jl:47
@cjdoris
Copy link
Collaborator

cjdoris commented Sep 6, 2022

Indeed, you can see from the error message that the python_list has been converted to a PyIterable which is the fallback if conversion to PyArray fails. And generic iterables do not support setindex!.

It should indeed be possible to support nested types, but it's fiddly to do in general (e.g. numpy dtypes can use packed or aligned memory layout) so I haven't got around to it yet.

@cjdoris
Copy link
Collaborator

cjdoris commented Sep 9, 2022

You can now convert numpy arrays with structured dtypes like this to PyArray (provided the dtype is aligned). This means your code now works:

In [1]: from juliacall import Main as jl

In [2]: jl.seval("""
   ...: function copy_value(python_list, julia_list)
   ...:   @show python_list julia_list
   ...:   python_list[1] = julia_list[1]
   ...: end
   ...: """)
Out[2]: copy_value (generic function with 1 method)

In [3]: import numpy as np

In [4]: python_list = np.array([(0,0.0)], dtype="i,f")

In [5]: julia_list = jl.seval("[(0,0.0)]")

In [6]: python_list[0] = julia_list[0]

In [7]: jl.copy_value(python_list, julia_list)
python_list = Tuple{Int32, Float32}[(0, 0.0)]
julia_list = [(0, 0.0)]
Out[7]: (0, 0.0)

In [8]: python_list
Out[8]: array([(0, 0.)], dtype=[('f0', '<i4'), ('f1', '<f4')])

In [9]: python_list[0] = (1,1.1)

In [10]: python_list
Out[10]: array([(1, 1.1)], dtype=[('f0', '<i4'), ('f1', '<f4')])

In [11]: jl.copy_value(python_list, julia_list)
python_list = Tuple{Int32, Float32}[(1, 1.1)]
julia_list = [(0, 0.0)]
Out[11]: (0, 0.0)

In [12]: python_list
Out[12]: array([(0, 0.)], dtype=[('f0', '<i4'), ('f1', '<f4')])

Assuming tests pass, I'll make a release today.

@cjdoris cjdoris closed this as completed Sep 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants