Passing a dict from Python to Julia

How can I pass a Python dict to Julia using PythonCall?

This is not working:

from juliacall import Main as jl, convert as jlconvert

setdict = {
  "log_level": 1,
  "area": 20.0,
  "solver": "IDA"
}

jlstore = jl.seval("(k, v) -> (@eval $(Symbol(k)) = $v; return)")
jlstore("set", setdict)

print(jl.seval(set))

Error message:

In [1]: %run test_dict2struct.py
Detected IPython. Loading juliacall extension. See https://juliapy.github.io/PythonCall.jl/stable/compat/#IPython
  Activating project at `~/repos/pykitesim`
---------------------------------------------------------------------------
JuliaError                                Traceback (most recent call last)
~/repos/pykitesim/test_dict2struct.py in <module>
     15 jlstore("set", setdict)
     16 
---> 17 print(jl.seval(set))

~/repos/pykitesim/.pixi/envs/default/lib/python3.8/site-packages/juliacall/__init__.py in seval(self, expr)
     23             return ValueBase.__dir__(self) + self._jl_callmethod($(pyjl_methodnum(pyjlmodule_dir)))
     24         def seval(self, expr):
---> 25             return self._jl_callmethod($(pyjl_methodnum(pyjlmodule_seval)), expr)
     26     """, @__FILE__(), "exec"), jl.__dict__)
     27     pycopy!(pyjlmoduletype, jl.ModuleValue)

JuliaError: cannot convert this Python 'type' to a Julia 'String'
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:35
 [2] macro expansion
   @ ~/.julia/packages/PythonCall/S5MOg/src/Convert/pyconvert.jl:357 [inlined]
 [3] macro expansion
   @ ~/.julia/packages/PythonCall/S5MOg/src/Core/Py.jl:132 [inlined]
 [4] pyconvert(::Type{String}, x::Py)
   @ PythonCall.Convert ~/.julia/packages/PythonCall/S5MOg/src/Convert/pyconvert.jl:372
 [5] pyjlmodule_seval(self::Module, expr::Py)
   @ PythonCall.JlWrap ~/.julia/packages/PythonCall/S5MOg/src/JlWrap/module.jl:13
 [6] _pyjl_callmethod(f::Any, self_::Ptr{PythonCall.C.PyObject}, args_::Ptr{PythonCall.C.PyObject}, nargs::Int64)
   @ PythonCall.JlWrap ~/.julia/packages/PythonCall/S5MOg/src/JlWrap/base.jl:66
 [7] _pyjl_callmethod(o::Ptr{PythonCall.C.PyObject}, args::Ptr{PythonCall.C.PyObject})
   @ PythonCall.JlWrap.Cjl ~/.julia/packages/PythonCall/S5MOg/src/JlWrap/C.jl:63

You meant "set" (the string) not set (the type).

1 Like

This works:

from juliacall import Main as jl, convert as jlconvert

setdict = {
  "log_level": 1,
  "area": 20.0,
  "solver": "IDA"
}

jlstore = jl.seval("(k, v) -> (@eval $(Symbol(k)) = $v; return)")
jlstore("set", setdict)

print(jl.set)

Most of the time you should not use jl.seval, but sometimes it is needed. Not so clear to me when it is needed.