Stack trace order is inconsistent
Is your feature request related to a problem? Please describe. Python stack traces place the most recent call last, Julia's place the most recent call first. When I the call stack has a bunch of Python function then a bunch of Julia functions, the most recent call is in the middle. I don't like that.
Describe the solution you'd like It'd be nice if PythonCall printed Python stack traces in julian order and JuliaCall printed julia stack traces in pythonic order.
Julia's Base could also flip the order all stacktraces are printed in :P
In Julia, PythonCall already has custom stacktrace printing so that the Python stack is in the same order as Julia:
julia> @pyexec """
global pyinner, pyouter
def pyinner():
raise ValueError()
def pyouter():
pyinner()
"""
julia> jlinner() = @pyeval "pyouter()"
jlinner (generic function with 1 method)
julia> jlouter() = jlinner()
jlouter (generic function with 1 method)
julia> jlouter()
ERROR: Python: ValueError:
Python stacktrace:
[1] pyinner
@ REPL[5]:1:3
[2] pyouter
@ REPL[5]:1:5
[3] <module>
@ REPL[6]:1:1
Stacktrace:
[1] pythrow()
@ PythonCall C:\Users\chris\.julia\dev\PythonCall\src\err.jl:94
[2] errcheck
@ PythonCall C:\Users\chris\.julia\dev\PythonCall\src\err.jl:10 [inlined]
[3] pycallargs(f::Py, args::Py)
@ PythonCall C:\Users\chris\.julia\dev\PythonCall\src\abstract\object.jl:210
[4] pycall(::Py, ::Py, ::Vararg{Py}; kwargs::@Kwargs{})
@ PythonCall C:\Users\chris\.julia\dev\PythonCall\src\abstract\object.jl:228
[5] pycall
@ PythonCall C:\Users\chris\.julia\dev\PythonCall\src\abstract\object.jl:218 [inlined]
[6] Py
@ PythonCall C:\Users\chris\.julia\dev\PythonCall\src\Py.jl:341 [inlined]
[7] pyeval(::Type{Py}, code::Py, globals::Module, locals::Tuple{})
@ PythonCall C:\Users\chris\.julia\dev\PythonCall\src\concrete\code.jl:50
[8] jlinner
@ Main .\REPL[6]:1 [inlined]
[9] jlouter()
@ Main .\REPL[7]:1
[10] top-level scope
@ REPL[8]:1
But yes, you're right that from Python, the Julia stack is printed in reverse. This is because custom stack printing has not been implemented on that side, so just uses Base.showerror(io, error, backtrace).
>>> jl.seval("""begin
... jlinner() = error()
... jlouter() = jlinner()
... end""")
Julia: jlouter (generic function with 1 method)
>>> def pyinner():
... jl.seval("jlouter()")
...
>>> def pyouter():
... pyinner()
...
>>> pyouter()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in pyouter
File "<stdin>", line 2, in pyinner
File "C:\Users\chris\.julia\packages\PythonCall\qTEA1\src\jlwrap\module.jl", line 25, in seval
return self._jl_callmethod($(pyjl_methodnum(pyjlmodule_seval)), expr)
juliacall.JuliaError:
Stacktrace:
[1] error()
@ Base .\error.jl:44
[2] jlinner()
@ Main .\none:2
[3] jlouter()
@ Main .\none:3
[4] top-level scope
@ none:1
[5] eval
@ .\boot.jl:370 [inlined]
[6] eval
@ .\Base.jl:68 [inlined]
[7] pyjlmodule_seval(self::Module, expr::Py)
@ PythonCall C:\Users\chris\.julia\packages\PythonCall\qTEA1\src\jlwrap\module.jl:13
[8] _pyjl_callmethod(f::Any, self_::Ptr{PythonCall.C.PyObject}, args_::Ptr{PythonCall.C.PyObject}, nargs::Int64)
@ PythonCall C:\Users\chris\.julia\packages\PythonCall\qTEA1\src\jlwrap\base.jl:62
[9] _pyjl_callmethod(o::Ptr{PythonCall.C.PyObject}, args::Ptr{PythonCall.C.PyObject})
@ PythonCall.C C:\Users\chris\.julia\packages\PythonCall\qTEA1\src\cpython\jlwrap.jl:47
It would indeed be nice to improve these stack traces.