Pluto.jl
Pluto.jl copied to clipboard
Pluto only shows a part of a stacktrace with PythonCall
Pluto's stacktrace doesn't show essential information:
compared to the Julia REPL:
julia> using PythonCall
julia> pybuiltins.sum(error(i) for i in 1:10)
ERROR: Python: Julia: 1
Stacktrace:
[1] error(s::Int64)
@ Base ./error.jl:44
[2] (::var"#8#9")(i::Int64)
@ Main ./none:0
[3] iterate(::Base.Generator{UnitRange{Int64}, var"#8#9"})
@ Base ./generator.jl:47
[4] pyjliter_next(self::PythonCall.JlWrap.Iterator)
@ PythonCall.JlWrap ~/.julia/packages/PythonCall/sQSpa/src/JlWrap/iter.jl:0
[5] _pyjl_callmethod(f::Any, self_::Ptr{PythonCall.C.PyObject}, args_::Ptr{PythonCall.C.PyObject}, nargs::Int64)
@ PythonCall.JlWrap ~/.julia/packages/PythonCall/sQSpa/src/JlWrap/base.jl:62
[6] _pyjl_callmethod(o::Ptr{PythonCall.C.PyObject}, args::Ptr{PythonCall.C.PyObject})
@ PythonCall.JlWrap.Cjl ~/.julia/packages/PythonCall/sQSpa/src/JlWrap/C.jl:63
[7] PyObject_CallObject
@ ~/.julia/packages/PythonCall/sQSpa/src/C/pointers.jl:301 [inlined]
[8] macro expansion
@ ~/.julia/packages/PythonCall/sQSpa/src/Core/Py.jl:132 [inlined]
[9] pycallargs
@ ~/.julia/packages/PythonCall/sQSpa/src/Core/builtins.jl:220 [inlined]
[10] pycall(f::Py, args::Base.Generator{UnitRange{Int64}, var"#8#9"}; kwargs::@Kwargs{})
@ PythonCall.Core ~/.julia/packages/PythonCall/sQSpa/src/Core/builtins.jl:243
[11] pycall
@ ~/.julia/packages/PythonCall/sQSpa/src/Core/builtins.jl:233 [inlined]
[12] (::Py)(args::Base.Generator{UnitRange{Int64}, var"#8#9"})
@ PythonCall.Core ~/.julia/packages/PythonCall/sQSpa/src/Core/Py.jl:357
[13] top-level scope
@ REPL[10]:1
[14] eval
@ ./boot.jl:385 [inlined]
[15] eval_user_input(ast::Any, backend::REPL.REPLBackend, mod::Module)
@ REPL ~/.julia/juliaup/julia-1.10.4+0.aarch64.apple.darwin14/share/julia/stdlib/v1.10/REPL/src/REPL.jl:150
[16] repl_backend_loop(backend::REPL.REPLBackend, get_module::Function)
@ REPL ~/.julia/juliaup/julia-1.10.4+0.aarch64.apple.darwin14/share/julia/stdlib/v1.10/REPL/src/REPL.jl:246
[17] start_repl_backend(backend::REPL.REPLBackend, consumer::Any; get_module::Function)
@ REPL ~/.julia/juliaup/julia-1.10.4+0.aarch64.apple.darwin14/share/julia/stdlib/v1.10/REPL/src/REPL.jl:231
[18] run_repl(repl::REPL.AbstractREPL, consumer::Any; backend_on_current_task::Bool, backend::Any)
@ REPL ~/.julia/juliaup/julia-1.10.4+0.aarch64.apple.darwin14/share/julia/stdlib/v1.10/REPL/src/REPL.jl:389
[19] run_repl(repl::REPL.AbstractREPL, consumer::Any)
@ REPL ~/.julia/juliaup/julia-1.10.4+0.aarch64.apple.darwin14/share/julia/stdlib/v1.10/REPL/src/REPL.jl:375
[20] (::Base.var"#1013#1015"{Bool, Bool, Bool})(REPL::Module)
@ Base ./client.jl:432
[21] #invokelatest#2
@ ./essentials.jl:892 [inlined]
[22] invokelatest
@ ./essentials.jl:889 [inlined]
[23] run_main_repl(interactive::Bool, quiet::Bool, banner::Bool, history_file::Bool, color_set::Bool)
@ Base ./client.jl:416
[24] exec_options(opts::Base.JLOptions)
@ Base ./client.jl:333
[25] _start()
@ Base ./client.jl:552
Python stacktrace:
[1] __next__
@ ~/.julia/packages/PythonCall/sQSpa/src/JlWrap/iter.jl:39
Stacktrace:
[1] pythrow()
@ PythonCall.Core ~/.julia/packages/PythonCall/sQSpa/src/Core/err.jl:92
[2] errcheck
@ ~/.julia/packages/PythonCall/sQSpa/src/Core/err.jl:10 [inlined]
[3] pycallargs
@ ~/.julia/packages/PythonCall/sQSpa/src/Core/builtins.jl:220 [inlined]
[4] pycall(f::Py, args::Base.Generator{UnitRange{Int64}, var"#8#9"}; kwargs::@Kwargs{})
@ PythonCall.Core ~/.julia/packages/PythonCall/sQSpa/src/Core/builtins.jl:243
[5] pycall
@ ~/.julia/packages/PythonCall/sQSpa/src/Core/builtins.jl:233 [inlined]
[6] (::Py)(args::Base.Generator{UnitRange{Int64}, var"#8#9"})
@ PythonCall.Core ~/.julia/packages/PythonCall/sQSpa/src/Core/Py.jl:357
[7] top-level scope
@ REPL[10]:1
Thanks @aplavin !
Maybe you could help by figuring out how this works in the REPL? I see 3 stack traces, where are these stored and how are they displayed?
I think PythonCall just uses the Julia showerror mechanism, see https://github.com/JuliaPy/PythonCall.jl/blob/bcd2bbbf1e75ed88d3814c69730137f551bbdbf2/src/Core/err.jl#L112 and around.
help?> showerror
search: showerror
showerror(io, e)
Show a descriptive representation of an exception object e. This method is
used to display the exception after a call to throw.
Oof that looks complicated... What do you think is a good solution? Maybe we should not use our fancy stack trace for PyException and just show it terminal-style?
Could you run PlutoRunner.PRETTY_STACKTRACES[] = false in your notebook and see if this is an improvement?
I won't have capacity to fix this soon, but feel free to make a PR! Search for "integrations" in the PlutoRunner file for doing package speicific thinngs. @schlichtanders maybe you can also help if this is relevant to you?