Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ uuid = "bc8888f7-b21e-4b7c-a06a-5d9c9496438c"
authors = ["jverzani <jverzani@gmail.com> and contributors"]
version = "0.2.4"


[deps]
CommonEq = "3709ef60-1bee-4518-9f2f-acd86f176c50"
CommonSolve = "38540f10-b2f7-11e9-35d8-d573e4eb0ff2"
Expand All @@ -19,15 +20,15 @@ Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
SymPyPythonCallSymbolicsExt = "Symbolics"

[compat]
CommonEq = "0.2"
CommonEq = "0.2.1"
CommonSolve = "0.2"
CondaPkg = "0.2"
LinearAlgebra = "1.6.1"
PythonCall = "0.9"
SpecialFunctions = "0.8, 0.9, 0.10, 1.0, 2"
Symbolics = "5"
SymbolicUtils = "1"
SymPyCore = "=0.1.5, 1"
SymPyCore = "0.1.6, 1"
julia = "1.6.1"


Expand Down
1 change: 1 addition & 0 deletions src/SymPyPythonCall.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ _pyimport(a) = PythonCall.pyimport(a)
_pyimport_conda(a,b) = PythonCall.pyimport(a) # XXX lose things
_pyobject(x) = PythonCall.pyconvert(Py, x)
_pytype_mapping(typ,a) = nothing
const _pybuiltin = PythonCall.pybuiltins

core_src_path = joinpath(pathof(SymPyCore), "../../src/SymPy")
include(joinpath(core_src_path, "sympy.jl"))
Expand Down
55 changes: 26 additions & 29 deletions src/python_connection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,24 @@ end

## Modifications for ↓, ↑
Sym(x::Nothing) = Sym(pybuiltins.None)

SymPyCore.:↓(x::PythonCall.Py) = x
SymPyCore.:↓(d::Dict) = pydict((↓(k) => ↓(v) for (k,v) ∈ pairs(d)))
SymPyCore.:↓(x::Set) = _sympy_.sympify(pyset(↓(sᵢ) for sᵢ ∈ x))

SymPyCore.:↑(::Type{<:AbstractString}, x) = Py(x)
SymPyCore.:↑(::Type{<:AbstractString}, x) = Sym(Py(x))
function SymPyCore.:↑(::Type{PythonCall.Py}, x)
class_nm = SymPyCore.classname(x)
class_nm == "set" && return Set(Sym.(collect(x)))
class_nm == "tuple" && return Tuple(↑(xᵢ) for xᵢ ∈ x)
class_nm == "list" && return [↑(xᵢ) for xᵢ ∈ x]
class_nm == "dict" && return Dict(↑(k) => ↑(x[k]) for k ∈ x)

class_nm == "FiniteSet" && return Set(Sym.(collect(x)))
class_nm == "MutableDenseMatrix" && return _up_matrix(x) #map(↑, x.tolist())
# this lower level approach shouldn't allocate
pyisinstance(x, pybuiltins.set) && return Set(Sym.(x)) #Set(↑(xᵢ) for xᵢ ∈ x)
pyisinstance(x, pybuiltins.tuple) && return Tuple(↑(xᵢ) for xᵢ ∈ x)
pyisinstance(x, pybuiltins.list) && return [↑(xᵢ) for xᵢ ∈ x]
pyisinstance(x, pybuiltins.dict) && return Dict(↑(k) => ↑(x[k]) for k ∈ x)

# others ... more hands on than pytype_mapping
# add more sympy containers in sympy.jl and here
pyisinstance(x, _FiniteSet_) && return Set(Sym.(x))
pyisinstance(x, _MutableDenseMatrix_) && return _up_matrix(x) #map(↑, x.tolist())

# fallback
Sym(x)
end

Expand All @@ -52,42 +53,38 @@ end

# should we also have different code path for a::String like PyCall?
function Base.getproperty(x::SymbolicObject{T}, a::Symbol) where {T <: PythonCall.Py}

a == :o && return getfield(x, a)

if a == :py
Base.depwarn("The field `.py` has been renamed `.o`", :getproperty)
return getfield(x,:o)
end

val = ↓(x)
!hasproperty(val, a) && return nothing # not a property
𝑎 = string(a)

meth = getproperty(val, a)
hasproperty(val, 𝑎) || return nothing # not a property
meth = getproperty(val, 𝑎)

pyconvert(Bool, meth == pybuiltins.None) && return nothing
pyis(meth, pybuiltins.None) && return nothing

if hasproperty(meth, "is_Boolean")
if pyconvert(Bool, meth.is_Boolean == true)
return meth == _sympy_.logic.boolalg.BooleanFalse
end
## __call__
if pycallable(meth) # "__call__") #hasproperty(meth, "__call__")
return SymPyCore.SymbolicCallable(meth)
end

# __class__ dispatch
if hasproperty(meth, :__class__)
cnm = string(meth.__class__.__name__)
if cnm == "bool"
return pyconvert(Bool, meth)
end
if cnm == "module"
# treat modules, callsm others differently
return Sym(meth)
end
if pyisinstance(meth, _bool_)
return pyconvert(Bool, meth)
end

## __call__
if hasproperty(meth, "__call__")
return SymPyCore.SymbolicCallable(meth)
if pyisinstance(meth, _ModuleType_)
return Sym(meth)
end


# just convert
return ↑(convert(PythonCall.Py, meth))

end
Expand Down