def is_dynamically_linked(executable): """ Check if Python `executable` is (likely to be) dynamically linked. It returns three possible values: * `True`: Likely that it's dynamically linked. * `False`: Likely that it's statically linked. * `None`: Unsupported platform. It's only "likely" since the check is by simple occurrence of a some substrings like "libpython". For example, if there is another library existing on the path containing "libpython", this function may return false-positive. """ path = which(executable) assert os.path.exists(path) if is_linux and which("ldd"): proc = run(["ldd", path], stdout=subprocess.PIPE, universal_newlines=True) print_completed_proc(proc) return "libpython" in proc.stdout elif is_apple and which("otool"): proc = run(["otool", "-L", path], stdout=subprocess.PIPE, universal_newlines=True) print_completed_proc(proc) return ("libpython" in proc.stdout or "/Python" in proc.stdout or "/.Python" in proc.stdout) # TODO: support Windows return None
def is_dynamically_linked(executable): """ Check if Python `executable` is (likely to be) dynamically linked. It returns three possible values: * `True`: Likely that it's dynamically linked. * `False`: Likely that it's statically linked. * `None`: Unsupported platform. It's only "likely" since the check is by simple occurrence of a some substrings like "libpython". For example, if there is another library existing on the path containing "libpython", this function may return false-positive. """ path = which(executable) assert os.path.exists(path) if is_linux and which("ldd"): proc = run(["ldd", path], stdout=subprocess.PIPE, universal_newlines=True) print_completed_proc(proc) return "libpython" in proc.stdout elif is_apple and which("otool"): proc = run( ["otool", "-L", path], stdout=subprocess.PIPE, universal_newlines=True ) print_completed_proc(proc) return ( "libpython" in proc.stdout or "/Python" in proc.stdout or "/.Python" in proc.stdout ) # TODO: support Windows return None
def test__using_default_setup(testdir, request): if request.config.getoption("runpytest") != "subprocess": raise ValueError("Need `-p pytester --runpytest=subprocess` options.") # create a temporary conftest.py file testdir.makeini(""" [pytest] addopts = -p julia.pytestplugin """) testdir.makepyfile(""" import pytest @pytest.mark.pyjulia__using_default_setup def test(): pass """) args = ("-p", "julia.pytestplugin", "--no-julia") r0 = testdir.runpytest(*args) r0.assert_outcomes(passed=1) r1 = testdir.runpytest("--julia-runtime", which("julia"), *args) r1.assert_outcomes(skipped=1) r2 = testdir.runpytest("--julia-inline=yes", *args) r2.assert_outcomes(skipped=1)
def test__using_default_setup(testdir, request): if request.config.getoption("runpytest") != "subprocess": raise ValueError("Need `-p pytester --runpytest=subprocess` options.") # create a temporary conftest.py file testdir.makeini( """ [pytest] addopts = -p julia.pytestplugin """ ) testdir.makepyfile( """ import pytest @pytest.mark.pyjulia__using_default_setup def test(): pass """ ) args = ("-p", "julia.pytestplugin", "--no-julia") r0 = testdir.runpytest(*args) r0.assert_outcomes(passed=1) r1 = testdir.runpytest("--julia-runtime", which("julia"), *args) r1.assert_outcomes(skipped=1) r2 = testdir.runpytest("--julia-inline=yes", *args) r2.assert_outcomes(skipped=1)
def test_incompatible_python(python, julia): python = which(python) proc = runcode( """ import os from julia import Julia Julia(runtime=os.getenv("PYJULIA_TEST_RUNTIME"), debug=True) """, python, ) assert proc.returncode == 1 assert "It seems your Julia and PyJulia setup are not supported." in proc.stderr dynamic = is_dynamically_linked(python) if dynamic is True: assert "`libpython` have to match" in proc.stderr elif dynamic is False: assert "is statically linked to libpython" in proc.stderr
def test_statically_linked(python): """ Simulate the case PyCall is configured with statically linked Python. In this case, `find_libpython()` would return the path identical to the one in PyCall's deps.jl. `is_compatible_exe` should reject it. """ python = which(python) runcode( python, """ from __future__ import print_function from julia.find_libpython import find_libpython from julia.core import is_compatible_exe, enable_debug enable_debug() assert not is_compatible_exe(find_libpython()) """, check=True, )
def test_statically_linked(python): """ Simulate the case PyCall is configured with statically linked Python. In this case, `find_libpython()` would return the path identical to the one in PyCall's deps.jl. `is_compatible_exe` should reject it. """ python = which(python) runcode( """ from __future__ import print_function from julia.core import enable_debug from julia.find_libpython import find_libpython from julia.juliainfo import is_compatible_exe enable_debug() assert not is_compatible_exe(find_libpython()) """, python, check=True, )
def test_incompatible_python(python, julia): if julia.eval("(VERSION.major, VERSION.minor)") == (0, 6): # Julia 0.6 implements mixed version return python = which(python) proc = runcode( python, """ import os from julia import Julia Julia(runtime=os.getenv("PYJULIA_TEST_RUNTIME"), debug=True) """, ) assert proc.returncode == 1 assert "It seems your Julia and PyJulia setup are not supported." in proc.stderr dynamic = is_dynamically_linked(python) if dynamic is True: assert "`libpython` have to match" in proc.stderr elif dynamic is False: assert "is statically linked to libpython" in proc.stderr
import os import shlex import subprocess from textwrap import dedent import pytest from julia.core import which from julia.python_jl import parse_pyjl_args PYJULIA_TEST_REBUILD = os.environ.get("PYJULIA_TEST_REBUILD", "no") == "yes" python_jl_required = pytest.mark.skipif( os.environ.get("PYJULIA_TEST_PYTHON_JL_IS_INSTALLED", "no") != "yes" and not which("python-jl"), reason="python-jl command not found", ) # fmt: off @pytest.mark.parametrize("args", [ "-h", "-i --help", "--julia false -h", "--julia false -i --help", ]) def test_help_option(args, capsys): with pytest.raises(SystemExit) as exc_info: parse_pyjl_args(shlex.split(args)) assert exc_info.value.code == 0
quick_pass_cli_args = [ "-h", "-i --help", "-V", "--version -c 1/0", ] @pytest.mark.parametrize("args", quick_pass_cli_args) def test_cli_quick_pass(args): subprocess.check_output(["python-jl"] + shlex.split(args), ) @pytest.mark.skipif(not which("false"), reason="false command not found") @pytest.mark.parametrize("args", quick_pass_cli_args) def test_cli_quick_pass_no_julia(args): subprocess.check_output(["python-jl", "--julia", "false"] + shlex.split(args), ) @pytest.mark.skipif(is_windows, reason="python-jl is not supported in Windows") @pytest.mark.skipif(not PYJULIA_TEST_REBUILD, reason="PYJULIA_TEST_REBUILD=yes is not set") def test_cli_import(): args = [ "-c", dedent(""" from julia import Base Base.banner()
depot = subprocess.check_output( [ runtime, "--startup-file=no", "-e", """ paths = [ARGS[1], DEPOT_PATH[2:end]...] print(join(paths, Sys.iswindows() ? ';' : ':')) """, str(tmpdir), ], universal_newlines=True, ).strip() jlinfo = JuliaInfo.load(runtime, env=dict(os.environ, JULIA_DEPOT_PATH=depot)) check_core_juliainfo(jlinfo) assert jlinfo.python is None assert jlinfo.libpython_path is None assert not jlinfo.is_pycall_built() assert not jlinfo.is_compatible_python() @pytest.mark.skipif(not which("false"), reason="false command not found") def test_juliainfo_failure(): with pytest.raises(subprocess.CalledProcessError) as excinfo: JuliaInfo.load(julia="false") assert excinfo.value.cmd[0] == "false" assert excinfo.value.returncode == 1 assert isinstance(excinfo.value.output, str)