-
Notifications
You must be signed in to change notification settings - Fork 101
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
Support virtualenv/venv without separate cache #190
Conversation
8a459a9
to
6bd383f
Compare
cache = joinpath(path, "PyCall.ji") | ||
backup = joinpath(path, "PyCall.ji.backup") | ||
if isfile(cache) | ||
mv(cache, backup; remove_destination=true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bit orthogonal to this PR but I figured fixing #175 is required for passing the test. Merging this fix should also resolve #109 and #169.
In .travis.yml
we have:
Lines 62 to 64 in 138d47d
- if [ "$CROSS_VERSION" = "1" ]; then | |
$PYTHON -m tox -e py,py27 -- -s; | |
fi |
Previously, use_separate_cache
was True
for both py
and py27
virtual environments. Thus, no global cache ~/.julia/lib/v0.6/PyCall.ji
existed while running the above test. However, with this patch, use_separate_cache
is False
in py
because the code I added sees that PYTHON
configured for PyCall
uses the same libpython
used by py
virtual environment prepared by tox
. So, after running tox -e py
, there is a file ~/.julia/lib/v0.6/PyCall.ji
. Now then running tox -e py27
hits the bug #175 because julia
0.6 does not recompile PyCall
when it finds ~/.julia/lib/v0.6/PyCall.ji
in Base.LOAD_CACHE_PATH[2]
.
julia/core.py
Outdated
return libpython_from_ldd_output(subprocess.check_output( | ||
["ldd", path], | ||
universal_newlines=True)) | ||
# TODO: somebody has to write it for in Windows and macOS: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: it only works in Linux at the moment
julia/core.py
Outdated
["ldd", path], | ||
universal_newlines=True)) | ||
return None | ||
# TODO: somebody has to write it for Windows and macOS: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: it only works in Linux at the moment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this at all? Oh, I see, to compare the path of libpython.
I merged #188 and rebased this PR onto master. There are test failures in macOS. But they are likely to be due to a bug in the latest pytest pytest-dev/pytest#3888 (Those failures are coming from doctests. Functions tested there are pure Python "pure" functions. So it doesn't make sense to have different results in different OSes.) @stevengj Can you have a look at it? Also please let me know if the idea of checking only the libpython path (my reasoning is in the issue description #190 (comment)) is the correct direction. |
It's annoying that finding The analogue of So, I think that we should fall back to searching the |
Pull Request Test Coverage Report for Build 448
💛 - Coveralls |
Pull Request Test Coverage Report for Build 467
💛 - Coveralls |
FWIW, there is a pure-Julia library which can do this: https://github.com/staticfloat/ObjectFile.jl (see |
@ihnorton Thanks. It looks like a good solution. Maybe PyCall.jl can use it in the build script and also expose it as a script tool. Then PyJulia can just call it. But I've already ported |
Actually, maybe we should just fetch |
# 32 julia latest Python-35 | ||
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe" | ||
# 32 julia-1.0 Python-35 | ||
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/1.0/julia-1.0-latest-win32.exe" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing with Julia nightly yields some bizarre failures (see below). The same code works with Julia 1.0. I suggest to test with stable release.
From Python 3.5:
ErrorException("ccall: could not find function PyString_AsStringAndSize in library C:\projects\pyjulia\.tox\py\Scripts\python35")
--- https://ci.appveyor.com/project/Keno/pyjulia/build/1.0.175/job/wwr318to7jr1b5h6#L433
From Python 2.7:
def test_call_julia_function_with_python_args(self): self.assertEqual(['A', 'B', 'C'], list(julia.map(julia.uppercase, > array.array('u', [u'a', u'b', u'c'])))) E RuntimeError: Julia exception: MethodError(uppercase, (PyObject u'a',), 0x000061ca)
--- https://ci.appveyor.com/project/Keno/pyjulia/build/1.0.175/job/wwr318to7jr1b5h6#L547
if is_same_path(jlinfo.pyprogramname, sys.executable): | ||
# In macOS and Windows, find_libpython does not work as good | ||
# as in Linux. We add this shortcut so that PyJulia can work | ||
# in those environments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I needed this shortcut to make it work since find_libpython.py
and PyCall/deps/build.jl
sometimes disagree:
For example, in macOS, PyCall/deps/build.jl
finds:
L957
jlinfo.libpython = /usr/local/opt/python/Frameworks/Python.framework/Versions/3.7/lib/libpython3.7m
but find_libpython.py
finds:
L958
py_libpython = /usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/Python
Another example in Windows: PyCall/deps/build.jl
cannot find a fullpath:
L517
jlinfo.libpython = python27
but find_libpython.py
"finds" it:
L518
py_libpython = C:\Windows\system32\python27.dl
(But it looks like the same path was found in win32 and win64. Ultimately, we need someone to write a function that uses dladdr
equivalent in Windows. It should be possible by just extending: https://stackoverflow.com/a/16659821)
I think it's better to use the same script to discover libpython in PyCall.jl and PyJulia. We can then avoid a hack like this. Since find_libpython.py
can call libdl.dladdr
(though it works only if libpython is dynamically linked), I think it's better approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the cases where they disagree, which is correct? Should deps/build.jl be fixed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have access to macOS so I'm not sure. But PyJulia printed
jlinfo.libpython = /usr/local/opt/python/Frameworks/Python.framework/Versions/3.7/lib/libpython3.7m
py_libpython = /usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/Python
jl_libpython = None
where jlinfo.libpython
is libpython
saved in deps/deps.jl
and jl_libpython
is the path I tried to resolved by
pyjulia/julia/find_libpython.py
Lines 176 to 182 in 6982ae8
if not os.path.isabs(path): | |
return None | |
if os.path.exists(path): | |
return os.path.realpath(path) | |
if os.path.exists(path + suffix): | |
return os.path.realpath(path + suffix) | |
return None |
So jl_libpython = None
means that libpython3.7m.dylib
did not exist (I set suffix = ".dylib"
in macOS). Maybe we should try libpython3.7m.so
in macOS too?
In the case of Windows, deps/build.jl
just gave up (jlinfo.libpython = python27
) whereas ctypes.util.find_library
finds C:\Windows\system32\python27.dl
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm trying it: 1d599be
os.name and sys.platform are more well-defined/documented and we don't need more detail than them.
Re: #190 (comment) So with some more manual handling in macOS cdbefb1 now
--- https://travis-ci.org/JuliaPy/pyjulia/jobs/422307471#L954 |
if is_apple: | ||
# sysconfig.get_config_var("SHLIB_SUFFIX") can be ".so" in macOS. | ||
# Let's not use the value from sysconfig. | ||
SHLIB_SUFFIX = ".dylib" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is the output of python -m sysconfig
from Python 3.7 in macOS https://travis-ci.org/JuliaPy/pyjulia/jobs/421924267#L1439
So to directly answer #190 (comment) That is to say, they both agree in Linux and macOS. In Windows and Python 2.7,
|
Sounds like deps/build.jl should be updated, then. |
Why don't we use |
(To be rebased after #188)
With this patch, we should be able to have multiple Python virtual environments without duplicating Julia's precompilation cache, provided that those Python executables are linked against same libpython.
Since PyCall.jl only cares about the identity of libpython when it is already initialized #182 (comment), i.e., it does not call
Py_SetPythonHome
etc., I think we only need to compare the path to libpython.@stevengj Is it correct? It seems that it works in my laptop.