Looks good to me. The verbosity is because PythonCall intentionally requires explicitly converting things back to Julia with pyconvert (unlike PyCall) - but ultimately it makes your code easier to reason about and more type stable.
The only improvements I can suggest are to do
using SymPyPythonCall.PythonCall
then you don’t need the pc. prefix.
Aside: you should really just have your project depend on PythonCall explicitly and do
BTW while the above advice about pynew and pycopy! is correct, I advise using one of the methods documented here instead: Guide · PythonCall & JuliaCall (my recommendation is the first version, with Ref).
These methods are safe (whereas pycopy! is unsafe in that it can cause memory corruption if you get it wrong), and I’m considering deprecating pycopy! from the API in PythonCall v1.
If anything, rename it to unsafe_pycopy!. It’s quite useful for module initialization because it allows a module like PythonPlot to initialize a variable like PythonPlot.matplotlib to directly access a Python object, without forcing the user to do PythonPlot.matplotlib[].
(But it can be made safe if you only use it with valid Py objects or NULL objects, no? Whereas with an invalid Py object, i.e. a corrupted pointer, everything is unsafe. It’s really PythonCall.pynew() that’s unsafe, because a lot of PythonCall functions don’t check for NULL pointers.)