From 0ffc3e5d88952dbcf115e5b7c58ba749bb5f2387 Mon Sep 17 00:00:00 2001 From: John Lapeyre Date: Mon, 10 Jan 2022 15:03:19 -0500 Subject: [PATCH 1/7] Use julia_project to manage Julia dependency pick dfc1426 Use julia_project to manage Julia dependency pick ae59cf3 Set env variables in tox.ini pick 52ec1cd Fix setting environment variables --- .gitignore | 3 ++ LICENSE.md | 2 +- MANIFEST.in | 3 ++ README.md | 6 +-- diffeqpy/Project.toml | 5 ++ diffeqpy/__init__.py | 38 +------------- diffeqpy/_julia_project.py | 38 ++++++++++++++ diffeqpy/_version.py | 2 + diffeqpy/install.jl | 8 --- diffeqpy/sys_image/Project.toml | 6 +++ diffeqpy/sys_image/compile_exercise_script.jl | 51 +++++++++++++++++++ diffeqpy/sys_image/compile_julia_project.jl | 11 ++++ setup.py | 11 +++- tox.ini | 2 +- 14 files changed, 134 insertions(+), 52 deletions(-) create mode 100644 diffeqpy/Project.toml create mode 100644 diffeqpy/_julia_project.py create mode 100644 diffeqpy/_version.py delete mode 100644 diffeqpy/install.jl create mode 100644 diffeqpy/sys_image/Project.toml create mode 100644 diffeqpy/sys_image/compile_exercise_script.jl create mode 100644 diffeqpy/sys_image/compile_julia_project.jl diff --git a/.gitignore b/.gitignore index a65d046..9f67c44 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,6 @@ docs/_build/ # PyBuilder target/ + +**/Manifest.toml +**/*.so diff --git a/LICENSE.md b/LICENSE.md index 3a49bdb..2d7170c 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,7 +1,7 @@ The MIT License (MIT) -Copyright (c) 2018: Chris Rackauckas. +Copyright (c) 2018, 2022: Chris Rackauckas. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MANIFEST.in b/MANIFEST.in index b719a4f..45ff4e6 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,7 @@ include README.md include LICENSE.md include docs/*.txt +include diffeqpy/sys_image/*.jl +include diffeqpy/sys_image/Project.toml +include diffeqpy/Project.toml include diffeqpy/*.jl diff --git a/README.md b/README.md index 02ce08c..ad0b01c 100644 --- a/README.md +++ b/README.md @@ -31,16 +31,14 @@ To install diffeqpy, use pip: pip install diffeqpy ``` -Using diffeqpy requires that Julia is installed and in the path, along -with DifferentialEquations.jl and PyCall.jl. To install Julia, -download a generic binary from +You can either install Julia yourself, or allow diffeqpy to do this for you. +To install Julia yourself, download a generic binary from [the JuliaLang site](https://julialang.org/downloads/) and add it to your path. To install Julia packages required for diffeqpy, open up Python interpreter then run: ```pycon >>> import diffeqpy ->>> diffeqpy.install() ``` and you're good! In addition, to improve the performance of your code it is diff --git a/diffeqpy/Project.toml b/diffeqpy/Project.toml new file mode 100644 index 0000000..7bbb6f3 --- /dev/null +++ b/diffeqpy/Project.toml @@ -0,0 +1,5 @@ +[deps] +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" +OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" +PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" diff --git a/diffeqpy/__init__.py b/diffeqpy/__init__.py index 511ae03..0abb23b 100644 --- a/diffeqpy/__init__.py +++ b/diffeqpy/__init__.py @@ -1,37 +1,3 @@ -import os -import shutil -import subprocess -import sys +from ._julia_project import julia, compile_diffeqpy, update_diffeqpy -from jill.install import install_julia - -script_dir = os.path.dirname(os.path.realpath(__file__)) - - -def _find_julia(): - # TODO: this should probably fallback to query jill - return shutil.which("julia") - - -def install(*, confirm=False): - """ - Install Julia (if required) and Julia packages required for diffeqpy. - """ - julia = _find_julia() - if not julia: - print("No Julia version found. Installing Julia.") - install_julia(confirm=confirm) - julia = _find_julia() - if not julia: - raise RuntimeError( - "Julia installed with jill but `julia` binary cannot be found in the path" - ) - env = os.environ.copy() - env["PYTHON"] = sys.executable - subprocess.check_call([julia, os.path.join(script_dir, "install.jl")], env=env) - - -def _ensure_installed(*kwargs): - if not _find_julia(): - # TODO: this should probably ensure that packages are installed too - install(*kwargs) +from ._version import __version__ diff --git a/diffeqpy/_julia_project.py b/diffeqpy/_julia_project.py new file mode 100644 index 0000000..4d496c9 --- /dev/null +++ b/diffeqpy/_julia_project.py @@ -0,0 +1,38 @@ +import julia +import logging + +from julia_project import JuliaProject + +import os +diffeqpy_path = os.path.dirname(os.path.abspath(__file__)) + +julia_project = JuliaProject( + name="diffeqpy", + package_path=diffeqpy_path, + preferred_julia_versions = ['1.7', '1.6', 'latest'], + env_prefix = 'DIFFEQPY_', + logging_level = logging.INFO, # or logging.WARN, + console_logging=False +) + +julia_project.run() + +# logger = julia_project.logger + +def compile_diffeqpy(): + """ + Compile a system image for `diffeqpy` in the subdirectory `./sys_image/`. This + system image will be loaded the next time you import `diffeqpy`. + """ + julia_project.compile_julia_project() + + +def update_diffeqpy(): + """ + Remove possible stale Manifest.toml files and compiled system image. + Update Julia packages and rebuild Manifest.toml file. + Before compiling, it's probably a good idea to call this method, then restart Python. + """ + julia_project.update() + + diff --git a/diffeqpy/_version.py b/diffeqpy/_version.py new file mode 100644 index 0000000..7124d09 --- /dev/null +++ b/diffeqpy/_version.py @@ -0,0 +1,2 @@ +"""Define version number here and read it from setup.py automatically""" +__version__ = "1.2.0" diff --git a/diffeqpy/install.jl b/diffeqpy/install.jl deleted file mode 100644 index 00dfa35..0000000 --- a/diffeqpy/install.jl +++ /dev/null @@ -1,8 +0,0 @@ -using Pkg -Pkg.add("DifferentialEquations") -Pkg.add("OrdinaryDiffEq") -Pkg.add("DiffEqBase") -Pkg.add("PyCall") -Pkg.build("PyCall") -using DifferentialEquations -using PyCall diff --git a/diffeqpy/sys_image/Project.toml b/diffeqpy/sys_image/Project.toml new file mode 100644 index 0000000..978f722 --- /dev/null +++ b/diffeqpy/sys_image/Project.toml @@ -0,0 +1,6 @@ +[deps] +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" +OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" +PackageCompiler = "9b87118b-4619-50d2-8e1e-99f35a4d4d9d" +PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" diff --git a/diffeqpy/sys_image/compile_exercise_script.jl b/diffeqpy/sys_image/compile_exercise_script.jl new file mode 100644 index 0000000..a9dd41f --- /dev/null +++ b/diffeqpy/sys_image/compile_exercise_script.jl @@ -0,0 +1,51 @@ +using DifferentialEquations +const DE = DifferentialEquations + +# This is curiously slow +function sde_exercise() + f = (u,p,t) -> 1.01*u + g = (u,p,t) -> 0.87*u + u0 = 0.5 + tspan = (0.0,1.0) + prob = DE.SDEProblem(f,g,u0,tspan) + sol = DE.solve(prob,reltol=1e-3,abstol=1e-3) + return nothing +end + +function ode_exercise() + f = (u,p,t) -> -u + u0 = 0.5 + tspan = (0., 1.) + prob = DE.ODEProblem(f, u0, tspan) + sol = DE.solve(prob) + return nothing +end + +function ode_exercise2() + f = function(u,p,t) + x, y, z = u + sigma, rho, beta = p + return [sigma * (y - x), x * (rho - z) - y, x * y - beta * z] + end + u0 = [1.0,0.0,0.0] + tspan = (0., 100.) + p = [10.0,28.0,8/3] + prob = DE.ODEProblem(f, u0, tspan, p) + sol = DE.solve(prob,saveat=0.01) + return nothing +end + +# From ODE docs +function ode_exercise3() + f(u,p,t) = 1.01*u + u0 = 1/2 + tspan = (0.0,1.0) + prob = ODEProblem(f,u0,tspan) + sol = solve(prob, Tsit5(), reltol=1e-8, abstol=1e-8) + return nothing +end + +ode_exercise() +ode_exercise2() +ode_exercise3() +sde_exercise() diff --git a/diffeqpy/sys_image/compile_julia_project.jl b/diffeqpy/sys_image/compile_julia_project.jl new file mode 100644 index 0000000..d743bc6 --- /dev/null +++ b/diffeqpy/sys_image/compile_julia_project.jl @@ -0,0 +1,11 @@ +using PackageCompiler +using Libdl: Libdl + +packages = [:PyCall, :DiffEqBase, :DifferentialEquations, :OrdinaryDiffEq] + +sysimage_path = joinpath(@__DIR__, "sys_julia_project." * Libdl.dlext) + +#create_sysimage(packages; sysimage_path=sysimage_path) + +create_sysimage(packages; sysimage_path=sysimage_path, + precompile_execution_file=joinpath(@__DIR__, "compile_exercise_script.jl")) diff --git a/setup.py b/setup.py index e72f068..58850e4 100644 --- a/setup.py +++ b/setup.py @@ -4,8 +4,14 @@ def readme(): with open('README.md') as f: return f.read() + +version = {} +with open("./diffeqpy/_version.py") as fp: + exec(fp.read(), version) + + setup(name='diffeqpy', - version='1.2.0', + version=version['__version__'], description='Solving Differential Equations in Python', long_description=readme(), long_description_content_type="text/markdown", @@ -24,6 +30,7 @@ def readme(): author_email='contact@juliadiffeq.org', license='MIT', packages=['diffeqpy','diffeqpy.tests'], - install_requires=['julia>=0.2', 'jill'], + install_requires=['julia>=0.2', + 'julia_project>=0.0.21'], include_package_data=True, zip_safe=False) diff --git a/tox.ini b/tox.ini index 525311a..bd6a0c8 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,7 @@ deps = pytest pytest-cov commands = - python -c 'import diffeqpy; diffeqpy.install()' + python -c 'import diffeqpy' py.test \ --pyargs diffeqpy \ {posargs} From a3322932f9dda7f4ff4428164b3e9cfdca3b56b7 Mon Sep 17 00:00:00 2001 From: John Lapeyre Date: Mon, 10 Jan 2022 15:42:56 -0500 Subject: [PATCH 2/7] Set env variables in tox.ini --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index bd6a0c8..c9dd854 100644 --- a/tox.ini +++ b/tox.ini @@ -12,6 +12,8 @@ whitelist_externals = setenv = # Do not use matplotlib GUI backend during tests. MPLBACKEND = agg + DIFFEQPY_COMPILE = n + DIFFEQ_DEPOT = y passenv = # Allow a workaround for "error initializing LibGit2 module": # https://github.com/JuliaLang/julia/issues/18693 From dc6cd528e0d9f853f18fea15cadf27f3c17daf0f Mon Sep 17 00:00:00 2001 From: John Lapeyre Date: Mon, 10 Jan 2022 16:12:09 -0500 Subject: [PATCH 3/7] Fix setting environment variables --- tox.ini | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index c9dd854..35b2b5b 100644 --- a/tox.ini +++ b/tox.ini @@ -12,8 +12,9 @@ whitelist_externals = setenv = # Do not use matplotlib GUI backend during tests. MPLBACKEND = agg - DIFFEQPY_COMPILE = n - DIFFEQ_DEPOT = y + DIFFEQPY_INSTALL_JULIA = y + DIFFEQPY_COMPILE = y + DIFFEQPY_DEPOT = y passenv = # Allow a workaround for "error initializing LibGit2 module": # https://github.com/JuliaLang/julia/issues/18693 From 97b2b4be2d16bd75cbeae03147647930ab2609e9 Mon Sep 17 00:00:00 2001 From: John Lapeyre Date: Mon, 10 Jan 2022 19:38:11 -0500 Subject: [PATCH 4/7] Get julia_project from pypi instead of github url From 67092f2e8f68c687ab372bb8523ab4676034fc59 Mon Sep 17 00:00:00 2001 From: John Lapeyre Date: Thu, 13 Jan 2022 19:59:05 -0500 Subject: [PATCH 5/7] Clean up something leftover from rebase attempt --- diffeqpy/de.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/diffeqpy/de.py b/diffeqpy/de.py index a0567ce..dc3d66b 100644 --- a/diffeqpy/de.py +++ b/diffeqpy/de.py @@ -1,12 +1,6 @@ import os import sys -from . import _ensure_installed - -# This is terrifying to many people. However, it seems SciML takes pragmatic approach. -_ensure_installed() - -# PyJulia have to be loaded after `_ensure_installed()` from julia import Main script_dir = os.path.dirname(os.path.realpath(__file__)) From 9e08135f952c25731f4ee49b1d385606945180cc Mon Sep 17 00:00:00 2001 From: John Lapeyre Date: Thu, 13 Jan 2022 20:42:12 -0500 Subject: [PATCH 6/7] Require latest version of julia_project to fix undefined variable bug Latest julia_project depends on latest find_julia which has a bug fix. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 58850e4..b9da46e 100644 --- a/setup.py +++ b/setup.py @@ -31,6 +31,6 @@ def readme(): license='MIT', packages=['diffeqpy','diffeqpy.tests'], install_requires=['julia>=0.2', - 'julia_project>=0.0.21'], + 'julia_project>=0.0.23'], include_package_data=True, zip_safe=False) From 7bd4d2e6152316991abf9f299ebb60273b7e0bd3 Mon Sep 17 00:00:00 2001 From: John Lapeyre Date: Thu, 13 Jan 2022 22:07:11 -0500 Subject: [PATCH 7/7] Require latest julia_project to fix bug There is another bug fix in find_julia --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b9da46e..24411b7 100644 --- a/setup.py +++ b/setup.py @@ -31,6 +31,6 @@ def readme(): license='MIT', packages=['diffeqpy','diffeqpy.tests'], install_requires=['julia>=0.2', - 'julia_project>=0.0.23'], + 'julia_project>=0.0.24'], include_package_data=True, zip_safe=False)