Skip to content

Commit 24556e1

Browse files
author
Christopher Doris
committed
separate copying and non-copying array conversion rules
1 parent c4fcc96 commit 24556e1

File tree

3 files changed

+47
-16
lines changed

3 files changed

+47
-16
lines changed

docs/src/conversion-to-julia.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ The following table specifies the conversion rules in place. If the initial Pyth
2020
| `juliacall.AnyValue` | `Any` |
2121
| `juliacall.As` | `Any` |
2222
| **Very high priority (arrays).** | |
23-
| Objects satisfying the buffer or array interface (inc. `bytes`, `bytearray`, `array.array`, `numpy.ndarray`) | `PyArray`, `Array`, `AbstractArray` |
23+
| Objects satisfying the buffer or array interface (inc. `bytes`, `bytearray`, `array.array`, `numpy.ndarray`) | `PyArray` |
2424
| **High priority (canonical conversions).** | |
2525
| `None` | `Nothing` |
2626
| `bool` | `Bool` |
@@ -54,7 +54,7 @@ The following table specifies the conversion rules in place. If the initial Pyth
5454
| `ctypes.c_char_p` | `Cstring`, `Ptr{Cchar}`, `Ptr` |
5555
| `ctypes.c_wchar_p` | `Cwstring`, `Ptr{Cwchar}`, `Ptr` |
5656
| `numpy.intXX`/`numpy.uintXX`/`numpy.floatXX` | `Integer`, `Rational`, `Real`, `Number` |
57-
| Objects satisfying the buffer or array interface | `Array` |
57+
| Objects satisfying the buffer or array interface | `Array`, `AbstractArray` |
5858
| **Low priority (fallback to `Py`).** | |
5959
| Anything | `Py` |
6060
| **Bottom priority (must be explicitly specified by excluding `Py`).** | |

src/convert.jl

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,37 @@ function pyconvert_get_rules(type::Type, pytype::Py)
142142
@assert all(pyis(x,y) for (x,y) in zip(omro, omro_))
143143

144144
# get the names of the types in the MRO of pytype
145-
mro = String["$(t.__module__)/$(t.__qualname__)" for t in mro]
145+
xmro = [["$(t.__module__)/$(t.__qualname__)"] for t in mro]
146+
147+
# add special names corresponding to certain interfaces
148+
# these get inserted just above the topmost type satisfying the interface
149+
for (t, x) in reverse(collect(zip(mro, xmro)))
150+
if pyhasattr(t, "__array_struct__")
151+
push!(x, "<arraystruct>")
152+
break
153+
end
154+
end
155+
for (t, x) in reverse(collect(zip(mro, xmro)))
156+
if pyhasattr(t, "__array_interface__")
157+
push!(x, "<arrayinterface>")
158+
break
159+
end
160+
end
161+
for (t, x) in reverse(collect(zip(mro, xmro)))
162+
if pyhasattr(t, "__array__")
163+
push!(x, "<array>")
164+
break
165+
end
166+
end
167+
for (t, x) in reverse(collect(zip(mro, xmro)))
168+
if C.PyType_CheckBuffer(getptr(t))
169+
push!(x, "<buffer>")
170+
break
171+
end
172+
end
146173

147-
# add special names
148-
# currently we don't care where they go because they are tested in their own priority (200)
149-
pyhasattr(pytype, "__array_struct__") && push!(mro, "<arraystruct>")
150-
pyhasattr(pytype, "__array_interface__") && push!(mro, "<arrayinterface>")
151-
pyhasattr(pytype, "__array__") && push!(mro, "<array>")
152-
C.PyType_CheckBuffer(getptr(pytype)) && push!(mro, "<buffer>")
174+
# flatten to get the MRO as a list of strings
175+
mro = String[x for xs in xmro for x in xs]
153176

154177
# get corresponding rules
155178
rules = PyConvertRule[rule for tname in mro for rule in get!(Vector{PyConvertRule}, PYCONVERT_RULES, tname)]
@@ -172,7 +195,7 @@ function pyconvert_get_rules(type::Type, pytype::Py)
172195
# filter out repeated rules
173196
rules = [rule for (i, rule) in enumerate(rules) if !any((rule.func === rules[j].func) && ((rule.type) <: (rules[j].type)) for j in 1:(i-1))]
174197

175-
# @info "pyconvert" rules
198+
@debug "pyconvert" type pytype mro=join(mro, " ") rules
176199
return Function[pyconvert_fix(rule.type, rule.func) for rule in rules]
177200
end
178201

@@ -282,10 +305,10 @@ function init_pyconvert()
282305
pyconvert_add_rule("juliacall/As", Any, pyconvert_rule_jlas, 300)
283306
pyconvert_add_rule("juliacall/ValueBase", Any, pyconvert_rule_jlvalue, 300)
284307
# priority 200: arrays
285-
pyconvert_add_rule("<arraystruct>", AbstractArray, pyconvert_rule_array, 200)
286-
pyconvert_add_rule("<arrayinterface>", AbstractArray, pyconvert_rule_array, 200)
287-
pyconvert_add_rule("<array>", AbstractArray, pyconvert_rule_array, 200)
288-
pyconvert_add_rule("<buffer>", AbstractArray, pyconvert_rule_array, 200)
308+
pyconvert_add_rule("<arraystruct>", PyArray, pyconvert_rule_array_nocopy, 200)
309+
pyconvert_add_rule("<arrayinterface>", PyArray, pyconvert_rule_array_nocopy, 200)
310+
pyconvert_add_rule("<array>", PyArray, pyconvert_rule_array_nocopy, 200)
311+
pyconvert_add_rule("<buffer>", PyArray, pyconvert_rule_array_nocopy, 200)
289312
# priority 100: canonical
290313
pyconvert_add_rule("builtins/NoneType", Nothing, pyconvert_rule_none, 100)
291314
pyconvert_add_rule("builtins/bool", Bool, pyconvert_rule_bool, 100)
@@ -327,6 +350,14 @@ function init_pyconvert()
327350
pyconvert_add_rule("collections.abc/Sequence", Tuple, pyconvert_rule_iterable)
328351
pyconvert_add_rule("collections.abc/Set", Set, pyconvert_rule_iterable)
329352
pyconvert_add_rule("collections.abc/Mapping", Dict, pyconvert_rule_mapping)
353+
pyconvert_add_rule("<arraystruct>", Array, pyconvert_rule_array)
354+
pyconvert_add_rule("<arrayinterface>", Array, pyconvert_rule_array)
355+
pyconvert_add_rule("<array>", Array, pyconvert_rule_array)
356+
pyconvert_add_rule("<buffer>", Array, pyconvert_rule_array)
357+
pyconvert_add_rule("<arraystruct>", AbstractArray, pyconvert_rule_array)
358+
pyconvert_add_rule("<arrayinterface>", AbstractArray, pyconvert_rule_array)
359+
pyconvert_add_rule("<array>", AbstractArray, pyconvert_rule_array)
360+
pyconvert_add_rule("<buffer>", AbstractArray, pyconvert_rule_array)
330361
# priority -100: fallbacks
331362
pyconvert_add_rule("builtins/object", Py, pyconvert_rule_object, -100)
332363
# priority -200: explicit

src/pywrap/PyArray.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ end
6262
end
6363
end
6464

65-
pyconvert_rule_array(::Type{A}, x::Py) where {A<:PyArray} = pyarray_make(A, x, copy=false)
65+
pyconvert_rule_array_nocopy(::Type{A}, x::Py) where {A<:PyArray} = pyarray_make(A, x, copy=false)
6666

6767
function pyconvert_rule_array(::Type{A}, x::Py) where {A<:AbstractArray}
68-
r = pyconvert_rule_array(PyArray, x)
68+
r = pyarray_make(PyArray, x)
6969
if pyconvert_isunconverted(r)
7070
return pyconvert_unconverted()
7171
else

0 commit comments

Comments
 (0)