diff --git a/src/callback.jl b/src/callback.jl index 55d84936..43101edd 100644 --- a/src/callback.jl +++ b/src/callback.jl @@ -39,7 +39,7 @@ function _pyjlwrap_call(f, args_::PyPtr, kw_::PyPtr) return pyreturn(ret) catch e - pyraise(e) + pyraise(e, catch_backtrace()) finally args.o = PyPtr_NULL # don't decref end diff --git a/src/exception.jl b/src/exception.jl index 58c74fa4..84994361 100644 --- a/src/exception.jl +++ b/src/exception.jl @@ -123,16 +123,21 @@ function pyexc_initialize() pyexc[PyIOError] = @pyglobalobjptr :PyExc_IOError end +_showerror_string(io::IO, e, ::Nothing) = showerror(io, e) +_showerror_string(io::IO, e, bt) = showerror(io, e, bt) + +# bt argument defaults to nothing, to delay dispatching on the presence of a +# backtrace until after the try-catch block """ showerror_string(e) :: String Convert output of `showerror` to a `String`. Since this function may be called via Python C-API, it tries to not throw at all cost. """ -function showerror_string(e::T) where {T} +function showerror_string(e::T, bt = nothing) where {T} try io = IOBuffer() - showerror(io, e, catch_backtrace()) + _showerror_string(io, e, bt) return String(take!(io)) catch try @@ -163,14 +168,15 @@ function showerror_string(e::T) where {T} end end -function pyraise(e) +function pyraise(e, bt = nothing) eT = typeof(e) pyeT = haskey(pyexc::Dict, eT) ? pyexc[eT] : pyexc[Exception] ccall((@pysym :PyErr_SetString), Cvoid, (PyPtr, Cstring), - pyeT, string("Julia exception: ", showerror_string(e))) + pyeT, string("Julia exception: ", showerror_string(e, bt))) end -function pyraise(e::PyError) +# Second argument allows for backtraces passed to `pyraise` to be ignored. +function pyraise(e::PyError, ::Vector = []) ccall((@pysym :PyErr_Restore), Cvoid, (PyPtr, PyPtr, PyPtr), e.T, e.val, e.traceback) e.T.o = e.val.o = e.traceback.o = C_NULL # refs were stolen diff --git a/src/pyiterator.jl b/src/pyiterator.jl index 5b4e44d6..80b36987 100644 --- a/src/pyiterator.jl +++ b/src/pyiterator.jl @@ -134,7 +134,7 @@ const jlWrapIteratorType = PyTypeObject() return pyreturn(item) end catch e - pyraise(e) + pyraise(e, catch_backtrace()) end return PyPtr_NULL end @@ -149,7 +149,7 @@ else return pyreturn(item) end catch e - pyraise(e) + pyraise(e, catch_backtrace()) end return PyPtr_NULL end @@ -162,7 +162,7 @@ function pyjlwrap_getiter(self_::PyPtr) self = unsafe_pyjlwrap_to_objref(self_) return pystealref!(jlwrap_iterator(self)) catch e - pyraise(e) + pyraise(e, catch_backtrace()) end return PyPtr_NULL end diff --git a/src/pytype.jl b/src/pytype.jl index 387bc56f..e59303e2 100644 --- a/src/pytype.jl +++ b/src/pytype.jl @@ -348,7 +348,7 @@ function pyjlwrap_repr(o::PyPtr) return pyreturn(o != C_NULL ? string("") : "") catch e - pyraise(e) + pyraise(e, catch_backtrace()) return PyPtr_NULL end end @@ -395,7 +395,7 @@ function pyjlwrap_getattr(self_::PyPtr, attr__::PyPtr) end end catch e - pyraise(e) + pyraise(e, catch_backtrace()) finally attr_.o = PyPtr_NULL # don't decref end