Skip to content

Commit 295f0fe

Browse files
author
Christopher Doris
committed
add @pyjltry macro for common try-catch pattern
1 parent 1afc393 commit 295f0fe

File tree

2 files changed

+80
-164
lines changed

2 files changed

+80
-164
lines changed

src/cpython/juliabase.jl

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,58 @@ PyJuliaValue_TryConvert_any(o, ::Type{S}) where {S} = begin
100100
x = PyJuliaValue_GetValue(o)
101101
putresult(tryconvert(S, x))
102102
end
103+
104+
macro pyjltry(body, errval, handlers...)
105+
handlercode = []
106+
finalcode = nothing
107+
for handler in handlers
108+
handler isa Expr && handler.head === :call && handler.args[1] == :(=>) || error("invalid handler: $handler (not a pair)")
109+
jt, pt = handler.args[2:end]
110+
if jt === :Finally
111+
finalcode = esc(pt)
112+
break
113+
end
114+
if jt isa Expr && jt.head === :tuple
115+
args = jt.args[2:end]
116+
jt = jt.args[1]
117+
else
118+
args = []
119+
end
120+
if jt === :MethodError
121+
if length(args) == 0
122+
cond = :(err isa MethodError)
123+
elseif length(args) == 1
124+
cond = :(err isa MethodError && err.f === $(esc(args[1])))
125+
elseif length(args) == 2
126+
cond = :(err isa MethodError && (err.f === $(esc(args[1])) || err.f === $(esc(args[2]))))
127+
elseif length(args) == 3
128+
cond = :(err isa MethodError && (err.f === $(esc(args[1])) || err.f === $(esc(args[2])) || err.f === $(esc(args[3]))))
129+
else
130+
error("more than two methods not implemented")
131+
end
132+
else
133+
error("invalid handler: $handler (bad julia error type)")
134+
end
135+
if pt === :JuliaError
136+
seterr = :(PyErr_SetJuliaError(err))
137+
elseif pt === :TypeError
138+
seterr = :(PyErr_SetStringFromJuliaError(PyExc_ValueError(), err))
139+
elseif pt === :ValueError
140+
seterr = :(PyErr_SetStringFromJuliaError(PyExc_ValueError(), err))
141+
else
142+
error("invalid handler: $handler (bad python error type)")
143+
end
144+
push!(handlercode, :($cond && ($seterr; return $(esc(errval)))))
145+
end
146+
quote
147+
try
148+
$(esc(body))
149+
catch err
150+
$(handlercode...)
151+
PyErr_SetJuliaError(err)
152+
return $(esc(errval))
153+
finally
154+
$finalcode
155+
end
156+
end
157+
end

src/cpython/juliaio.jl

Lines changed: 25 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -34,112 +34,42 @@ end
3434

3535
pyjlio_close(xo::PyPtr, ::PyPtr) = begin
3636
x = PyJuliaValue_GetValue(xo)::IO
37-
try
38-
close(x)
39-
PyNone_New()
40-
catch err
41-
if err isa MethodError && err.f === close
42-
PyErr_SetStringFromJuliaError(PyExc_ValueError(), err)
43-
else
44-
PyErr_SetJuliaError(err)
45-
end
46-
PyNULL
47-
end
37+
@pyjltry (close(x); PyNone_New()) PyNULL (MethodError, close)=>ValueError
4838
end
4939

5040
pyjlio_closed(xo::PyPtr, ::Ptr{Cvoid}) = begin
5141
x = PyJuliaValue_GetValue(xo)::IO
52-
try
53-
PyObject_From(!isopen(x))
54-
catch err
55-
if err isa MethodError && err.f === isopen
56-
PyErr_SetStringFromJuliaError(PyExc_ValueError(), err)
57-
else
58-
PyErr_SetJuliaError(err)
59-
end
60-
PyNULL
61-
end
42+
@pyjltry PyObject_From(!isopen(x)) PyNULL (MethodError, isopen)=>ValueError
6243
end
6344

6445
pyjlio_fileno(xo::PyPtr, ::PyPtr) = begin
6546
x = PyJuliaValue_GetValue(xo)::IO
66-
try
67-
PyObject_From(fd(x))
68-
catch err
69-
if err isa MethodError && err.f === fd
70-
PyErr_SetStringFromJuliaError(PyExc_ValueError(), err)
71-
else
72-
PyErr_SetJuliaError(err)
73-
end
74-
PyNULL
75-
end
47+
@pyjltry PyObject_From(fd(x)) PyNULL (MethodError, fd)=>ValueError
7648
end
7749

7850
pyjlio_flush(xo::PyPtr, ::PyPtr) = begin
7951
x = PyJuliaValue_GetValue(xo)::IO
80-
try
81-
flush(x)
82-
PyNone_New()
83-
catch err
84-
if err isa MethodError && err.f === flush
85-
PyErr_SetStringFromJuliaError(PyExc_ValueError(), err)
86-
else
87-
PyErr_SetJuliaError(err)
88-
end
89-
PyNULL
90-
end
52+
@pyjltry (flush(x); PyNone_New()) PyNULL (MethodError, flush)=>ValueError
9153
end
9254

9355
pyjlio_isatty(xo::PyPtr, ::PyPtr) = begin
9456
x = PyJuliaValue_GetValue(xo)::IO
95-
try
96-
PyObject_From(x isa Base.TTY)
97-
catch err
98-
PyErr_SetJuliaError(err)
99-
PyNULL
100-
end
57+
@pyjltry PyObject_From(x isa Base.TTY) PyNULL
10158
end
10259

10360
pyjlio_readable(xo::PyPtr, ::PyPtr) = begin
10461
x = PyJuliaValue_GetValue(xo)::IO
105-
try
106-
PyObject_From(isreadable(x))
107-
catch err
108-
if err isa MethodError && err.f === isreadable
109-
PyErr_SetStringFromJuliaError(PyExc_ValueError(), err)
110-
else
111-
PyErr_SetJuliaError(err)
112-
end
113-
PyNULL
114-
end
62+
@pyjltry PyObject_From(isreadable(x)) PyNULL (MethodError, isreadable)=>ValueError
11563
end
11664

11765
pyjlio_writable(xo::PyPtr, ::PyPtr) = begin
11866
x = PyJuliaValue_GetValue(xo)::IO
119-
try
120-
PyObject_From(iswritable(x))
121-
catch err
122-
if err isa MethodError && err.f === iswritable
123-
PyErr_SetStringFromJuliaError(PyExc_ValueError(), err)
124-
else
125-
PyErr_SetJuliaError(err)
126-
end
127-
PyNULL
128-
end
67+
@pyjltry PyObject_From(iswritable(x)) PyNULL (MethodError, iswritable)=>ValueError
12968
end
13069

13170
pyjlio_tell(xo::PyPtr, ::PyPtr) = begin
13271
x = PyJuliaValue_GetValue(xo)::IO
133-
try
134-
PyObject_From(position(x))
135-
catch err
136-
if err isa MethodError && err.f === position
137-
PyErr_SetStringFromJuliaError(PyExc_ValueError(), err)
138-
else
139-
PyErr_SetJuliaError(err)
140-
end
141-
PyNULL
142-
end
72+
@pyjltry PyObject_From(position(x)) PyNULL (MethodError, position)=>ValueError
14373
end
14474

14575
pyjlio_seek(xo::PyPtr, args::PyPtr) = begin
@@ -149,7 +79,7 @@ pyjlio_seek(xo::PyPtr, args::PyPtr) = begin
14979
n = takeresult(Int)
15080
ism1(PyArg_GetArg(Int, "seek", args, 1, 0)) && return PyNULL
15181
w = takeresult(Int)
152-
try
82+
@pyjltry begin
15383
if w == 0
15484
seek(x, n)
15585
elseif w == 1
@@ -162,14 +92,7 @@ pyjlio_seek(xo::PyPtr, args::PyPtr) = begin
16292
return PyNULL
16393
end
16494
PyObject_From(position(x))
165-
catch err
166-
if err isa MethodError && (err.f === seek || err.f === position || err.f === seekend)
167-
PyErr_SetStringFromJuliaError(PyExc_ValueError(), err)
168-
else
169-
PyErr_SetJuliaError(err)
170-
end
171-
PyNULL
172-
end
95+
end PyNULL (MethodError, seek, position, seekend)=>ValueError
17396
end
17497

17598
pyjlio_writelines(xo::PyPtr, lines::PyPtr) = begin
@@ -212,18 +135,11 @@ pyjlio_truncate(xo::PyPtr, args::PyPtr) = begin
212135
return PyNULL
213136
n = takeresult(Union{Int,Nothing})
214137
x = PyJuliaValue_GetValue(xo)::IO
215-
try
138+
@pyjltry begin
216139
m = n === nothing ? position(x) : n
217140
truncate(x, m)
218141
PyObject_From(m)
219-
catch err
220-
if err isa MethodError && (err.f === truncate || err.f === position)
221-
PyErr_SetStringFromJuliaError(PyExc_ValueError(), err)
222-
else
223-
PyErr_SetJuliaError(err)
224-
end
225-
PyNULL
226-
end
142+
end PyNULL (MethodError, truncate, position)=>ValueError
227143
end
228144

229145
pyjlio_seekable(xo::PyPtr, ::PyPtr) = begin
@@ -242,19 +158,10 @@ pyjlio_write_bytes(xo::PyPtr, bo::PyPtr) = begin
242158
b = Ref(Py_buffer())
243159
ism1(PyObject_GetBuffer(bo, b, PyBUF_SIMPLE)) && return PyNULL
244160
s = unsafe_wrap(Vector{UInt8}, Ptr{UInt8}(b[].buf), b[].len)
245-
try
161+
@pyjltry begin
246162
write(x, s)
247163
PyObject_From(length(s))
248-
catch err
249-
if err isa MethodError && err.f === write
250-
PyErr_SetStringFromJuliaError(PyExc_ValueError(), err)
251-
else
252-
PyErr_SetJuliaError(err)
253-
end
254-
PyNULL
255-
finally
256-
PyBuffer_Release(b)
257-
end
164+
end PyNULL (MethodError, write)=>ValueError Finally=>PyBuffer_Release(b)
258165
end
259166

260167
pyjlio_write_str(xo::PyPtr, so::PyPtr) = begin
@@ -263,7 +170,7 @@ pyjlio_write_str(xo::PyPtr, so::PyPtr) = begin
263170
s = takeresult(String)
264171
sep = ""
265172
havesep = false
266-
try
173+
@pyjltry begin
267174
i = firstindex(s)
268175
while true
269176
j = findnext('\n', s, i)
@@ -291,33 +198,15 @@ pyjlio_write_str(xo::PyPtr, so::PyPtr) = begin
291198
end
292199
end
293200
PyObject_From(length(s))
294-
catch err
295-
if err isa MethodError && err.f === write
296-
PyErr_SetStringFromJuliaError(PyExc_ValueError(), err)
297-
else
298-
PyErr_SetJuliaError(err)
299-
end
300-
PyNULL
301-
end
201+
end PyNULL (MethodError, write)=>ValueError
302202
end
303203

304204
pyjlio_readinto(xo::PyPtr, bo::PyPtr) = begin
305205
b = Ref(Py_buffer())
306206
ism1(PyObject_GetBuffer(bo, b, PyBUF_WRITABLE)) && return PyNULL
307207
x = PyJuliaValue_GetValue(xo)::IO
308208
a = unsafe_wrap(Vector{UInt8}, Ptr{UInt8}(b[].buf), b[].len)
309-
try
310-
PyObject_From(readbytes!(x, a, length(a)))
311-
catch err
312-
if err isa MethodError && err.f === readbytes!
313-
PyErr_SetStringFromJuliaError(PyExc_ValueError(), err)
314-
else
315-
PyErr_SetJuliaError(err)
316-
end
317-
PyNULL
318-
finally
319-
PyBuffer_Release(b)
320-
end
209+
@pyjltry PyObject_From(readbytes!(x, a, length(a))) PyNULL (MethodError, readbytes!)=>ValueError Finally=>PyBuffer_Release(b)
321210
end
322211

323212
readpybytes(io::IO, limit = nothing) = begin
@@ -335,16 +224,9 @@ pyjlio_read_bytes(xo::PyPtr, args::PyPtr) = begin
335224
ism1(PyArg_GetArg(Union{Int,Nothing}, "read", args, 0, nothing)) && return PyNULL
336225
limit = takeresult(Union{Int,Nothing})
337226
x = PyJuliaValue_GetValue(xo)::IO
338-
try
227+
@pyjltry begin
339228
PyBytes_From(readpybytes(x, (limit === nothing || limit < 0) ? nothing : limit))
340-
catch err
341-
if err isa MethodError && (err.f === eof || err.f === read || err.f === peek)
342-
PyErr_SetStringFromJuliaError(PyExc_ValueError(), err)
343-
else
344-
PyErr_SetJuliaError(err)
345-
end
346-
PyNULL
347-
end
229+
end PyNULL (MethodError, eof, read, peek)=>ValueError
348230
end
349231

350232
readpystr(io::IO, limit = nothing) = begin
@@ -370,16 +252,9 @@ pyjlio_read_str(xo::PyPtr, args::PyPtr) = begin
370252
ism1(PyArg_GetArg(Union{Int,Nothing}, "read", args, 0, nothing)) && return PyNULL
371253
limit = takeresult(Union{Int,Nothing})
372254
x = PyJuliaValue_GetValue(xo)::IO
373-
try
255+
@pyjltry begin
374256
PyObject_From(readpystr(x, (limit === nothing || limit < 0) ? nothing : limit))
375-
catch err
376-
if err isa MethodError && (err.f === eof || err.f === read || err.f === peek)
377-
PyErr_SetStringFromJuliaError(PyExc_ValueError(), err)
378-
else
379-
PyErr_SetJuliaError(err)
380-
end
381-
PyNULL
382-
end
257+
end PyNULL (MethodError, eof, read, peek)=>ValueError
383258
end
384259

385260
readpybyteline(io::IO, limit = nothing) = begin
@@ -399,16 +274,9 @@ pyjlio_readline_bytes(xo::PyPtr, args::PyPtr) = begin
399274
return PyNULL
400275
limit = takeresult(Union{Int,Nothing})
401276
x = PyJuliaValue_GetValue(xo)::IO
402-
try
277+
@pyjltry begin
403278
PyBytes_From(readpybyteline(x, (limit === nothing || limit < 0) ? nothing : limit))
404-
catch err
405-
if err isa MethodError && (err.f === eof || err.f === read || err.f === peek)
406-
PyErr_SetStringFromJuliaError(PyExc_ValueError(), err)
407-
else
408-
PyErr_SetJuliaError(err)
409-
end
410-
PyNULL
411-
end
279+
end PyNULL (MethodError, eof, read, peek)=>ValueError
412280
end
413281

414282
readpyline(io::IO, limit = nothing) = begin
@@ -437,16 +305,9 @@ pyjlio_readline_str(xo::PyPtr, args::PyPtr) = begin
437305
return PyNULL
438306
limit = takeresult(Union{Int,Nothing})
439307
x = PyJuliaValue_GetValue(xo)::IO
440-
try
308+
@pyjltry begin
441309
PyObject_From(readpyline(x, (limit === nothing || limit < 0) ? nothing : limit))
442-
catch err
443-
if err isa MethodError && (err.f === eof || err.f === read || err.f === peek)
444-
PyErr_SetStringFromJuliaError(PyExc_ValueError(), err)
445-
else
446-
PyErr_SetJuliaError(err)
447-
end
448-
PyNULL
449-
end
310+
end PyNULL (MethodError, eof, read, peek)=>ValueError
450311
end
451312

452313
const PyJuliaIOValue_Type = LazyPyObject() do

0 commit comments

Comments
 (0)