Skip to content

Commit 80ed1ff

Browse files
author
Christopher Doris
committed
tests for pyeval and pyexec
1 parent 626e1fd commit 80ed1ff

File tree

2 files changed

+70
-7
lines changed

2 files changed

+70
-7
lines changed

src/concrete/code.jl

+13-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
const MODULE_GLOBALS = Dict{Module,Py}()
22

3-
function _pyeval_args(globals, locals)
3+
function _pyeval_args(code, globals, locals)
4+
if code isa AbstractString
5+
code_ = code
6+
elseif ispy(code)
7+
code_ = code
8+
else
9+
throw(ArgumentError("code must be a string or Python code"))
10+
end
411
if globals isa Module
512
globals_ = get!(pydict, MODULE_GLOBALS, globals)
613
elseif ispy(globals)
@@ -15,7 +22,7 @@ function _pyeval_args(globals, locals)
1522
else
1623
locals_ = pydict(locals)
1724
end
18-
return (globals_, locals_)
25+
return (code_, globals_, locals_)
1926
end
2027

2128
"""
@@ -39,8 +46,8 @@ pyeval(Float64, "x+y", Main, (x=1.1, y=2.2)) # returns 3.3
3946
```
4047
"""
4148
function pyeval(::Type{T}, code, globals, locals=nothing) where {T}
42-
globals_, locals_ = _pyeval_args(globals, locals)
43-
ans = pybuiltins.eval(code, globals_, locals_)
49+
code_, globals_, locals_ = _pyeval_args(code, globals, locals)
50+
ans = pybuiltins.eval(code_, globals_, locals_)
4451
pydel!(locals_)
4552
return T == Py ? ans : pyconvert(T, ans)
4653
end
@@ -94,8 +101,8 @@ pyeval(Int, "x", Main) # returns 12
94101
```
95102
"""
96103
function pyexec(::Type{T}, code, globals, locals=nothing) where {T}
97-
globals_, locals_ = _pyeval_args(globals, locals)
98-
pydel!(pybuiltins.exec(code, globals_, locals_))
104+
code_, globals_, locals_ = _pyeval_args(code, globals, locals)
105+
pydel!(pybuiltins.exec(code_, globals_, locals_))
99106
ans = _pyexec_ans(T, globals_, locals_)
100107
pydel!(locals_)
101108
return ans

test/concrete.jl

+57-1
Original file line numberDiff line numberDiff line change
@@ -286,5 +286,61 @@ end
286286
end
287287

288288
@testitem "code" begin
289-
# TODO
289+
# check for ArgumentError when inputs are mixed up
290+
@test_throws ArgumentError pyeval(Main, "1+1")
291+
@test_throws ArgumentError pyeval(Main, Main)
292+
@test_throws ArgumentError pyeval("1+1", "1+1")
293+
@test_throws ArgumentError pyexec(Main, "1+1")
294+
@test_throws ArgumentError pyexec(Main, Main)
295+
@test_throws ArgumentError pyexec("1+1", "1+1")
296+
# basic code execution
297+
m = Module(:test)
298+
g = pydict()
299+
@test pyeq(Bool, pyeval("1+1", m), 2)
300+
@test pyeq(Bool, pyeval("1+1", g), 2)
301+
@test pyeq(Bool, pyeval(pystr("1+1"), g), 2)
302+
@test pyexec("1+1", m) === nothing
303+
@test pyexec("1+1", g) === nothing
304+
@test pyexec(pystr("1+1"), g) === nothing
305+
# check the globals are what we think they are
306+
@test pyis(pyeval("globals()", g), g)
307+
mg = pyeval("globals()", m)
308+
@test pyisinstance(mg, pybuiltins.dict)
309+
# these automatically gain 1 item, __builtins__
310+
@test length(g) == 1
311+
@test length(mg) == 1
312+
@test pycontains(g, "__builtins__")
313+
@test pycontains(mg, "__builtins__")
314+
# code should fail when x does not exist
315+
@test_throws PyException pyeval("x+1", g)
316+
@test_throws PyException pyeval("x+1", g)
317+
# now set x and try again
318+
g["x"] = 1
319+
@test pyeq(Bool, pyeval("x+1", g), 2)
320+
# set x using pyexec this time
321+
pyexec("x=2", g)
322+
@test pyeq(Bool, g["x"], 2)
323+
@test pyeq(Bool, pyeval("x+1", g), 3)
324+
# now use locals
325+
# check empty locals have no effect
326+
l = pydict()
327+
@test pyeq(Bool, pyeval("x+1", g, l), 3)
328+
@test pyeq(Bool, pyeval("x+1", g, Dict()), 3)
329+
# now set x locally
330+
l["x"] = 3
331+
@test pyeq(Bool, pyeval("x+1", g, l), 4)
332+
@test pyeq(Bool, pyeval("x+1", g, Dict()), 3)
333+
@test pyeq(Bool, pyeval("x+1", g, Dict("x" => 0)), 1)
334+
@test pyeq(Bool, pyeval("x+1", g, (x=1,)), 2)
335+
# check pyexec runs in local scope
336+
pyexec("x=4", g, l)
337+
@test pyeq(Bool, g["x"], 2)
338+
@test pyeq(Bool, l["x"], 4)
339+
# check global code runs in global scope
340+
pyexec("global y; y=x+1", g, l)
341+
@test pyeq(Bool, g["y"], 5)
342+
@test !pycontains(l, "y")
343+
# check pyeval converts types correctly
344+
@test pyeval(Int, "1+1", g) === 2
345+
@test pyeval(Nothing, "None", g) === nothing
290346
end

0 commit comments

Comments
 (0)