From dc27f11d273437ef0daf035da355b14578d0eb57 Mon Sep 17 00:00:00 2001 From: Joel Mason Date: Tue, 3 Apr 2018 16:55:42 +1000 Subject: [PATCH 1/3] Add syntax to call python functions using pyfn=>ReturnType adds a shorthand `(pyfun=>ReturnType)(args...; kws...)` for `pycall(pyfn, ReturnType, args...; kws...)`. --- README.md | 11 ++++++----- src/PyCall.jl | 1 + test/runtests.jl | 2 ++ test/testmisc.jl | 16 ++++++++++++++++ 4 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 test/testmisc.jl diff --git a/README.md b/README.md index ad94f7f4..ea45bc06 100644 --- a/README.md +++ b/README.md @@ -328,15 +328,16 @@ cases where the Python return type is known can also improve performance, both by eliminating the overhead of runtime type inference and also by providing more type information to the Julia compiler. -* `pycall(function::PyObject, returntype::Type, args...)`. Call the given - Python `function` (typically looked up from a module) with the given +* `pycall(pyfunc::PyObject, returntype::Type, args...)`. Call the given + Python function `pyfunc` (typically looked up from a module) with the given `args...` (of standard Julia types which are converted automatically to the corresponding Python types if possible), converting the return value to `returntype` (use a `returntype` of `PyObject` to return the unconverted Python object reference, or of `PyAny` to request an automated conversion). - For convenience, a macro `@pycall` exists which automatically converts - `@pycall function(args...)::returntype` into - `pycall(function,returntype,args...)`. + * For convenience, a macro `@pycall` exists which automatically converts + `@pycall pyfunc(args...)::returntype` into + `pycall(pyfunc,returntype,args...)`. + * Another equivalent is `(pyfunc=>returntype)(args...)`. Alternatively you can define `pyfunc_ret = pyfunc=>returntype`, then call `pyfunc_ret(args...)` instead of `pycall(pyfunc,returntype,args...)` * `pyimport(s)`: Import the Python module `s` (a string or symbol) and return a pointer to it (a `PyObject`). Functions or other symbols diff --git a/src/PyCall.jl b/src/PyCall.jl index 37cd10c2..6e82b008 100644 --- a/src/PyCall.jl +++ b/src/PyCall.jl @@ -732,6 +732,7 @@ pycall(o::Union{PyObject,PyPtr}, ::Type{PyAny}, args...; kwargs...) = return convert(PyAny, _pycall(o, args...; kwargs...)) (o::PyObject)(args...; kws...) = pycall(o, PyAny, args...; kws...) +(ot::Pair{PyObject, <:TypeTuple})(args...; kws...) = pycall(ot[1], ot[2], args...; kws...) PyAny(o::PyObject) = convert(PyAny, o) diff --git a/test/runtests.jl b/test/runtests.jl index 3db84b83..b9ef256e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -560,3 +560,5 @@ end @test_throws ErrorException @pywith IgnoreError(false) error() @test (@pywith IgnoreError(true) error(); true) end + +include("testmisc.jl") \ No newline at end of file diff --git a/test/testmisc.jl b/test/testmisc.jl new file mode 100644 index 00000000..a0bfca10 --- /dev/null +++ b/test/testmisc.jl @@ -0,0 +1,16 @@ +using Compat.Test, PyCall + +PyCall.@npyinitialize # see #481 + +@testset "pair call syntax" begin + np = pyimport("numpy") + arrpyo = np["array"]=>PyObject + arrpytpl = np["array"]=>Tuple{Vararg{Int}} + arrpyvec = np["array"]=>Vector{Int} + arrpyany = np["array"]=>PyAny + @test typeof(arrpyo(1:10)) == PyObject + @test arrpytpl(1:10) isa Tuple{Vararg{Int}} + @test typeof(arrpytpl(1:10)) == NTuple{10, Int} + @test typeof(arrpyvec(1:10)) == Vector{Int} + @test typeof(arrpyany(1:10)) == Vector{Int} +end From eec331dbcca0da72cc73d995db9778d73e662a0f Mon Sep 17 00:00:00 2001 From: Joel Mason Date: Sat, 7 Apr 2018 03:08:37 +1000 Subject: [PATCH 2/3] numpy.array to array.array --- test/testmisc.jl | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/test/testmisc.jl b/test/testmisc.jl index a0bfca10..38576f93 100644 --- a/test/testmisc.jl +++ b/test/testmisc.jl @@ -1,16 +1,15 @@ using Compat.Test, PyCall -PyCall.@npyinitialize # see #481 - @testset "pair call syntax" begin - np = pyimport("numpy") - arrpyo = np["array"]=>PyObject - arrpytpl = np["array"]=>Tuple{Vararg{Int}} - arrpyvec = np["array"]=>Vector{Int} - arrpyany = np["array"]=>PyAny - @test typeof(arrpyo(1:10)) == PyObject - @test arrpytpl(1:10) isa Tuple{Vararg{Int}} - @test typeof(arrpytpl(1:10)) == NTuple{10, Int} - @test typeof(arrpyvec(1:10)) == Vector{Int} - @test typeof(arrpyany(1:10)) == Vector{Int} + pyarr = pyimport("array")["array"] + arrpyo = pyarr=>PyObject + arrpytpl = pyarr=>Tuple{Vararg{Float64}} + arrpyvec = pyarr=>Vector{Float64} + arrpyany = pyarr=>PyAny + @test typeof(arrpyo("d", 1.0:10.0)) == PyObject + @test arrpytpl("d", 1.0:10.0) isa Tuple{Vararg{Float64}} + @test typeof(arrpytpl("d", 1.0:10.0)) == NTuple{10, Float64} + @test typeof(arrpyvec("d", 1.0:10.0)) == Vector{Float64} + # broken with __array_interface__ but not with buffer protocol + @test_broken typeof(arrpyany("d", 1.0:10.0)) == Vector{Float64} end From 17f5329c8ef647b510ee5e4c05a77e3f81ede983 Mon Sep 17 00:00:00 2001 From: Joel Mason Date: Mon, 9 Apr 2018 01:31:37 +1000 Subject: [PATCH 3/3] apparently array.array doesn't support the buffer protocol in py 2.7 --- test/testmisc.jl | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/test/testmisc.jl b/test/testmisc.jl index 38576f93..82eb1d9e 100644 --- a/test/testmisc.jl +++ b/test/testmisc.jl @@ -1,15 +1,14 @@ using Compat.Test, PyCall @testset "pair call syntax" begin - pyarr = pyimport("array")["array"] - arrpyo = pyarr=>PyObject - arrpytpl = pyarr=>Tuple{Vararg{Float64}} - arrpyvec = pyarr=>Vector{Float64} - arrpyany = pyarr=>PyAny - @test typeof(arrpyo("d", 1.0:10.0)) == PyObject - @test arrpytpl("d", 1.0:10.0) isa Tuple{Vararg{Float64}} - @test typeof(arrpytpl("d", 1.0:10.0)) == NTuple{10, Float64} - @test typeof(arrpyvec("d", 1.0:10.0)) == Vector{Float64} - # broken with __array_interface__ but not with buffer protocol - @test_broken typeof(arrpyany("d", 1.0:10.0)) == Vector{Float64} + pylist = pybuiltin("list") + listpyo = pylist=>PyObject + listpytpl = pylist=>Tuple{Vararg{Float64}} + listpyvec = pylist=>Vector{Float64} + listpyany = pylist=>PyAny + @test typeof(listpyo(1.0:10.0)) == PyObject + @test listpytpl(1.0:10.0) isa Tuple{Vararg{Float64}} + @test typeof(listpytpl(1.0:10.0)) == NTuple{10, Float64} + @test typeof(listpyvec(1.0:10.0)) == Vector{Float64} + @test typeof(listpyany(1.0:10.0)) == Vector{Float64} end