Description
Is your feature request related to a problem? Please describe.
I have users that are passing in python objects of unknown type and Julia code that expects native Julia objects. When trying to migrate from PyCall to PythonCall, I find the conversions defined here do not convert user provided objects into the most native equivalent Julia type.
Describe the solution you'd like
I would like an option to convert an arbitrary Python object to a Julia object with eager semantics. For example,
julia> eager_pyconvert(Any, pyeval("[1.0, 2.0, 3.0]", Main))
3-element Vector{Float64}:
1.0
2.0
3.0
julia> pyconvert(Any, pyeval("[1.0, 2.0, 3.0]", Main)) # Current (if type is unknown)
3-element PyList{Any}:
1.0
2.0
3.0
julia> pyconvert(Array, pyeval("[1.0, 2.0, 3.0]", Main)) # Current (if type is known)
3-element Vector{Float64}:
1.0
2.0
3.0
julia> py"[1.0, 2.0, 3.0]" # PyCall
3-element Vector{Float64}:
1.0
2.0
3.0
By "eager semantics" I mean it will convert to as specific a target type as possible. Or, equivalently, opt out of types defined by PythonCall.jl.
Describe alternatives you've considered
Coming up with a "magic type" that can be passed to the existing pyconvert
function
types(m) = (x for x in (getglobal(m, n) for n in names(m)) if x isa Type && x !== Any)
BaseTypes = BaseTypes = Union{types(Core)..., types(Base)...}
pyconvert(BaseTypes, pyeval("[1.0, 2.0, 3.0]", Main))
Fails because PyList <: BaseTypes
.
Restricting to concrete types segfaults julia
types(m) = (x for x in (getglobal(m, n) for n in names(m)) if x isa Type && !isabstracttype(x))
BaseTypes = Union{types(Core)..., types(Base)...}
pyconvert(BaseTypes, pyeval("[1.0, 2.0, 3.0]", Main))
# [68187] signal (11.2): Segmentation fault: 11
# in expression starting at REPL[41]:1
# ...
Home rolling conversion rules for specific types feels like reinventing the wheel and hard to maintain.
Additional context
Basically, I'd like to opt into the conversion behavior of PyCall.