Skip to content

Commit e3e3008

Browse files
authored
add pyinclude macro (#948)
1 parent 429f251 commit e3e3008

File tree

5 files changed

+40
-2
lines changed

5 files changed

+40
-2
lines changed

Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "PyCall"
22
uuid = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
33
authors = ["Steven G. Johnson <stevenj@mit.edu>", "Yichao Yu <yyc1992@gmail.com>", "Takafumi Arakaki <aka.tkf@gmail.com>", "Simon Kornblith <simon@simonster.com>", "Páll Haraldsson <Pall.Haraldsson@gmail.com>", "Jon Malmaud <malmaud@gmail.com>", "Jake Bolewski <jakebolewski@gmail.com>", "Keno Fischer <keno@alumni.harvard.edu>", "Joel Mason <jobba1@hotmail.com>", "Jameson Nash <vtjnash@gmail.com>", "The JuliaPy development team"]
4-
version = "1.92.5"
4+
version = "1.93.0"
55

66
[deps]
77
Conda = "8f4d0f93-b110-5947-807f-2305c1781a2d"

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ def sinpi(x):
165165
py"sinpi"(1)
166166
```
167167

168+
You can also execute a whole script `"foo.py"` via `@pyinclude("foo.py")` as if you had pasted it into a `py"""..."""` string.
169+
168170
When creating a Julia module, it is a useful pattern to define Python
169171
functions or classes in Julia's `__init__` and then use it in Julia
170172
function with `py"..."`.
@@ -390,6 +392,11 @@ and also by providing more type information to the Julia compiler.
390392
`__init__`. Side-effect in Python occurred at top-level Julia scope
391393
cannot be used at run-time for precompiled modules.
392394

395+
You can also execute a Python script file `"foo.py"` by running `@pyinclude("foo.py")`, and it will be as if you had pasted the
396+
script into a `py"..."` string. (`@pyinclude` does not support
397+
interpolating Julia variables with `$var`, however — the script
398+
must be pure Python.)
399+
393400
* `pybuiltin(s)`: Look up `s` (a string or symbol) among the global Python
394401
builtins. If `s` is a string it returns a `PyObject`, while if `s` is a
395402
symbol it returns the builtin converted to `PyAny`. (You can also use `py"s"`

src/PyCall.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export pycall, pycall!, pyimport, pyimport_e, pybuiltin, PyObject, PyReverseDims
1414
pyraise, pytype_mapping, pygui, pygui_start, pygui_stop,
1515
pygui_stop_all, @pylab, set!, PyTextIO, @pysym, PyNULL, ispynull, @pydef,
1616
pyimport_conda, @py_str, @pywith, @pycall, pybytes, pyfunction, pyfunctionret,
17-
pywrapfn, pysetarg!, pysetargs!
17+
pywrapfn, pysetarg!, pysetargs!, @pyinclude
1818

1919
import Base: size, ndims, similar, copy, getindex, setindex!, stride,
2020
convert, pointer, summary, convert, show, haskey, keys, values,

src/pyeval.jl

+21
Original file line numberDiff line numberDiff line change
@@ -232,3 +232,24 @@ macro py_str(code, options...)
232232
ret
233233
end
234234
end
235+
236+
"""
237+
@pyinclude(filename)
238+
239+
Execute the Python script in the file `filename` as if
240+
it were in a `py\"\"\" ... \"\"\"` block, e.g. so that
241+
any globals defined in `filename` are available to
242+
subsequent `py"..."` evaluations.
243+
244+
(Unlike `py"..."`, however, `@pyinclude` does not
245+
interpolate Julia variables into `\$var` expressions —
246+
the `filename` script must be pure Python.)
247+
"""
248+
macro pyinclude(fname)
249+
quote
250+
m = pynamespace($__module__)
251+
fname = $(esc(fname))
252+
pyeval_(read(fname, String), m, m, Py_file_input, fname)
253+
nothing
254+
end
255+
end

test/runtests.jl

+10
Original file line numberDiff line numberDiff line change
@@ -819,3 +819,13 @@ if lowercase(get(ENV, "JULIA_PKGEVAL", "false")) != "true"
819819
include("test_venv.jl")
820820
include("test_build.jl")
821821
end
822+
823+
@testset "@pyinclude" begin
824+
mktemp() do path, io
825+
print(io, "foo1 = 1\nbar2 = 2\n")
826+
close(io)
827+
@pyinclude(path)
828+
@test py"foo1" == 1
829+
@test py"bar2" == 2
830+
end
831+
end

0 commit comments

Comments
 (0)