Skip to content

Commit

Permalink
jlwrap methods now pydel! their own args if needed
Browse files Browse the repository at this point in the history
it was buggy to always delete them for all methods, because sometimes
the arguments can be persisted (e.g. by setproperty!)
  • Loading branch information
Christopher Doris committed Oct 31, 2023
1 parent 29cd6b2 commit 45a75c1
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 22 deletions.
3 changes: 3 additions & 0 deletions docs/src/releasenotes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Release Notes

## Unreleased
* Bug fixes.

## 0.9.15 (2023-10-25)
* JuliaCall now supports `-X juliacall-startup-file=no` to disable running startup.jl.
* If you are using CondaPkg then Python can optionally now be installed from the anaconda
Expand Down
23 changes: 19 additions & 4 deletions src/jlwrap/any.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ pyjlany_str(self) = Py(sprint(print, self))

function pyjlany_getattr(self, k_::Py)
k = Symbol(pyjl_attr_py2jl(pyconvert(String, k_)))
pydel!(k_)
Py(getproperty(self, k))
end
pyjl_handle_error_type(::typeof(pyjlany_getattr), self, exc) = pybuiltins.AttributeError

function pyjlany_setattr(self, k_::Py, v_::Py)
k = Symbol(pyjl_attr_py2jl(pyconvert(String, k_)))
pydel!(k_)
v = pyconvert(Any, v_)
setproperty!(self, k, v)
Py(nothing)
Expand All @@ -31,30 +33,36 @@ function pyjlany_call(self, args_::Py, kwargs_::Py)
if pylen(kwargs_) > 0
args = pyconvert(Vector{Any}, args_)
kwargs = pyconvert(Dict{Symbol,Any}, kwargs_)
Py(self(args...; kwargs...))
ans = Py(self(args...; kwargs...))
elseif pylen(args_) > 0
args = pyconvert(Vector{Any}, args_)
Py(self(args...))
ans = Py(self(args...))
else
Py(self())
ans = Py(self())
end
pydel!(args_)
pydel!(kwargs_)
ans
end
pyjl_handle_error_type(::typeof(pyjlany_call), self, exc) = exc isa MethodError && exc.f === self ? pybuiltins.TypeError : PyNULL

pyjlany_getitem(self, k_::Py) =
function pyjlany_getitem(self, k_::Py)
if pyistuple(k_)
k = pyconvert(Vector{Any}, k_)
pydel!(k_)
Py(self[k...])
else
k = pyconvert(Any, k_)
Py(self[k])
end
end
pyjl_handle_error_type(::typeof(pyjlany_getitem), self, exc) = exc isa BoundsError ? pybuiltins.IndexError : exc isa KeyError ? pybuiltins.KeyError : PyNULL

function pyjlany_setitem(self, k_::Py, v_::Py)
v = pyconvert(Any, v_)
if pyistuple(k_)
k = pyconvert(Vector{Any}, k_)
pydel!(k_)
self[k...] = v
else
k = pyconvert(Any, k_)
Expand All @@ -67,6 +75,7 @@ pyjl_handle_error_type(::typeof(pyjlany_setitem), self, exc) = exc isa BoundsErr
function pyjlany_delitem(self, k_::Py)
if pyistuple(k_)
k = pyconvert(Vector{Any}, k_)
pydel!(k_)
delete!(self, k...)
else
k = pyconvert(Any, k_)
Expand All @@ -86,6 +95,7 @@ end
function (op::pyjlany_op)(self, other_::Py)
if pyisjl(other_)
other = pyjlvalue(other_)
pydel!(other_)
Py(op.op(self, other))
else
pybuiltins.NotImplemented
Expand All @@ -95,6 +105,8 @@ function (op::pyjlany_op)(self, other_::Py, other2_::Py)
if pyisjl(other_) && pyisjl(other2_)
other = pyjlvalue(other_)
other2 = pyjlvalue(other2_)
pydel!(other_)
pydel!(other2_)
Py(op.op(self, other, other2))
else
pybuiltins.NotImplemented
Expand All @@ -108,6 +120,7 @@ end
function (op::pyjlany_rev_op)(self, other_::Py)
if pyisjl(other_)
other = pyjlvalue(other_)
pydel!(other_)
Py(op.op(other, self))
else
pybuiltins.NotImplemented
Expand All @@ -117,6 +130,8 @@ function (op::pyjlany_rev_op)(self, other_::Py, other2_::Py)
if pyisjl(other_) && pyisjl(other2_)
other = pyjlvalue(other_)
other2 = pyjlvalue(other2_)
pydel!(other_)
pydel!(other2_)
Py(op.op(other, self, other2))
else
pybuiltins.NotImplemented
Expand Down
4 changes: 4 additions & 0 deletions src/jlwrap/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ end

function pyjlarray_getitem(x::AbstractArray{T,N}, k_::Py) where {T,N}
k = pyjl_getarrayindices(x, k_)
pydel!(k_)
if k isa NTuple{N,Int}
return Py(x[k...])
else
Expand All @@ -90,6 +91,7 @@ end

function pyjlarray_setitem(x::AbstractArray{T,N}, k_::Py, v_::Py) where {T,N}
k = pyjl_getarrayindices(x, k_)
pydel!(k_)
if k isa NTuple{N,Int}
v = pyconvertarg(T, v_, "value")
x[k...] = v
Expand All @@ -103,6 +105,7 @@ end
function pyjlarray_delitem(x::AbstractArray{T,N}, k_::Py) where {T,N}
if N == 1
k = pyjl_getarrayindices(x, k_)
pydel!(k_)
deleteat!(x, k...)
else
errset(pybuiltins.TypeError, "can only delete from 1D arrays")
Expand All @@ -114,6 +117,7 @@ pyjl_handle_error_type(::typeof(pyjlarray_delitem), x, exc::MethodError) = exc.f

function pyjlarray_reshape(x::AbstractArray, shape_::Py)
shape = pyconvertarg(Union{Int,Vector{Int}}, shape_, "shape")
pydel!(shape_)
return Py(reshape(x, shape...))
end

Expand Down
6 changes: 0 additions & 6 deletions src/jlwrap/base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,25 +65,19 @@ function Cjl._pyjl_callmethod(f, self_::C.PyPtr, args_::C.PyPtr, nargs::C.Py_ssi
in_f = true
ans = f(self, arg1)::Py
in_f = false
pydel!(arg1)
elseif nargs == 3
arg1 = pynew(incref(C.PyTuple_GetItem(args_, 1)))
arg2 = pynew(incref(C.PyTuple_GetItem(args_, 2)))
in_f = true
ans = f(self, arg1, arg2)::Py
in_f = false
pydel!(arg1)
pydel!(arg2)
elseif nargs == 4
arg1 = pynew(incref(C.PyTuple_GetItem(args_, 1)))
arg2 = pynew(incref(C.PyTuple_GetItem(args_, 2)))
arg3 = pynew(incref(C.PyTuple_GetItem(args_, 3)))
in_f = true
ans = f(self, arg1, arg2, arg3)::Py
in_f = false
pydel!(arg1)
pydel!(arg2)
pydel!(arg3)
else
errset(pybuiltins.NotImplementedError, "__jl_callmethod not implemented for this many arguments")
end
Expand Down
19 changes: 11 additions & 8 deletions src/jlwrap/callback.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,29 @@ function pyjlcallback_call(self, args_::Py, kwargs_::Py)
if pylen(kwargs_) > 0
args = pyconvert(Vector{Py}, args_)
kwargs = pyconvert(Dict{Symbol,Py}, kwargs_)
Py(self(args...; kwargs...))
ans = Py(self(args...; kwargs...))
elseif (nargs = pylen(args_)) > 0
args = pyconvert(Vector{Py}, args_)
@assert length(args) == nargs
if nargs == 1
Py(self(args[1]))
ans = Py(self(args[1]))
elseif nargs == 2
Py(self(args[1], args[2]))
ans = Py(self(args[1], args[2]))
elseif nargs == 3
Py(self(args[1], args[2], args[3]))
ans = Py(self(args[1], args[2], args[3]))
elseif nargs == 4
Py(self(args[1], args[2], args[3], args[4]))
ans = Py(self(args[1], args[2], args[3], args[4]))
elseif nargs == 5
Py(self(args[1], args[2], args[3], args[4], args[5]))
ans = Py(self(args[1], args[2], args[3], args[4], args[5]))
else
Py(self(args...))
ans = Py(self(args...))
end
else
Py(self())
ans = Py(self())
end
pydel!(args_)
pydel!(kwargs_)
ans
end
pyjl_handle_error_type(::typeof(pyjlcallback_call), self, exc::MethodError) = exc.f === self ? pybuiltins.TypeError : PyNULL

Expand Down
7 changes: 7 additions & 0 deletions src/jlwrap/number.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ end
function (op::pyjlnumber_op)(self, other_::Py)
if pyisjl(other_)
other = pyjlvalue(other_)
pydel!(other_)
else
other = @pyconvert(Number, other_, return pybuiltins.NotImplemented)
end
Expand All @@ -19,11 +20,13 @@ end
function (op::pyjlnumber_op)(self, other_::Py, other2_::Py)
if pyisjl(other_)
other = pyjlvalue(other_)
pydel!(other_)
else
other = @pyconvert(Number, other_, return pybuiltins.NotImplemented)
end
if pyisjl(other2_)
other2 = pyjlvalue(other2_)
pydel!(other2_)
else
other2 = @pyconvert(Number, other2_, return pybuiltins.NotImplemented)
end
Expand All @@ -37,6 +40,7 @@ end
function (op::pyjlnumber_rev_op)(self, other_::Py)
if pyisjl(other_)
other = pyjlvalue(other_)
pydel!(other_)
else
other = @pyconvert(Number, other_, return pybuiltins.NotImplemented)
end
Expand All @@ -45,11 +49,13 @@ end
function (op::pyjlnumber_rev_op)(self, other_::Py, other2_::Py)
if pyisjl(other_)
other = pyjlvalue(other_)
pydel!(other_)
else
other = @pyconvert(Number, other_, return pybuiltins.NotImplemented)
end
if pyisjl(other2_)
other2 = pyjlvalue(other2_)
pydel!(other2_)
else
other2 = @pyconvert(Number, other2_, return pybuiltins.NotImplemented)
end
Expand All @@ -68,6 +74,7 @@ pyjl_handle_error_type(::typeof(pyjlreal_ceil), self, exc::MethodError) = exc.f

function pyjlreal_round(self::Real, ndigits_::Py)
ndigits = pyconvertarg(Union{Int,Nothing}, ndigits_, "ndigits")
pydel!(ndigits_)
if ndigits === nothing
Py(round(Integer, self))
else
Expand Down
14 changes: 11 additions & 3 deletions src/jlwrap/raw.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ pyjl_attr_jl2py(k::String) = replace(k, r"!+$" => (x -> "_" * "b"^length(x)))

function pyjlraw_getattr(self, k_::Py)
k = Symbol(pyjl_attr_py2jl(pyconvert(String, k_)))
pydel!(k_)
pyjlraw(getproperty(self, k))
end

function pyjlraw_setattr(self, k_::Py, v_::Py)
k = Symbol(pyjl_attr_py2jl(pyconvert(String, k_)))
pydel!(k_)
v = pyconvert(Any, v_)
setproperty!(self, k, v)
Py(nothing)
Expand All @@ -26,20 +28,24 @@ function pyjlraw_call(self, args_::Py, kwargs_::Py)
if pylen(kwargs_) > 0
args = pyconvert(Vector{Any}, args_)
kwargs = pyconvert(Dict{Symbol,Any}, kwargs_)
pyjlraw(self(args...; kwargs...))
ans = pyjlraw(self(args...; kwargs...))
elseif pylen(args_) > 0
args = pyconvert(Vector{Any}, args_)
pyjlraw(self(args...))
ans = pyjlraw(self(args...))
else
pyjlraw(self())
ans = pyjlraw(self())
end
pydel!(args_)
pydel!(kwargs_)
ans
end

pyjlraw_len(self) = Py(length(self))

function pyjlraw_getitem(self, k_::Py)
if pyistuple(k_)
k = pyconvert(Vector{Any}, k_)
pydel!(k_)
pyjlraw(self[k...])
else
k = pyconvert(Any, k_)
Expand All @@ -51,6 +57,7 @@ function pyjlraw_setitem(self, k_::Py, v_::Py)
v = pyconvert(Any, v_)
if pyistuple(k_)
k = pyconvert(Vector{Any}, k_)
pydel!(k_)
self[k...] = v
else
k = pyconvert(Any, k_)
Expand All @@ -62,6 +69,7 @@ end
function pyjlraw_delitem(self, k_::Py)
if pyistuple(k_)
k = pyconvert(Vector{Any}, k_)
pydel!(k_)
delete!(self, k...)
else
k = pyconvert(Any, k_)
Expand Down
1 change: 1 addition & 0 deletions src/jlwrap/type.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const pyjltypetype = pynew()
function pyjltype_getitem(self::Type, k_)
if pyistuple(k_)
k = pyconvert(Vector{Any}, k_)
pydel!(k_)
Py(self{k...})
else
k = pyconvert(Any, k_)
Expand Down
8 changes: 7 additions & 1 deletion src/jlwrap/vector.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ const pyjlvectortype = pynew()

function pyjlvector_resize(x::AbstractVector, size_::Py)
size = pyconvertarg(Int, size_, "size")
pydel!(size_)
resize!(x, size)
Py(nothing)
end

function pyjlvector_sort(x::AbstractVector, reverse_::Py, key_::Py)
reverse = pyconvertarg(Bool, reverse_, "reverse")
pydel!(reverse_)
key = pyconvertarg(Any, key_, "size")
if key === nothing
sort!(x, rev=reverse)
pydel!(key_)
else
sort!(x, rev=reverse, by=key)
end
Expand All @@ -33,6 +36,7 @@ end

function pyjlvector_insert(x::AbstractVector, k_::Py, v_::Py)
k = pyconvertarg(Int, k_, "index")
pydel!(k_)
a = axes(x, 1)
k′ = k < 0 ? (last(a) + 1 + k) : (first(a) + k)
if checkbounds(Bool, x, k′) || k′ == last(a)+1
Expand All @@ -46,7 +50,7 @@ function pyjlvector_insert(x::AbstractVector, k_::Py, v_::Py)
end

function pyjlvector_append(x::AbstractVector, v_::Py)
v = pyconvertarg(Int, v_, "value")
v = pyconvertarg(eltype(x), v_, "value")
push!(x, v)
Py(nothing)
end
Expand All @@ -56,11 +60,13 @@ function pyjlvector_extend(x::AbstractVector, vs_::Py)
v = pyconvert(eltype(x), v_)
push!(x, v)
end
pydel!(vs_)
Py(nothing)
end

function pyjlvector_pop(x::AbstractVector, k_::Py)
k = pyconvertarg(Int, k_, "index")
pydel!(k_)
a = axes(x, 1)
k′ = k < 0 ? (last(a) + 1 + k) : (first(a) + k)
if checkbounds(Bool, x, k′)
Expand Down

0 comments on commit 45a75c1

Please sign in to comment.