Skip to content

Commit 2857e9a

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

File tree

2 files changed

+153
-20
lines changed

2 files changed

+153
-20
lines changed

README.md

Lines changed: 152 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,57 +6,69 @@ 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:
48+
49+
```sh
50+
python3 -m pip install --user 'https://github.com/JuliaPy/pyjulia/archive/master.zip#egg=julia'
3951
```
4052

4153
You may clone it directly to your home directory.
4254

4355
```
4456
git clone https://github.com/JuliaPy/pyjulia
45-
4657
```
58+
4759
then inside the pyjulia directory you need to run the python setup file
4860

4961
```
50-
[sudo] pip install [-e] .
62+
cd pyjulia
63+
python3 -m pip install --user .
64+
python3 -m pip install --user -e . # If you want "development install"
5165
```
5266

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

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")`.
71+
See [Testing](#testing) below for how to run tests.
6072

6173
Usage
6274
-----
@@ -126,6 +138,84 @@ from julia import Base
126138
```
127139

128140

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

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

144277

145278
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)