Skip to content

Commit dfd7eba

Browse files
committed
Add more information in README.md [ci skip]
1 parent 5fc02df commit dfd7eba

File tree

2 files changed

+154
-20
lines changed

2 files changed

+154
-20
lines changed

README.md

Lines changed: 153 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,57 +6,70 @@ PyJulia
66

77
Experimenting with developing a better interface to [Julia language](https://julialang.org/) that works with [Python](https://www.python.org/) 2 & 3 and Julia v0.6+.
88

9-
to run the tests, execute from the toplevel directory
10-
11-
```shell
12-
tox
13-
```
14-
15-
See [Testing](#testing) below for details.
16-
17-
**Note** You need to explicitly add julia to your `PATH`, an alias will not work.
18-
199
`pyjulia` is tested against Python versions 2.7, 3.6, and 3.7. Older versions of Python (than 2.7) are not supported.
2010

2111
Installation
2212
------------
13+
14+
**Note:** If you are using Python installed with Ubuntu or `conda`,
15+
PyJulia does not work by default with standard Python interpreter and
16+
Julia ≥ 0.7. For workarounds, see [Troubleshooting](#troubleshooting)
17+
below. Same caution applies to other Debian-based and possibly other
18+
GNU/Linux distributions.
19+
2320
You will need to install PyCall in your existing Julia installation
2421

2522
```julia
23+
using Pkg # for julia ≥ 0.7
2624
Pkg.add("PyCall")
2725
```
2826

2927
Your python installation must be able to call Julia. If your installer
3028
does not add the Julia binary directory to your `PATH`, you will have to
31-
add it.
29+
add it. _An alias will not work._
3230

3331
Then finally you have to install pyjulia.
3432

33+
**Note:** If you are not familiar with `pip` and have some troubles
34+
with the following installation steps, we recommend to go through
35+
[Tutorials in Python Packaging User Guide](https://packaging.python.org/tutorials/).
36+
3537
To get released versions you can use:
3638

39+
```sh
40+
python3 -m pip install --user julia
41+
python2 -m pip install --user julia # If you need Python 2
3742
```
38-
pip install julia
43+
44+
where `--user` should be omitted if you are using virtual environment
45+
(`virtualenv`, `venv`, `conda`, etc.).
46+
47+
If you are interested in using the development version, you can
48+
install PyJulia directly from GitHub:
49+
50+
```sh
51+
python3 -m pip install --user 'https://github.com/JuliaPy/pyjulia/archive/master.zip#egg=julia'
3952
```
4053

4154
You may clone it directly to your home directory.
4255

4356
```
4457
git clone https://github.com/JuliaPy/pyjulia
45-
4658
```
59+
4760
then inside the pyjulia directory you need to run the python setup file
4861

4962
```
50-
[sudo] pip install [-e] .
63+
cd pyjulia
64+
python3 -m pip install --user .
65+
python3 -m pip install --user -e . # If you want "development install"
5166
```
5267

53-
The `-e` flag makes a development install meaning that any change to pyjulia
68+
The `-e` flag makes a development install, meaning that any change to pyjulia
5469
source tree will take effect at next python interpreter restart without having
5570
to reissue an install command.
5671

57-
`pyjulia` is known to work with `PyCall.jl``v0.7.2`.
58-
59-
If you run into problems using `pyjulia`, first check the version of `PyCall.jl` you have installed by running `Pkg.installed("PyCall")`.
72+
See [Testing](#testing) below for how to run tests.
6073

6174
Usage
6275
-----
@@ -126,6 +139,84 @@ from julia import Base
126139
```
127140

128141

142+
Troubleshooting
143+
---------------
144+
145+
### Your Python interpreter is statically linked to libpython
146+
147+
If you use Python installed with Debian-based Linux distribution such
148+
as Ubuntu or install Python by `conda`, you might have noticed that
149+
PyJulia cannot be initialized properly with Julia ≥ 0.7. This is
150+
because those Python executables are statically linked to libpython.
151+
(See [Limitations](#limitations) below for why that's a problem.)
152+
153+
If you are unsure if your `python` has this problem, you can quickly
154+
check it by:
155+
156+
```console
157+
$ ldd $(which python) | grep libpython
158+
libpython3.7m.so.1.0 => /usr/lib/libpython3.7m.so.1.0 (0x00007f17c12c4000)
159+
```
160+
161+
If it does not print the path to libpython like above, you need to use
162+
one of the workaround below.
163+
164+
The easiest workaround is to use the `python-jl` command bundled in
165+
PyJulia. This can be used instead of normal `python` command for
166+
basic use-cases such as:
167+
168+
```console
169+
$ python-jl your_script.py
170+
$ python-jl -c 'from julia.Base import banner; banner()'
171+
$ python-jl -m IPython
172+
```
173+
174+
See `python-jl --help` for more information.
175+
176+
Note that `python-jl` works by launching Python interpreter inside
177+
Julia. If you are comfortable with working in Julia REPL, you can
178+
simply do:
179+
180+
```julia
181+
julia> using PyCall
182+
183+
julia> py"""
184+
from julia import Julia
185+
Julia(init_julia=False)
186+
187+
from your_module_using_pyjulia import function
188+
function()
189+
"""
190+
```
191+
192+
Alternatively, you can use [pyenv](https://github.com/pyenv/pyenv) to
193+
build
194+
[`--enable-shared` option](https://github.com/pyenv/pyenv/wiki#how-to-build-cpython-with---enable-shared).
195+
Of course, manually building from Python source distribution with the
196+
same configuration also works.
197+
198+
```console
199+
$ PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install 3.6.6
200+
Downloading Python-3.6.6.tar.xz...
201+
-> https://www.python.org/ftp/python/3.6.6/Python-3.6.6.tar.xz
202+
Installing Python-3.6.6...
203+
Installed Python-3.6.6 to /home/USER/.pyenv/versions/3.6.6
204+
205+
$ ldd ~/.pyenv/versions/3.6.6/bin/python3.6 | grep libpython
206+
libpython3.6m.so.1.0 => /home/USER/.pyenv/versions/3.6.6/lib/libpython3.6m.so.1.0 (0x00007fca44c8b000)
207+
```
208+
209+
For more discussion, see:
210+
https://github.com/JuliaPy/pyjulia/issues/185
211+
212+
### Segmentation fault in IPython
213+
214+
You may experience segmentation fault when using PyJulia in old
215+
versions of IPython. You can avoid this issue by updating IPython to
216+
7.0 or above. Alternatively, you can use IPython via Jupyter (e.g.,
217+
`jupyter console`) to workaround the problem.
218+
219+
129220
How it works
130221
------------
131222
PyJulia loads the `libjulia` library and executes the statements therein.
@@ -139,7 +230,50 @@ when reference count drops to zero, so that the Julia object may be freed).
139230
Limitations
140231
------------
141232

142-
Not all valid Julia identifiers are valid Python identifiers. Unicode identifiers are invalid in Python 2.7 and so `pyjulia` cannot call or access Julia methods/variables with names that are not ASCII only. Additionally, it is a common idiom in Julia to append a `!` character to methods which mutate their arguments. These method names are invalid Python identifers. `pyjulia` renames these methods by subsituting `!` with `_b`. For example, the Julia method `sum!` can be called in `pyjulia` using `sum_b(...)`.
233+
### Mismatch in valid set of identifiers
234+
235+
Not all valid Julia identifiers are valid Python identifiers. Unicode
236+
identifiers are invalid in Python 2.7 and so `pyjulia` cannot call or
237+
access Julia methods/variables with names that are not ASCII only.
238+
Although Python 3 allows Unicode identifiers, they are more
239+
aggressively normalized than Julia. For example, `ϵ` (GREEK LUNATE
240+
EPSILON SYMBOL) and `ε` (GREEK SMALL LETTER EPSILON) are identical in
241+
Python 3 but different in Julia. Additionally, it is a common idiom
242+
in Julia to append a `!` character to methods which mutate their
243+
arguments. These method names are invalid Python identifers.
244+
`pyjulia` renames these methods by subsituting `!` with `_b`. For
245+
example, the Julia method `sum!` can be called in `pyjulia` using
246+
`sum_b(...)`.
247+
248+
### Pre-compilation mechanism in Julia 1.0
249+
250+
There was a major overhaul in the module loading system between Julia
251+
0.6 and 1.0. As a result,
252+
[the hack](https://github.com/JuliaPy/pyjulia/tree/master/julia/fake-julia)
253+
supporting the PyJulia to load PyCall.
254+
255+
To understand the issue, you need to understand a bit of details in
256+
PyCall implementation. PyCall uses Julia's precompilation mechanism
257+
to reduce JIT compilation required while Julia is loading it. This
258+
results in encoding the path to libpython used by PyCall when it's
259+
loaded from `julia`. Furthermore, libpython ABI such as C struct
260+
layout varies across Python versions. Currently, this is determined
261+
while precompiling PyJulia and cannot be changed at run-time.
262+
Consequently, PyCall only works if it loads the same libpython in
263+
Julia and Python. This is why PyJulia has to be imported in a Python
264+
executable dynamically linked to libpython when using the same PyCall
265+
precompilation cache.
266+
267+
The aforementioned hack worked by monkey-patching Julia's
268+
precompilation mechanism to emit the precompilation cache file to
269+
other directory when PyCall is used via PyJulia. However, as Juila's
270+
internal for module loading was changed after Juila 0.6, this
271+
monkey-patch does not work anymore. Similar monkey-patch in Julia 1.0
272+
can be done by using `Base.DEPOT_PATH` although it would waste more
273+
disk space than the similar hack for Julia 0.6.
274+
275+
For the update on this problem, see:
276+
https://github.com/JuliaLang/julia/issues/28518
143277

144278

145279
Testing

julia/core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ def is_compatible_exe(jlinfo, _debug=lambda *_: None):
407407
See `python-jl --help` for more information.
408408
409409
For other available workarounds, see:
410-
https://github.com/JuliaPy/pyjulia/issues/185
410+
https://github.com/JuliaPy/pyjulia#troubleshooting
411411
"""
412412

413413

0 commit comments

Comments
 (0)