From f3e9f3ce6f6972b21eac429011767a317dab33df Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Wed, 6 Jan 2021 10:06:06 -0500 Subject: [PATCH 01/28] Add pyslice and PySlice for Python slices --- src/PyCall.jl | 5 +++-- src/conversions.jl | 33 +++++++++++++++++++++++++++++++++ src/pyinit.jl | 4 ++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/PyCall.jl b/src/PyCall.jl index 48c28697..e0d8c5ed 100644 --- a/src/PyCall.jl +++ b/src/PyCall.jl @@ -8,7 +8,7 @@ using VersionParsing export pycall, pycall!, pyimport, pyimport_e, pybuiltin, PyObject, PyReverseDims, PyPtr, pyincref, pydecref, pyversion, - PyArray, PyArray_Info, PyBuffer, + PyArray, PyArray_Info, PyBuffer, PySlice, pyerr_check, pyerr_clear, pytype_query, PyAny, @pyimport, PyDict, pyisinstance, pywrap, pytypeof, pyeval, PyVector, pystring, pystr, pyrepr, pyraise, pytype_mapping, pygui, pygui_start, pygui_stop, @@ -22,7 +22,8 @@ import Base: size, ndims, similar, copy, getindex, setindex!, stride, filter!, hash, splice!, pop!, ==, isequal, push!, append!, insert!, prepend!, unsafe_convert, pushfirst!, popfirst!, firstindex, lastindex, - getproperty, setproperty!, propertynames + getproperty, setproperty!, propertynames, + first, last, step, SubArray if isdefined(Base, :hasproperty) # Julia 1.2 import Base: hasproperty diff --git a/src/conversions.jl b/src/conversions.jl index 540c25b3..1fdacfd7 100644 --- a/src/conversions.jl +++ b/src/conversions.jl @@ -230,6 +230,33 @@ function convert(::Type{Pair{K,V}}, o::PyObject) where {K,V} return Pair(k, v) end +######################################################################### +# PySlice: no-copy wrapping of a Julia object around a Python slice +struct PySlice{T} <: AbstractRange{T} + o::PyObject + function PySlice{T}(o::PyObject) where T + if !pyisinstance(o, pyslice[]) + throw(ArgumentError("Argument must be a slice")) + end + new{T}(o) + end +end + +PySlice(stop) = PySlice{typeof(stop)}( slice(nothing, stop, nothing) ) +PySlice(start, stop) = PySlice{promote_type(typeof(start),typeof(stop))}( slice(start, stop, nothing) ) +PySlice(start, stop, step) = PySlice{promote_type(typeof(start),typeof(stop),typeof(step))}( slice(start, stop, step) ) +PySlice(r::AbstractRange{T}) where T = PySlice{T}( slice(first(r), last(r)+1, step(r)) ) +PySlice(S::PySlice{T}) where T = S + +first(s::PySlice{T}) where T = (pystart = s.o.start; isnothing( pystart ) ? 0 : pystart) +last(s::PySlice{T}) where T = s.o.stop-1 +step(s::PySlice{T}) where T = (pystep = s.o.step; isnothing( pystep ) ? 1 : pystep) +length(s::PySlice{T}) where T = length( first(s):step(s):last(s) ) + +convert(::Type{PyObject}, S::PySlice) = S.o +PyObject(S::PySlice) = S.o + + ######################################################################### # PyVector: no-copy wrapping of a Julia object around a Python sequence @@ -599,6 +626,9 @@ end xrange(start, stop, step) = pycall(pyxrange[], PyObject, start, stop, step) +slice(start, stop, step) = pycall(pyslice[], PyObject, + start, stop, step) + function PyObject(r::AbstractRange{T}) where T<:Integer s = step(r) f = first(r) @@ -612,6 +642,9 @@ function PyObject(r::AbstractRange{T}) where T<:Integer end function convert(::Type{T}, o::PyObject) where T<:AbstractRange + if pyisinstance(o, pyslice[]) + return o.start:o.step:o.stop-1 + end v = PyVector(o) len = length(v) if len == 0 diff --git a/src/pyinit.jl b/src/pyinit.jl index 42a928df..6d6cb4e4 100644 --- a/src/pyinit.jl +++ b/src/pyinit.jl @@ -20,6 +20,7 @@ const c_void_p_Type = PyNULL() # or are simply left as non-const values const pynothing = Ref{PyPtr}(0) const pyxrange = Ref{PyPtr}(0) +const pyslice = Ref{PyPtr}(0) ######################################################################### # initialize jlWrapType for pytype.jl @@ -217,6 +218,9 @@ function __init__() # xrange type (or range in Python 3) pyxrange[] = @pyglobalobj(:PyRange_Type) + # slice type + pyslice[] = @pyglobalobj(:PySlice_Type) + # ctypes.c_void_p for Ptr types copy!(c_void_p_Type, pyimport("ctypes")."c_void_p") From 48cb90b10732b527685d9ebc47b94ce4731b6fad Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Wed, 6 Jan 2021 10:33:00 -0500 Subject: [PATCH 02/28] PermutedDimsArray and StridedSubArray PyObject OL --- src/PyCall.jl | 2 +- src/numpy.jl | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/PyCall.jl b/src/PyCall.jl index e0d8c5ed..ec526bc9 100644 --- a/src/PyCall.jl +++ b/src/PyCall.jl @@ -23,7 +23,7 @@ import Base: size, ndims, similar, copy, getindex, setindex!, stride, append!, insert!, prepend!, unsafe_convert, pushfirst!, popfirst!, firstindex, lastindex, getproperty, setproperty!, propertynames, - first, last, step, SubArray + first, last, step, StridedSubArray if isdefined(Base, :hasproperty) # Julia 1.2 import Base: hasproperty diff --git a/src/numpy.jl b/src/numpy.jl index f3d523aa..95708c9c 100644 --- a/src/numpy.jl +++ b/src/numpy.jl @@ -225,3 +225,17 @@ PyObject(a::Union{LinearAlgebra.Adjoint{<:Real},LinearAlgebra.Transpose}) = PyReverseDims(a.parent) PyObject(a::LinearAlgebra.Adjoint) = PyObject(Matrix(a)) # non-real arrays require a copy + +function PyObject(pda::PermutedDimsArray{T,N,perm}) where {T,N,perm} + parent = PyObject(pda.parent) + # numpy.transpose is similar to PermutedDimsArray and creates a view of the data + pycall(parent.transpose, PyObject, perm .- 1) +end + +function PyObject(a::StridedSubArray{T,N}) where {T <: PYARR_TYPES,N} + parent = PyObject(a.parent) + inds = a.indices + # hasstep(T) = Val( hasmethod( step, Tuple{ typeof(T) } ) ) + slices = map( ind->PySlice(ind .- 1) , inds ) + pycall( parent.__getitem__, PyObject, slices ) +end \ No newline at end of file From bfbb1e963ab739740eec58a7244f0b80185d5731 Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Mon, 11 Jan 2021 02:10:28 -0500 Subject: [PATCH 03/28] pyembed ReinterpretArray as parent --- src/PyCall.jl | 2 +- src/gc.jl | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/PyCall.jl b/src/PyCall.jl index ec526bc9..4c2504bb 100644 --- a/src/PyCall.jl +++ b/src/PyCall.jl @@ -23,7 +23,7 @@ import Base: size, ndims, similar, copy, getindex, setindex!, stride, append!, insert!, prepend!, unsafe_convert, pushfirst!, popfirst!, firstindex, lastindex, getproperty, setproperty!, propertynames, - first, last, step, StridedSubArray + first, last, step, StridedSubArray, ReinterpretArray if isdefined(Base, :hasproperty) # Julia 1.2 import Base: hasproperty diff --git a/src/gc.jl b/src/gc.jl index e000cc37..0221c717 100644 --- a/src/gc.jl +++ b/src/gc.jl @@ -43,3 +43,11 @@ function pyembed(po::PyObject, jo::Any) pycall_gc[wo] = jo return po end + +# "embed" a reference to jo.parent in po, using the weak-reference mechanism +function pyembed(po::PyObject, jo::ReinterpretArray) + # When a ReinterpretArray is converted to a Ptr{T}, the Ptr is actually + # to parent. + # See Base.unsafe_convert(::Type{Ptr{T}}, ::ReinterpretArray{T,N,S}) + pyembed(po, jo.parent) +end \ No newline at end of file From 9db36cd36c04bec76c97f2eb050356a8c1b5f8a2 Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Mon, 11 Jan 2021 20:33:39 -0500 Subject: [PATCH 04/28] Widen NpyArray to AbstractArray from StridedArray --- src/PyCall.jl | 2 +- src/gc.jl | 21 +++++++++++++-------- src/numpy.jl | 17 ++++++++++------- test/runtests.jl | 29 +++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 16 deletions(-) diff --git a/src/PyCall.jl b/src/PyCall.jl index 4c2504bb..effaa885 100644 --- a/src/PyCall.jl +++ b/src/PyCall.jl @@ -23,7 +23,7 @@ import Base: size, ndims, similar, copy, getindex, setindex!, stride, append!, insert!, prepend!, unsafe_convert, pushfirst!, popfirst!, firstindex, lastindex, getproperty, setproperty!, propertynames, - first, last, step, StridedSubArray, ReinterpretArray + first, last, step, StridedSubArray, ReinterpretArray, ReshapedArray if isdefined(Base, :hasproperty) # Julia 1.2 import Base: hasproperty diff --git a/src/gc.jl b/src/gc.jl index 0221c717..ffa52003 100644 --- a/src/gc.jl +++ b/src/gc.jl @@ -29,7 +29,13 @@ const weakref_callback_meth = Ref{PyMethodDef}() function pyembed(po::PyObject, jo::Any) # If there's a need to support immutable embedding, # the API needs to be changed to return the pointer. - isimmutable(jo) && throw(ArgumentError("pyembed: immutable argument not allowed")) + if isimmutable(jo) + if hasmethod(parent, ( typeof(jo), ) ) + return pyembed(po, parent(jo) ) + else + throw(ArgumentError("pyembed: immutable argument not allowed")) + end + end if ispynull(weakref_callback_obj) cf = @cfunction(weakref_callback, PyPtr, (PyPtr,PyPtr)) weakref_callback_meth[] = PyMethodDef("weakref_callback", cf, METH_O) @@ -44,10 +50,9 @@ function pyembed(po::PyObject, jo::Any) return po end -# "embed" a reference to jo.parent in po, using the weak-reference mechanism -function pyembed(po::PyObject, jo::ReinterpretArray) - # When a ReinterpretArray is converted to a Ptr{T}, the Ptr is actually - # to parent. - # See Base.unsafe_convert(::Type{Ptr{T}}, ::ReinterpretArray{T,N,S}) - pyembed(po, jo.parent) -end \ No newline at end of file +# Embed the mutable type underlying the immutable view of the array +# See Base.unsafe_convert(::Type{Ptr{T}}, jo::ArrayType) for specific array types +pyembed(po::PyObject, jo::SubArray ) = pyembed(po, jo.parent) +pyembed(po::PyObject, jo::ReshapedArray ) = pyembed(po, jo.parent) +pyembed(po::PyObject, jo::ReinterpretArray ) = pyembed(po, jo.parent) +pyembed(po::PyObject, jo::PermutedDimsArray) = pyembed(po, jo.parent) \ No newline at end of file diff --git a/src/numpy.jl b/src/numpy.jl index 95708c9c..fa722f5a 100644 --- a/src/numpy.jl +++ b/src/numpy.jl @@ -172,7 +172,7 @@ const NPY_ARRAY_WRITEABLE = Int32(0x0400) # dimensions. For example, although NumPy works with both row-major and # column-major data, some Python libraries like OpenCV seem to require # row-major data (the default in NumPy). In such cases, use PyReverseDims(array) -function NpyArray(a::StridedArray{T}, revdims::Bool) where T<:PYARR_TYPES +function NpyArray(a::AbstractArray{T}, revdims::Bool) where T<:PYARR_TYPES @npyinitialize size_a = revdims ? reverse(size(a)) : size(a) strides_a = revdims ? reverse(strides(a)) : strides(a) @@ -186,7 +186,7 @@ function NpyArray(a::StridedArray{T}, revdims::Bool) where T<:PYARR_TYPES return PyObject(p, a) end -function PyObject(a::StridedArray{T}) where T<:PYARR_TYPES +function PyObject(a::AbstractArray{T}) where T<:PYARR_TYPES try return NpyArray(a, false) catch @@ -194,7 +194,7 @@ function PyObject(a::StridedArray{T}) where T<:PYARR_TYPES end end -function PyReverseDims(a::StridedArray{T,N}) where {T<:PYARR_TYPES,N} +function PyReverseDims(a::AbstractArray{T,N}) where {T<:PYARR_TYPES,N} try return NpyArray(a, true) catch @@ -226,14 +226,17 @@ PyObject(a::Union{LinearAlgebra.Adjoint{<:Real},LinearAlgebra.Transpose}) = PyObject(a::LinearAlgebra.Adjoint) = PyObject(Matrix(a)) # non-real arrays require a copy -function PyObject(pda::PermutedDimsArray{T,N,perm}) where {T,N,perm} - parent = PyObject(pda.parent) +# Alternative conversion of array views mapping parent in Julia to base in Numpy +PyObjectWithParent(a::AbstractArray) = PyObject(a) + +function PyObjectWithParent(pda::PermutedDimsArray{T,N,perm}) where {T,N,perm} + parent = PyObjectWithParent(pda.parent) # numpy.transpose is similar to PermutedDimsArray and creates a view of the data pycall(parent.transpose, PyObject, perm .- 1) end -function PyObject(a::StridedSubArray{T,N}) where {T <: PYARR_TYPES,N} - parent = PyObject(a.parent) +function PyObjectWithParent(a::StridedSubArray{T,N}) where {T <: PYARR_TYPES,N} + parent = PyObjectWithParent(a.parent) inds = a.indices # hasstep(T) = Val( hasmethod( step, Tuple{ typeof(T) } ) ) slices = map( ind->PySlice(ind .- 1) , inds ) diff --git a/test/runtests.jl b/test/runtests.jl index dff36dbc..192c8a16 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -107,6 +107,35 @@ const PyInt = pyversion < v"3" ? Int : Clonglong @test GC.@preserve(o, pyincref.(PyArray(o))) == a end end + let A = Float64[1 2; 3 4] + # SubArray + B = view(A, 1:2, 2) + C = PyArray( PyObject(B) ) + @test C == B + A[3] = 5 + @test C == B && C[1] == A[3] + + # ReshapedArray + B = Base.ReshapedArray( A, (1,4), () ) + C = PyArray( PyObject(B) ) + @test C == B + A[2] = 6 + @test C == B && C[2] == A[2] + + # PermutedDimsArray + B = PermutedDimsArray(A, (2,1) ) + C = PyArray( PyObject(B) ) + @test C == B + A[1] == 7 + @test C == B && C[1] == A[1] + + # ReinterpretArray + B = reinterpret(UInt64, A) + C = PyArray( PyObject(B) ) + @test C == B + A[1] = 12 + @test C == B && C[1] == reinterpret(UInt64, A[1]) + end end @test PyVector(PyObject([1,3.2,"hello",true])) == [1,3.2,"hello",true] @test PyDict(PyObject(Dict(1 => "hello", 2 => "goodbye"))) == Dict(1 => "hello", 2 => "goodbye") From 8909d2b1d527ae05b4fe71a9483ad85da4f2bc5f Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Tue, 12 Jan 2021 00:04:30 -0500 Subject: [PATCH 05/28] Consolidate PySlice --- src/conversions.jl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/conversions.jl b/src/conversions.jl index 1fdacfd7..6db5f9b8 100644 --- a/src/conversions.jl +++ b/src/conversions.jl @@ -232,6 +232,10 @@ end ######################################################################### # PySlice: no-copy wrapping of a Julia object around a Python slice + +slice(start, stop, step) = pycall(pyslice[], PyObject, + start, stop, step) + struct PySlice{T} <: AbstractRange{T} o::PyObject function PySlice{T}(o::PyObject) where T @@ -254,6 +258,7 @@ step(s::PySlice{T}) where T = (pystep = s.o.step; isnothing( pystep ) ? 1 : pyst length(s::PySlice{T}) where T = length( first(s):step(s):last(s) ) convert(::Type{PyObject}, S::PySlice) = S.o +convert(::Type{PySlice}, o::PyObject) = PySlice{Int}(o) PyObject(S::PySlice) = S.o @@ -626,9 +631,6 @@ end xrange(start, stop, step) = pycall(pyxrange[], PyObject, start, stop, step) -slice(start, stop, step) = pycall(pyslice[], PyObject, - start, stop, step) - function PyObject(r::AbstractRange{T}) where T<:Integer s = step(r) f = first(r) @@ -784,6 +786,8 @@ function pysequence_query(o::PyObject) return typetuple(pytype_query(PyObject(ccall((@pysym :PySequence_GetItem), PyPtr, (PyPtr,Int), o,i-1)), PyAny) for i = 1:len) elseif pyisinstance(o, pyxrange[]) return AbstractRange + elseif pyisinstance(o, pyslice[]) + return PySlice elseif ispybytearray(o) return Vector{UInt8} elseif !isbuftype(o) From 9fd89da8808180b31056e948bf394ae73b7cec64 Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Tue, 12 Jan 2021 01:55:58 -0500 Subject: [PATCH 06/28] Fix scalar indices in SubArray --- src/numpy.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/numpy.jl b/src/numpy.jl index fa722f5a..84a455a0 100644 --- a/src/numpy.jl +++ b/src/numpy.jl @@ -239,6 +239,9 @@ function PyObjectWithParent(a::StridedSubArray{T,N}) where {T <: PYARR_TYPES,N} parent = PyObjectWithParent(a.parent) inds = a.indices # hasstep(T) = Val( hasmethod( step, Tuple{ typeof(T) } ) ) - slices = map( ind->PySlice(ind .- 1) , inds ) + ind2slice(ind) = isa(ind,AbstractRange) ? + PySlice(ind .- 1) : + PySlice(ind-1:ind-1) + slices = map( ind2slice , inds ) pycall( parent.__getitem__, PyObject, slices ) end \ No newline at end of file From d4c18995e1858e213a85c09ea20d941d863b7293 Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Tue, 12 Jan 2021 01:56:35 -0500 Subject: [PATCH 07/28] Enhance coverage with tests --- test/runtests.jl | 68 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 192c8a16..c976f13d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -72,6 +72,8 @@ const PyInt = pyversion < v"3" ? Int : Clonglong @test roundtripeq(Int32) @test roundtripeq(Dict(1 => "hello", 2 => "goodbye")) && roundtripeq(Dict()) @test roundtripeq(UInt8[1,3,4,5]) + @test roundtirpeq(1:5) + @test roundtirpeq(5:2:10) @test roundtrip(3 => 4) == (3,4) @test roundtrip(Pair{Int,Int}, 3 => 4) == Pair(3,4) @test eltype(roundtrip([Ref(1), Ref(2)])) == typeof(Ref(1)) @@ -87,6 +89,48 @@ const PyInt = pyversion < v"3" ? Int : Clonglong @test roundtrip(testkw)(314157) == 314157 @test roundtrip(testkw)(314157, y=1) == 314159 + let s = PyCall.slice(nothing, 10, nothing) + @test s.start === nothing + @test s.stop == 10 + @test s.step === nothing + @test PySlice{Int}(s) == 0:9 + @test convert(PySlice, s) == 0:9 + @test PyObject( PySlice{Int}(s) ) === s + end + + let s = PyCall.slice(1, 5, nothing) + @test s.start == 1 + @test s.stop == 5 + @test s.step === nothing + @test PySlice{Int}(s) == 1:4 + @test convert(PySlice, s) == 1:4 + @test PyObject( PySlice{Int}(s) ) === s + end + + let s = PyCall.slice(3, 9, 2) + @test s.start == 3 + @test s.stop == 9 + @test s.step == 2 + @test PySlice{Int}(s) == 3:2:7 + @test convert(PySlice, s) == 3:2:7 + @test PyObject( PySlice{Int}(s) ) === s + end + + let s = PySlice(4, 5) + @test first(s) == 4 + @test last(s) == 4 + @test step(s) == 1 + @test length(s) == 1 + @test PySlice(s) === s + @test s == pybuiltin("slice")(4, 5) + end + + @test PySlice(5) == 0:4 + @test PySlice(1,5) == 1:4 + @test PySlice(1,6,2) == 1:2:5 + @test PySlice(1:5) == 1:5 + @test PySlice(2:2:6) == 2:2:6 + # check type stability of pycall with an explicit return type @inferred pycall(PyObject(1).__add__, Int, 2) @@ -108,12 +152,29 @@ const PyInt = pyversion < v"3" ? Int : Clonglong end end let A = Float64[1 2; 3 4] + # Normal array + B = copy(A) + C = PyArray( PyObject(B) ) + @test C == B + B[1] = 3 + @test C == B && C[1] == B[1] + + C = PyArray( PyCall.PyObjectWithParent(B) ) + @test C == B + B[1] = 2 + @test C == B && C[1] == B[1] + # SubArray - B = view(A, 1:2, 2) + B = view(A, 1:2, 2:2) C = PyArray( PyObject(B) ) @test C == B A[3] = 5 @test C == B && C[1] == A[3] + + C = PyArray( PyCall.PyObjectWithParent(B) ) + @test C == B + A[3] = 4 + @test C == B && C[1] == A[3] # ReshapedArray B = Base.ReshapedArray( A, (1,4), () ) @@ -129,6 +190,11 @@ const PyInt = pyversion < v"3" ? Int : Clonglong A[1] == 7 @test C == B && C[1] == A[1] + C = PyArray( PyCall.PyObjectWithParent(B) ) + @test C == B + A[1] == 8 + @test C == B && C[1] == A[1] + # ReinterpretArray B = reinterpret(UInt64, A) C = PyArray( PyObject(B) ) From 39eb96b34ecc7819cd685ee3f5d4358adf5ab586 Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Tue, 12 Jan 2021 01:57:16 -0500 Subject: [PATCH 08/28] Fix Core.TypeofVararg pyany_toany for Julia 1.7 --- src/conversions.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/conversions.jl b/src/conversions.jl index 6db5f9b8..bd8f1a65 100644 --- a/src/conversions.jl +++ b/src/conversions.jl @@ -170,7 +170,9 @@ function pyany_toany(T::Type) end pyany_toany(::Type{PyAny}) = Any pyany_toany(t::Type{T}) where {T<:Tuple} = Tuple{map(pyany_toany, t.types)...} - +@static if VERSION >= v"1.7.0-DEV.255" + pyany_toany(::Core.TypeofVararg{PyAny}) = Vararg{Any} +end # PyAny acts like Any for conversions, except for converting PyObject (below) convert(::Type{PyAny}, x) = x From 457d1f36ee8a71cff28517d5fd17b2242373b72f Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Tue, 12 Jan 2021 01:59:24 -0500 Subject: [PATCH 09/28] Fix roundtripeq typo for ranges --- test/runtests.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index c976f13d..afa36815 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -72,8 +72,8 @@ const PyInt = pyversion < v"3" ? Int : Clonglong @test roundtripeq(Int32) @test roundtripeq(Dict(1 => "hello", 2 => "goodbye")) && roundtripeq(Dict()) @test roundtripeq(UInt8[1,3,4,5]) - @test roundtirpeq(1:5) - @test roundtirpeq(5:2:10) + @test roundtripeq(1:5) + @test roundtripeq(5:2:10) @test roundtrip(3 => 4) == (3,4) @test roundtrip(Pair{Int,Int}, 3 => 4) == Pair(3,4) @test eltype(roundtrip([Ref(1), Ref(2)])) == typeof(Ref(1)) From 38a8db342818a364c6b99983c77a616455258921 Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Tue, 12 Jan 2021 02:13:39 -0500 Subject: [PATCH 10/28] Fix Julia 1.0 isnothing, and 1.7 Core.TypeofVararg --- src/conversions.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/conversions.jl b/src/conversions.jl index bd8f1a65..1cf0a492 100644 --- a/src/conversions.jl +++ b/src/conversions.jl @@ -171,7 +171,7 @@ end pyany_toany(::Type{PyAny}) = Any pyany_toany(t::Type{T}) where {T<:Tuple} = Tuple{map(pyany_toany, t.types)...} @static if VERSION >= v"1.7.0-DEV.255" - pyany_toany(::Core.TypeofVararg{PyAny}) = Vararg{Any} + pyany_toany(T::Core.TypeofVararg) = T === Vararg{PyAny} ? Vararg{Any} : T end # PyAny acts like Any for conversions, except for converting PyObject (below) convert(::Type{PyAny}, x) = x @@ -254,9 +254,9 @@ PySlice(start, stop, step) = PySlice{promote_type(typeof(start),typeof(stop),typ PySlice(r::AbstractRange{T}) where T = PySlice{T}( slice(first(r), last(r)+1, step(r)) ) PySlice(S::PySlice{T}) where T = S -first(s::PySlice{T}) where T = (pystart = s.o.start; isnothing( pystart ) ? 0 : pystart) +first(s::PySlice{T}) where T = (pystart = s.o.start; pystart === nothing ? 0 : pystart) last(s::PySlice{T}) where T = s.o.stop-1 -step(s::PySlice{T}) where T = (pystep = s.o.step; isnothing( pystep ) ? 1 : pystep) +step(s::PySlice{T}) where T = (pystep = s.o.step; pystep === nothing ? 1 : pystep) length(s::PySlice{T}) where T = length( first(s):step(s):last(s) ) convert(::Type{PyObject}, S::PySlice) = S.o From 5520835f454501bc6479df4c638608715945be56 Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Tue, 12 Jan 2021 03:00:47 -0500 Subject: [PATCH 11/28] Lower version for Core.TypeofVararg --- src/conversions.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversions.jl b/src/conversions.jl index 1cf0a492..94081e95 100644 --- a/src/conversions.jl +++ b/src/conversions.jl @@ -170,7 +170,7 @@ function pyany_toany(T::Type) end pyany_toany(::Type{PyAny}) = Any pyany_toany(t::Type{T}) where {T<:Tuple} = Tuple{map(pyany_toany, t.types)...} -@static if VERSION >= v"1.7.0-DEV.255" +@static if VERSION >= v"1.7.0-DEV.0" pyany_toany(T::Core.TypeofVararg) = T === Vararg{PyAny} ? Vararg{Any} : T end # PyAny acts like Any for conversions, except for converting PyObject (below) From b2c3b41059e9da012648839de68f41bdb591009f Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Tue, 12 Jan 2021 03:36:20 -0500 Subject: [PATCH 12/28] Remove @static from TypeOfVararg --- src/conversions.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversions.jl b/src/conversions.jl index 94081e95..be0e3766 100644 --- a/src/conversions.jl +++ b/src/conversions.jl @@ -170,7 +170,7 @@ function pyany_toany(T::Type) end pyany_toany(::Type{PyAny}) = Any pyany_toany(t::Type{T}) where {T<:Tuple} = Tuple{map(pyany_toany, t.types)...} -@static if VERSION >= v"1.7.0-DEV.0" +if VERSION >= v"1.7.0-DEV.0" pyany_toany(T::Core.TypeofVararg) = T === Vararg{PyAny} ? Vararg{Any} : T end # PyAny acts like Any for conversions, except for converting PyObject (below) From bb3f68e0a7da32f4d6e643d89500e9af8cfb2511 Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Tue, 12 Jan 2021 03:43:21 -0500 Subject: [PATCH 13/28] Skip Core.TypeofVararg test for 1.7 prerelease --- test/runtests.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index afa36815..9bc2bcc6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -50,7 +50,11 @@ const PyInt = pyversion < v"3" ? Int : Clonglong @test pyany_toany(PyAny) == Any @test pyany_toany(Tuple{Int,PyAny}) == Tuple{Int,Any} @test pyany_toany(Tuple{Int,Tuple{PyAny,Int8}}) == Tuple{Int,Tuple{Any,Int8}} - @test pyany_toany(Tuple{PyAny,Int,Vararg{PyAny}}) == Tuple{Any,Int,Vararg{Any}} + if v"1.7.0-DEV.0" <= VERSION < v"1.7" + @test_skip pyany_toany(Tuple{PyAny,Int,Vararg{PyAny}}) == Tuple{Any,Int,Vararg{Any}} + else + @test pyany_toany(Tuple{PyAny,Int,Vararg{PyAny}}) == Tuple{Any,Int,Vararg{Any}} + end @test roundtripeq(17) @test roundtripeq(0x39) From a9e562bf8e34264ed6926b9e6469cf64fc5237b7 Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Tue, 12 Jan 2021 03:50:12 -0500 Subject: [PATCH 14/28] Check version during AOT test --- test/runtests.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/test/runtests.jl b/test/runtests.jl index 9bc2bcc6..b38cc7d6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -50,6 +50,7 @@ const PyInt = pyversion < v"3" ? Int : Clonglong @test pyany_toany(PyAny) == Any @test pyany_toany(Tuple{Int,PyAny}) == Tuple{Int,Any} @test pyany_toany(Tuple{Int,Tuple{PyAny,Int8}}) == Tuple{Int,Tuple{Any,Int8}} + @info "Julia $VERSION" if v"1.7.0-DEV.0" <= VERSION < v"1.7" @test_skip pyany_toany(Tuple{PyAny,Int,Vararg{PyAny}}) == Tuple{Any,Int,Vararg{Any}} else From 3d4760e017c696204334dbf11d84a3a3f4a77063 Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Tue, 12 Jan 2021 04:10:49 -0500 Subject: [PATCH 15/28] Fix AOT workflow due to resolved issues --- .github/workflows/aot.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/aot.yml b/.github/workflows/aot.yml index d12b7db9..ea23d765 100644 --- a/.github/workflows/aot.yml +++ b/.github/workflows/aot.yml @@ -41,13 +41,7 @@ jobs: arch: ${{ matrix.architecture }} show-versioninfo: true - # Revert to `@v1` after this PR is merged: - # https://github.com/JuliaLang/PackageCompiler.jl/pull/443 - - run: julia -e 'using Pkg; pkg"add PackageCompiler#cb994c72e2087c57ffa4727ef93589e1b98d8a32"' - - # Workaround https://github.com/JuliaLang/julia/issues/37441. - # Once it's solved, we can remove the following line: - - run: julia -e 'using Pkg; pkg"dev PyCall"' + - run: julia -e 'using Pkg; pkg"add PackageCompiler@v1"' - run: aot/compile.jl - run: aot/assert_has_pycall.jl From 09ab06ae5c56725bb990431693ba76c58d47c001 Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Tue, 12 Jan 2021 04:37:02 -0500 Subject: [PATCH 16/28] Add --project when running tests --- aot/runtests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aot/runtests.sh b/aot/runtests.sh index 4d5f573b..6692ef29 100755 --- a/aot/runtests.sh +++ b/aot/runtests.sh @@ -1,6 +1,6 @@ #!/bin/bash thisdir="$(dirname "${BASH_SOURCE[0]}")" -exec "$thisdir/julia.sh" --startup-file=no --color=yes -e ' +exec "$thisdir/julia.sh" --startup-file=no --color=yes -e --project $thisdir ' using Pkg Pkg.test("PyCall") ' From 42eda17fd87e7ec41bd92e40b5db618218d8019d Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Tue, 12 Jan 2021 04:41:54 -0500 Subject: [PATCH 17/28] Fix runtests.sh arg order --- aot/runtests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aot/runtests.sh b/aot/runtests.sh index 6692ef29..5187c0eb 100755 --- a/aot/runtests.sh +++ b/aot/runtests.sh @@ -1,6 +1,6 @@ #!/bin/bash thisdir="$(dirname "${BASH_SOURCE[0]}")" -exec "$thisdir/julia.sh" --startup-file=no --color=yes -e --project $thisdir ' +exec "$thisdir/julia.sh" --startup-file=no --color=yes --project $thisdir -e ' using Pkg Pkg.test("PyCall") ' From f05803c7aa66eefb6935a582325b40044f12e28f Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Tue, 12 Jan 2021 04:50:03 -0500 Subject: [PATCH 18/28] Fix runtests.sh --- aot/runtests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aot/runtests.sh b/aot/runtests.sh index 5187c0eb..6f4f2929 100755 --- a/aot/runtests.sh +++ b/aot/runtests.sh @@ -1,6 +1,6 @@ #!/bin/bash thisdir="$(dirname "${BASH_SOURCE[0]}")" -exec "$thisdir/julia.sh" --startup-file=no --color=yes --project $thisdir -e ' +exec "$thisdir/julia.sh" --startup-file=no --color=yes --project=$thisdir -e ' using Pkg Pkg.test("PyCall") ' From 57fd8fdb94e0912978c408d9df19a110b64f2f16 Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Tue, 12 Jan 2021 05:00:57 -0500 Subject: [PATCH 19/28] Cleanup tests --- test/runtests.jl | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index b38cc7d6..10a64848 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -50,12 +50,7 @@ const PyInt = pyversion < v"3" ? Int : Clonglong @test pyany_toany(PyAny) == Any @test pyany_toany(Tuple{Int,PyAny}) == Tuple{Int,Any} @test pyany_toany(Tuple{Int,Tuple{PyAny,Int8}}) == Tuple{Int,Tuple{Any,Int8}} - @info "Julia $VERSION" - if v"1.7.0-DEV.0" <= VERSION < v"1.7" - @test_skip pyany_toany(Tuple{PyAny,Int,Vararg{PyAny}}) == Tuple{Any,Int,Vararg{Any}} - else - @test pyany_toany(Tuple{PyAny,Int,Vararg{PyAny}}) == Tuple{Any,Int,Vararg{Any}} - end + @test pyany_toany(Tuple{PyAny,Int,Vararg{PyAny}}) == Tuple{Any,Int,Vararg{Any}} @test roundtripeq(17) @test roundtripeq(0x39) From 151bffe7d2a19830a432e0b5873764048335169d Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Tue, 12 Jan 2021 15:06:04 -0500 Subject: [PATCH 20/28] Fix whitespace --- src/numpy.jl | 2 +- test/runtests.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/numpy.jl b/src/numpy.jl index 84a455a0..380ea8c2 100644 --- a/src/numpy.jl +++ b/src/numpy.jl @@ -244,4 +244,4 @@ function PyObjectWithParent(a::StridedSubArray{T,N}) where {T <: PYARR_TYPES,N} PySlice(ind-1:ind-1) slices = map( ind2slice , inds ) pycall( parent.__getitem__, PyObject, slices ) -end \ No newline at end of file +end diff --git a/test/runtests.jl b/test/runtests.jl index 10a64848..afa36815 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -50,7 +50,7 @@ const PyInt = pyversion < v"3" ? Int : Clonglong @test pyany_toany(PyAny) == Any @test pyany_toany(Tuple{Int,PyAny}) == Tuple{Int,Any} @test pyany_toany(Tuple{Int,Tuple{PyAny,Int8}}) == Tuple{Int,Tuple{Any,Int8}} - @test pyany_toany(Tuple{PyAny,Int,Vararg{PyAny}}) == Tuple{Any,Int,Vararg{Any}} + @test pyany_toany(Tuple{PyAny,Int,Vararg{PyAny}}) == Tuple{Any,Int,Vararg{Any}} @test roundtripeq(17) @test roundtripeq(0x39) From 60979d73adf3dea147d106bfa10c46964c5a560e Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Tue, 12 Jan 2021 15:36:11 -0500 Subject: [PATCH 21/28] Annotate Core.TypeofVararg code --- src/conversions.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/conversions.jl b/src/conversions.jl index be0e3766..60ca93eb 100644 --- a/src/conversions.jl +++ b/src/conversions.jl @@ -170,7 +170,8 @@ function pyany_toany(T::Type) end pyany_toany(::Type{PyAny}) = Any pyany_toany(t::Type{T}) where {T<:Tuple} = Tuple{map(pyany_toany, t.types)...} -if VERSION >= v"1.7.0-DEV.0" +@static if isdefined(Core, :TypeofVararg) # VERSION >= v"1.7.0-DEV.77" + # Core.TypeofVararg introduced in https://github.com/JuliaLang/julia/pull/38136 pyany_toany(T::Core.TypeofVararg) = T === Vararg{PyAny} ? Vararg{Any} : T end # PyAny acts like Any for conversions, except for converting PyObject (below) From 51dfc0227b37882c438660fe3fe6e04e98bab796 Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Wed, 13 Jan 2021 14:17:07 -0500 Subject: [PATCH 22/28] Remove PyObjectWithParent code --- src/numpy.jl | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/numpy.jl b/src/numpy.jl index 380ea8c2..47dbe6d9 100644 --- a/src/numpy.jl +++ b/src/numpy.jl @@ -225,23 +225,3 @@ PyObject(a::Union{LinearAlgebra.Adjoint{<:Real},LinearAlgebra.Transpose}) = PyReverseDims(a.parent) PyObject(a::LinearAlgebra.Adjoint) = PyObject(Matrix(a)) # non-real arrays require a copy - -# Alternative conversion of array views mapping parent in Julia to base in Numpy -PyObjectWithParent(a::AbstractArray) = PyObject(a) - -function PyObjectWithParent(pda::PermutedDimsArray{T,N,perm}) where {T,N,perm} - parent = PyObjectWithParent(pda.parent) - # numpy.transpose is similar to PermutedDimsArray and creates a view of the data - pycall(parent.transpose, PyObject, perm .- 1) -end - -function PyObjectWithParent(a::StridedSubArray{T,N}) where {T <: PYARR_TYPES,N} - parent = PyObjectWithParent(a.parent) - inds = a.indices - # hasstep(T) = Val( hasmethod( step, Tuple{ typeof(T) } ) ) - ind2slice(ind) = isa(ind,AbstractRange) ? - PySlice(ind .- 1) : - PySlice(ind-1:ind-1) - slices = map( ind2slice , inds ) - pycall( parent.__getitem__, PyObject, slices ) -end From cd36aa2c127d3456ad1feda8397d37d6ed1528d6 Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Wed, 13 Jan 2021 14:17:45 -0500 Subject: [PATCH 23/28] Remove automatic conversion of slices to PySlice --- src/conversions.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/conversions.jl b/src/conversions.jl index 60ca93eb..6f711650 100644 --- a/src/conversions.jl +++ b/src/conversions.jl @@ -789,8 +789,6 @@ function pysequence_query(o::PyObject) return typetuple(pytype_query(PyObject(ccall((@pysym :PySequence_GetItem), PyPtr, (PyPtr,Int), o,i-1)), PyAny) for i = 1:len) elseif pyisinstance(o, pyxrange[]) return AbstractRange - elseif pyisinstance(o, pyslice[]) - return PySlice elseif ispybytearray(o) return Vector{UInt8} elseif !isbuftype(o) From fa4ed28f2c282fd5a0e14ca4954dc786325f5e72 Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Wed, 13 Jan 2021 14:28:04 -0500 Subject: [PATCH 24/28] Use applicable rather than hasmethod --- src/gc.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gc.jl b/src/gc.jl index ffa52003..2057ddf4 100644 --- a/src/gc.jl +++ b/src/gc.jl @@ -30,7 +30,7 @@ function pyembed(po::PyObject, jo::Any) # If there's a need to support immutable embedding, # the API needs to be changed to return the pointer. if isimmutable(jo) - if hasmethod(parent, ( typeof(jo), ) ) + if applicable(parent, jo) return pyembed(po, parent(jo) ) else throw(ArgumentError("pyembed: immutable argument not allowed")) From 0c8db2034adffa25a6b30787d235883d22afb440 Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Wed, 13 Jan 2021 14:33:15 -0500 Subject: [PATCH 25/28] Remove PyObjectWithParent tests --- test/runtests.jl | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index afa36815..3aec7159 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -159,11 +159,6 @@ const PyInt = pyversion < v"3" ? Int : Clonglong B[1] = 3 @test C == B && C[1] == B[1] - C = PyArray( PyCall.PyObjectWithParent(B) ) - @test C == B - B[1] = 2 - @test C == B && C[1] == B[1] - # SubArray B = view(A, 1:2, 2:2) C = PyArray( PyObject(B) ) @@ -171,11 +166,6 @@ const PyInt = pyversion < v"3" ? Int : Clonglong A[3] = 5 @test C == B && C[1] == A[3] - C = PyArray( PyCall.PyObjectWithParent(B) ) - @test C == B - A[3] = 4 - @test C == B && C[1] == A[3] - # ReshapedArray B = Base.ReshapedArray( A, (1,4), () ) C = PyArray( PyObject(B) ) @@ -190,11 +180,6 @@ const PyInt = pyversion < v"3" ? Int : Clonglong A[1] == 7 @test C == B && C[1] == A[1] - C = PyArray( PyCall.PyObjectWithParent(B) ) - @test C == B - A[1] == 8 - @test C == B && C[1] == A[1] - # ReinterpretArray B = reinterpret(UInt64, A) C = PyArray( PyObject(B) ) From 777db620f4ccc3b500ca338a62020807e685329f Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Fri, 15 Jan 2021 01:51:16 -0500 Subject: [PATCH 26/28] Replace Core.TypeofVararg with typeof(Vararg) --- src/conversions.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversions.jl b/src/conversions.jl index 6f711650..acb14f89 100644 --- a/src/conversions.jl +++ b/src/conversions.jl @@ -172,7 +172,7 @@ pyany_toany(::Type{PyAny}) = Any pyany_toany(t::Type{T}) where {T<:Tuple} = Tuple{map(pyany_toany, t.types)...} @static if isdefined(Core, :TypeofVararg) # VERSION >= v"1.7.0-DEV.77" # Core.TypeofVararg introduced in https://github.com/JuliaLang/julia/pull/38136 - pyany_toany(T::Core.TypeofVararg) = T === Vararg{PyAny} ? Vararg{Any} : T + pyany_toany(T::typeof(Vararg)) = T === Vararg{PyAny} ? Vararg{Any} : T end # PyAny acts like Any for conversions, except for converting PyObject (below) convert(::Type{PyAny}, x) = x From 97bb48b8d446b847eff6518438983432afe47edc Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Thu, 28 Jan 2021 00:57:06 -0500 Subject: [PATCH 27/28] Remove PySlice, pyslice, and other slice related code for a separate PR --- src/PyCall.jl | 4 ++-- src/conversions.jl | 35 ----------------------------------- src/pyinit.jl | 4 ---- test/runtests.jl | 44 +------------------------------------------- 4 files changed, 3 insertions(+), 84 deletions(-) diff --git a/src/PyCall.jl b/src/PyCall.jl index effaa885..5acf61f9 100644 --- a/src/PyCall.jl +++ b/src/PyCall.jl @@ -8,7 +8,7 @@ using VersionParsing export pycall, pycall!, pyimport, pyimport_e, pybuiltin, PyObject, PyReverseDims, PyPtr, pyincref, pydecref, pyversion, - PyArray, PyArray_Info, PyBuffer, PySlice, + PyArray, PyArray_Info, PyBuffer, pyerr_check, pyerr_clear, pytype_query, PyAny, @pyimport, PyDict, pyisinstance, pywrap, pytypeof, pyeval, PyVector, pystring, pystr, pyrepr, pyraise, pytype_mapping, pygui, pygui_start, pygui_stop, @@ -23,7 +23,7 @@ import Base: size, ndims, similar, copy, getindex, setindex!, stride, append!, insert!, prepend!, unsafe_convert, pushfirst!, popfirst!, firstindex, lastindex, getproperty, setproperty!, propertynames, - first, last, step, StridedSubArray, ReinterpretArray, ReshapedArray + StridedSubArray, ReinterpretArray, ReshapedArray if isdefined(Base, :hasproperty) # Julia 1.2 import Base: hasproperty diff --git a/src/conversions.jl b/src/conversions.jl index acb14f89..0226f036 100644 --- a/src/conversions.jl +++ b/src/conversions.jl @@ -233,38 +233,6 @@ function convert(::Type{Pair{K,V}}, o::PyObject) where {K,V} return Pair(k, v) end -######################################################################### -# PySlice: no-copy wrapping of a Julia object around a Python slice - -slice(start, stop, step) = pycall(pyslice[], PyObject, - start, stop, step) - -struct PySlice{T} <: AbstractRange{T} - o::PyObject - function PySlice{T}(o::PyObject) where T - if !pyisinstance(o, pyslice[]) - throw(ArgumentError("Argument must be a slice")) - end - new{T}(o) - end -end - -PySlice(stop) = PySlice{typeof(stop)}( slice(nothing, stop, nothing) ) -PySlice(start, stop) = PySlice{promote_type(typeof(start),typeof(stop))}( slice(start, stop, nothing) ) -PySlice(start, stop, step) = PySlice{promote_type(typeof(start),typeof(stop),typeof(step))}( slice(start, stop, step) ) -PySlice(r::AbstractRange{T}) where T = PySlice{T}( slice(first(r), last(r)+1, step(r)) ) -PySlice(S::PySlice{T}) where T = S - -first(s::PySlice{T}) where T = (pystart = s.o.start; pystart === nothing ? 0 : pystart) -last(s::PySlice{T}) where T = s.o.stop-1 -step(s::PySlice{T}) where T = (pystep = s.o.step; pystep === nothing ? 1 : pystep) -length(s::PySlice{T}) where T = length( first(s):step(s):last(s) ) - -convert(::Type{PyObject}, S::PySlice) = S.o -convert(::Type{PySlice}, o::PyObject) = PySlice{Int}(o) -PyObject(S::PySlice) = S.o - - ######################################################################### # PyVector: no-copy wrapping of a Julia object around a Python sequence @@ -647,9 +615,6 @@ function PyObject(r::AbstractRange{T}) where T<:Integer end function convert(::Type{T}, o::PyObject) where T<:AbstractRange - if pyisinstance(o, pyslice[]) - return o.start:o.step:o.stop-1 - end v = PyVector(o) len = length(v) if len == 0 diff --git a/src/pyinit.jl b/src/pyinit.jl index 6d6cb4e4..42a928df 100644 --- a/src/pyinit.jl +++ b/src/pyinit.jl @@ -20,7 +20,6 @@ const c_void_p_Type = PyNULL() # or are simply left as non-const values const pynothing = Ref{PyPtr}(0) const pyxrange = Ref{PyPtr}(0) -const pyslice = Ref{PyPtr}(0) ######################################################################### # initialize jlWrapType for pytype.jl @@ -218,9 +217,6 @@ function __init__() # xrange type (or range in Python 3) pyxrange[] = @pyglobalobj(:PyRange_Type) - # slice type - pyslice[] = @pyglobalobj(:PySlice_Type) - # ctypes.c_void_p for Ptr types copy!(c_void_p_Type, pyimport("ctypes")."c_void_p") diff --git a/test/runtests.jl b/test/runtests.jl index 3aec7159..82a6700f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -89,48 +89,6 @@ const PyInt = pyversion < v"3" ? Int : Clonglong @test roundtrip(testkw)(314157) == 314157 @test roundtrip(testkw)(314157, y=1) == 314159 - let s = PyCall.slice(nothing, 10, nothing) - @test s.start === nothing - @test s.stop == 10 - @test s.step === nothing - @test PySlice{Int}(s) == 0:9 - @test convert(PySlice, s) == 0:9 - @test PyObject( PySlice{Int}(s) ) === s - end - - let s = PyCall.slice(1, 5, nothing) - @test s.start == 1 - @test s.stop == 5 - @test s.step === nothing - @test PySlice{Int}(s) == 1:4 - @test convert(PySlice, s) == 1:4 - @test PyObject( PySlice{Int}(s) ) === s - end - - let s = PyCall.slice(3, 9, 2) - @test s.start == 3 - @test s.stop == 9 - @test s.step == 2 - @test PySlice{Int}(s) == 3:2:7 - @test convert(PySlice, s) == 3:2:7 - @test PyObject( PySlice{Int}(s) ) === s - end - - let s = PySlice(4, 5) - @test first(s) == 4 - @test last(s) == 4 - @test step(s) == 1 - @test length(s) == 1 - @test PySlice(s) === s - @test s == pybuiltin("slice")(4, 5) - end - - @test PySlice(5) == 0:4 - @test PySlice(1,5) == 1:4 - @test PySlice(1,6,2) == 1:2:5 - @test PySlice(1:5) == 1:5 - @test PySlice(2:2:6) == 2:2:6 - # check type stability of pycall with an explicit return type @inferred pycall(PyObject(1).__add__, Int, 2) @@ -172,7 +130,7 @@ const PyInt = pyversion < v"3" ? Int : Clonglong @test C == B A[2] = 6 @test C == B && C[2] == A[2] - + # PermutedDimsArray B = PermutedDimsArray(A, (2,1) ) C = PyArray( PyObject(B) ) From d7a1030be7bd8332b14b3c02bef3b4a11d92dafc Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Thu, 28 Jan 2021 01:01:10 -0500 Subject: [PATCH 28/28] Remove unused reference to StridedSubArray --- src/PyCall.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PyCall.jl b/src/PyCall.jl index 5acf61f9..0ca5a849 100644 --- a/src/PyCall.jl +++ b/src/PyCall.jl @@ -23,7 +23,7 @@ import Base: size, ndims, similar, copy, getindex, setindex!, stride, append!, insert!, prepend!, unsafe_convert, pushfirst!, popfirst!, firstindex, lastindex, getproperty, setproperty!, propertynames, - StridedSubArray, ReinterpretArray, ReshapedArray + ReinterpretArray, ReshapedArray if isdefined(Base, :hasproperty) # Julia 1.2 import Base: hasproperty