Skip to content

Commit 8407cc4

Browse files
committed
add variable interpolation
1 parent eeccb4f commit 8407cc4

File tree

3 files changed

+67
-10
lines changed

3 files changed

+67
-10
lines changed

docs/source/usage.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ You can then use, e.g.,
7070
In IPython (and therefore in Jupyter), you can directly execute Julia
7171
code using `%%julia` magic:
7272

73-
```
73+
```none
7474
In [1]: %load_ext julia.magic
7575
Initializing Julia interpreter. This may take some time...
7676
@@ -86,6 +86,35 @@ In [2]: %%julia
8686
|__/ |
8787
```
8888

89+
Any `$var` or `$(var)` expressions that appear in the Julia code (except in
90+
comments or string literals) are evaluated in Python and passed to Julia. Use
91+
`$$var` to insert a literal `$var` in Julia code.
92+
93+
```none
94+
In [3]: foo = [[1,2],[3,4]]
95+
96+
In [4]: %julia $foo .+ 1
97+
98+
Out[4]:
99+
array([[2, 3],
100+
[4, 5]], dtype=int64)
101+
102+
In [22]: %%julia
103+
...: bar=3
104+
...: :($$bar)
105+
106+
Out[22]: 3
107+
108+
```
109+
110+
Variables are automatically converted between equivalent Python/Julia types (should they exist) using PyCall. Note below that `1`, `x`, and the tuple itself are converted to Julia `Int64`, `String`, and `Tuple`, respectively, although the function `abs` and the result of `typeof` are not.
111+
112+
```none
113+
In [6]: %julia typeof($(1,"x",abs))
114+
115+
Out[6]: <PyCall.jlwrap Tuple{Int64,String,PyObject}>
116+
```
117+
89118
#### IPython configuration
90119

91120
PyJulia-IPython integration can be configured via IPython's

src/julia/magic.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import sys
2323
import warnings
2424

25-
from IPython.core.magic import Magics, magics_class, line_cell_magic
25+
from IPython.core.magic import Magics, magics_class, line_cell_magic, no_var_expand
2626
from IPython.utils import py3compat as compat
2727
from traitlets import Bool, Enum
2828

@@ -89,6 +89,7 @@ def __init__(self, shell):
8989
self._julia = Julia(init_julia=True)
9090
print()
9191

92+
@no_var_expand
9293
@line_cell_magic
9394
def julia(self, line, cell=None):
9495
"""
@@ -97,14 +98,9 @@ def julia(self, line, cell=None):
9798
"""
9899
src = compat.unicode_type(line if cell is None else cell)
99100

100-
try:
101-
ans = self._julia.eval(src)
102-
except JuliaError as e:
103-
print(e, file=sys.stderr)
104-
ans = None
105-
106-
return ans
107-
101+
return self._julia.eval("""
102+
_PyJuliaHelper.@prepare_for_pyjulia_call begin %s end
103+
"""%src)(self.shell.user_ns, self.shell.user_ns)
108104

109105
# Add to the global docstring the class information.
110106
__doc__ = __doc__.format(

src/julia/pyjulia_helper.jl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
module _PyJuliaHelper
22

3+
using PyCall
4+
using PyCall: pyeval_
5+
using MacroTools
6+
using MacroTools: isexpr
7+
38
if VERSION < v"0.7-"
49
nameof(m::Module) = ccall(:jl_module_name, Ref{Symbol}, (Any,), m)
510

@@ -44,6 +49,33 @@ if VERSION >= v"0.7-"
4449
end
4550
end
4651

52+
53+
macro prepare_for_pyjulia_call(ex)
54+
55+
# f(x) returns transformed expression x and whether to recurse
56+
# into the new expression
57+
function walk(f, x)
58+
(fx, recurse) = f(x)
59+
MacroTools.walk(fx, (recurse ? (x -> walk(f,x)) : identity), identity)
60+
end
61+
62+
ex = walk(ex) do x
63+
if isexpr(x, :$)
64+
if isexpr(x.args[1], :$)
65+
x.args[1], false
66+
else
67+
:($convert($PyAny, $pyeval_($("$(x.args[1])"),__globals,__locals))), true
68+
end
69+
else
70+
x, true
71+
end
72+
end
73+
esc(quote
74+
$pyfunction((__globals,__locals) -> $ex, $PyObject, $PyObject)
75+
end)
76+
end
77+
78+
4779
module IOPiper
4880

4981
const orig_stdin = Ref{IO}()

0 commit comments

Comments
 (0)