Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

change py_str to py_cmd #794

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
46 changes: 23 additions & 23 deletions README.md
Expand Up @@ -145,45 +145,45 @@ which is automatically converted to a Julia type, you will have override this
via `@pywith EXPR::PyObject ...`.

If you are already familiar with Python, it perhaps is easier to use
`py"..."` and `py"""..."""` which are equivalent to Python's
`` py`...` `` and ` py```...``` ` which are equivalent to Python's
[`eval`](https://docs.python.org/3/library/functions.html#eval) and
[`exec`](https://docs.python.org/3/library/functions.html#exec),
respectively:

```julia
py"""
````julia
py```
import numpy as np

def sinpi(x):
return np.sin(np.pi * x)
"""
py"sinpi"(1)
```
py`sinpi`(1)
````

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"..."`.
function with `` py`...` ``.

```julia
````julia
module MyModule

using PyCall

function __init__()
py"""
py```
import numpy as np

def one(x):
return np.sin(x) ** 2 + np.cos(x) ** 2
"""
```
end

two(x) = py"one"(x) + py"one"(x)
two(x) = py`one`(x) + py`one`(x)

end
```
````

Note that Python code in `py"..."` of above example is evaluated in a
Note that Python code in `` py`...` `` of above example is evaluated in a
Python namespace dedicated to `MyModule`. Thus, Python function `one`
cannot be accessed outside `MyModule`.

Expand Down Expand Up @@ -355,38 +355,38 @@ and also by providing more type information to the Julia compiler.
`@pycall function(args...)::returntype` into
`pycall(function,returntype,args...)`.

* `py"..."` evaluates `"..."` as Python code, equivalent to
* `` py`...` `` evaluates `"..."` as Python code, equivalent to
Python's [`eval`](https://docs.python.org/3/library/functions.html#eval) function, and returns the result
converted to `PyAny`. Alternatively, `py"..."o` returns the raw `PyObject`
converted to `PyAny`. Alternatively, `` py`...`o `` returns the raw `PyObject`
(which can then be manually converted if desired). You can interpolate
Julia variables and other expressions into the Python code with `$`,
which interpolates the *value* (converted to `PyObject`) of the given
expression---data is not passed as a string, so this is different from
ordinary Julia string interpolation. e.g. `py"sum($([1,2,3]))"` calls the
ordinary Julia string interpolation. e.g. `` py`sum($([1,2,3]))` `` calls the
Python `sum` function on the Julia array `[1,2,3]`, returning `6`.
In contrast, if you use `$$` before the interpolated expression, then
the value of the expression is inserted as a string into the Python code,
allowing you to generate Python code itself via Julia expressions.
For example, if `x="1+1"` in Julia, then `py"$x"` returns the string `"1+1"`,
but `py"$$x"` returns `2`.
If you use `py"""..."""` to pass a *multi-line* string, the string can
For example, if `x="1+1"` in Julia, then `` py`$x` `` returns the string `"1+1"`,
but `` py`$$x` `` returns `2`.
If you use ` py```...``` ` to pass a *multi-line* string, the string can
contain arbitrary Python code (not just a single expression) to be evaluated,
but the return value is `nothing`; this is useful e.g. to define pure-Python
functions, and is equivalent to Python's
[`exec`](https://docs.python.org/3/library/functions.html#exec) function.
(If you define a Python global `g` in a multiline `py"""..."""`
string, you can retrieve it in Julia by subsequently evaluating `py"g"`.)
(If you define a Python global `g` in a multiline ` py```...``` `
string, you can retrieve it in Julia by subsequently evaluating `` py`g` ``.)

When `py"..."` is used inside a Julia module, it uses a Python namespace
When `` py`...` `` is used inside a Julia module, it uses a Python namespace
dedicated to this Julia module. Thus, you can define Python function
using `py"""...."""` in your module without worrying about name clash
using ` py```....``` ` in your module without worrying about name clash
with other Python code. Note that Python functions _must_ be defined in
`__init__`. Side-effect in Python occurred at top-level Julia scope
cannot be used at run-time for precompiled modules.

* `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"`
symbol it returns the builtin converted to `PyAny`. (You can also use `` py`s` ``
to look up builtins or other Python globas.)

Occasionally, you may need to pass a keyword argument to Python that
Expand Down
4 changes: 2 additions & 2 deletions src/PyCall.jl
Expand Up @@ -13,8 +13,8 @@ export pycall, pycall!, pyimport, pyimport_e, pybuiltin, PyObject, PyReverseDims
pyisinstance, pywrap, pytypeof, pyeval, PyVector, pystring, pystr, pyrepr,
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!
pyimport_conda, @py_cmd, @py_str, @pywith, @pycall, pybytes, pyfunction,
pyfunctionret, pywrapfn, pysetarg!, pysetargs!

import Base: size, ndims, similar, copy, getindex, setindex!, stride,
convert, pointer, summary, convert, show, haskey, keys, values,
Expand Down
26 changes: 18 additions & 8 deletions src/pyeval.jl
Expand Up @@ -53,7 +53,7 @@ For example, `pyeval("x + y", x=1, y=2)` returns 3.
function pyeval(s::AbstractString, returntype::TypeTuple=PyAny,
locals=PyDict{AbstractString, PyObject}(),
input_type=Py_eval_input; kwargs...)
# construct deprecation warning in favor of py"..." strings
# construct deprecation warning in favor of py`...` strings
depbuf = IOBuffer()
q = input_type==Py_eval_input ? "\"" : "\"\"\"\n"
qr = reverse(q)
Expand Down Expand Up @@ -177,17 +177,18 @@ function interpolate_pycode(code::AbstractString)
end

"""
py".....python code....."
py`.....python code.....`[o]
py".....python code....."[o]

Evaluate the given Python code string in the main Python module.
Evaluate the given Python code in the main Python module.

If the string is a single line (no newlines), then the Python
If the input is a single line (no newlines), then the Python
expression is evaluated and the result is returned.
If the string is multiple lines (contains a newline), then the Python
If the input has multiple lines (contains a newline), then the Python
code is compiled and evaluated in the `__main__` Python module
and nothing is returned.

If the `o` option is appended to the string, as in `py"..."o`, then the
If the `o` option is appended to the command, as in ``` py`...`o ```, then the
return value is an unconverted `PyObject`; otherwise, it is
automatically converted to a native Julia type if possible.

Expand All @@ -196,12 +197,21 @@ Any `\$var` or `\$(expr)` expressions that appear in the Python code
and passed to Python via auto-generated global variables. This
allows you to "interpolate" Julia values into Python code.

Similarly, ny `\$\$var` or `\$\$(expr)` expressions in the Python code
Similarly, `\$\$var` or `\$\$(expr)` expressions in the Python code
are evaluated in Julia, converted to strings via `string`, and are
pasted into the Python code. This allows you to evaluate code
pasted into the Python code. This allows you to evaluate code
where the code itself is generated by a Julia expression.
"""
macro py_cmd(code, options...)
return py_cmd(__module__, code, options...)
end

@doc (@doc @py_cmd)
macro py_str(code, options...)
return py_cmd(__module__, code, options...)
end

function py_cmd(__module__, code, options...)
T = length(options) == 1 && 'o' in options[1] ? PyObject : PyAny
code, locals = interpolate_pycode(code)
input_type = '\n' in code ? Py_file_input : Py_eval_input
Expand Down