Repository: JuliaPy/PyCall.jl
Pull request #948 (2021-12-21 13:21:26)

add pyinclude macro
Add a `@pyinclude("foo.py")` macro, which is nearly equivalent to
```jl
py"""
$$(read("foo.py", String)
"""
```

codecov-commenter: # [Codecov](https://codecov.io/gh/JuliaPy/PyCall.jl/pull/948?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
> Merging [#948](https://codecov.io/gh/JuliaPy/PyCall.jl/pull/948?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (de447f0) into [master](https://codecov.io/gh/JuliaPy/PyCall.jl/commit/429f2515ec7d34027c32ee1a057b301e4966f403?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (429f251) will **decrease** coverage by `1.44%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/JuliaPy/PyCall.jl/pull/948/graphs/tree.svg?width=650&height=150&src=pr&token=aC5yT2hEvI&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)](https://codecov.io/gh/JuliaPy/PyCall.jl/pull/948?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)

```diff
@@            Coverage Diff             @@
##           master     #948      +/-   ##
==========================================
- Coverage   68.24%   66.80%   -1.45%     
==========================================
  Files          20       20              
  Lines        2012     1997      -15     
==========================================
- Hits         1373     1334      -39     
- Misses        639      663      +24     
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `66.80% <100.00%> (-1.45%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/JuliaPy/PyCall.jl/pull/948?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | Coverage Δ | |
|---|---|---|
| [src/PyCall.jl](https://codecov.io/gh/JuliaPy/PyCall.jl/pull/948/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL1B5Q2FsbC5qbA==) | `62.82% <ø> (-7.88%)` | :arrow_down: |
| [src/pyeval.jl](https://codecov.io/gh/JuliaPy/PyCall.jl/pull/948/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL3B5ZXZhbC5qbA==) | `70.27% <100.00%> (-0.21%)` | :arrow_down: |
| [src/pyinit.jl](https://codecov.io/gh/JuliaPy/PyCall.jl/pull/948/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL3B5aW5pdC5qbA==) | `80.61% <0.00%> (-3.07%)` | :arrow_down: |
| [src/pybuffer.jl](https://codecov.io/gh/JuliaPy/PyCall.jl/pull/948/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL3B5YnVmZmVyLmps) | `60.67% <0.00%> (-0.44%)` | :arrow_down: |
| [src/conversions.jl](https://codecov.io/gh/JuliaPy/PyCall.jl/pull/948/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL2NvbnZlcnNpb25zLmps) | `63.08% <0.00%> (-0.25%)` | :arrow_down: |
| [src/pytype.jl](https://codecov.io/gh/JuliaPy/PyCall.jl/pull/948/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL3B5dHlwZS5qbA==) | `82.75% <0.00%> (+0.94%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/JuliaPy/PyCall.jl/pull/948?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/JuliaPy/PyCall.jl/pull/948?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None). Last update [429f251...de447f0](https://codecov.io/gh/JuliaPy/PyCall.jl/pull/948?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).


Patch:
diff --git a/Project.toml b/Project.toml
index f2a099e..3dea4f2 100644
--- a/Project.toml
+++ b/Project.toml
@@ -1,7 +1,7 @@
 name = "PyCall"
 uuid = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
 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"]
-version = "1.92.5"
+version = "1.93.0"
 
 [deps]
 Conda = "8f4d0f93-b110-5947-807f-2305c1781a2d"
diff --git a/README.md b/README.md
index 3554b4b..d05ee32 100644
--- a/README.md
+++ b/README.md
@@ -165,6 +165,8 @@ def sinpi(x):
 py"sinpi"(1)
 ```
 
+You can also execute a whole script `"foo.py"` via `@pyinclude("foo.py")` as if you had pasted it into a `py"""..."""` string.
+
 When creating a Julia module, it is a useful pattern to define Python
 functions or classes in Julia's `__init__` and then use it in Julia
 function with `py"..."`.
@@ -390,6 +392,11 @@ and also by providing more type information to the Julia compiler.
   `__init__`.  Side-effect in Python occurred at top-level Julia scope
   cannot be used at run-time for precompiled modules.
 
+  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
+  script into a `py"..."` string.  (`@pyinclude` does not support
+  interpolating Julia variables with `$var`, however — the script
+  must be pure Python.)
+
 * `pybuiltin(s)`: Look up `s` (a string or symbol) among the global Python
   builtins.  If `s` is a string it returns a `PyObject`, while if `s` is a
   symbol it returns the builtin converted to `PyAny`.  (You can also use `py"s"`
diff --git a/src/PyCall.jl b/src/PyCall.jl
index 42713b9..c09cc20 100644
--- a/src/PyCall.jl
+++ b/src/PyCall.jl
@@ -14,7 +14,7 @@ export pycall, pycall!, pyimport, pyimport_e, pybuiltin, PyObject, PyReverseDims
        pyraise, pytype_mapping, pygui, pygui_start, pygui_stop,
        pygui_stop_all, @pylab, set!, PyTextIO, @pysym, PyNULL, ispynull, @pydef,
        pyimport_conda, @py_str, @pywith, @pycall, pybytes, pyfunction, pyfunctionret,
-       pywrapfn, pysetarg!, pysetargs!
+       pywrapfn, pysetarg!, pysetargs!, @pyinclude
 
 import Base: size, ndims, similar, copy, getindex, setindex!, stride,
        convert, pointer, summary, convert, show, haskey, keys, values,
diff --git a/src/pyeval.jl b/src/pyeval.jl
index 4eca19d..a312853 100644
--- a/src/pyeval.jl
+++ b/src/pyeval.jl
@@ -232,3 +232,24 @@ macro py_str(code, options...)
         ret
     end
 end
+
+"""
+    @pyinclude(filename)
+
+Execute the Python script in the file `filename` as if
+it were in a `py\"\"\" ... \"\"\"` block, e.g. so that
+any globals defined in `filename` are available to
+subsequent `py"..."` evaluations.
+
+(Unlike `py"..."`, however, `@pyinclude` does not
+interpolate Julia variables into `\$var` expressions —
+the `filename` script must be pure Python.)
+"""
+macro pyinclude(fname)
+    quote
+        m = pynamespace($__module__)
+        fname = $(esc(fname))
+        pyeval_(read(fname, String), m, m, Py_file_input, fname)
+        nothing
+    end
+end


Test patch:
diff --git a/test/runtests.jl b/test/runtests.jl
index 2e82608..4594cc4 100644
--- a/test/runtests.jl
+++ b/test/runtests.jl
@@ -819,3 +819,13 @@ if lowercase(get(ENV, "JULIA_PKGEVAL", "false")) != "true"
     include("test_venv.jl")
     include("test_build.jl")
 end
+
+@testset "@pyinclude" begin
+    mktemp() do path, io
+        print(io, "foo1 = 1\nbar2 = 2\n")
+        close(io)
+        @pyinclude(path)
+        @test py"foo1" == 1
+        @test py"bar2" == 2
+    end
+end