diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index ff1adb9..37533e8 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -62,7 +62,9 @@ jobs: run: pip install matplotlib - name: Install Matplotlib (Anaconda) if: startsWith(matrix.build, 'Anaconda') - run: $CONDA/bin/conda install conda-forge::matplotlib + run: | + $CONDA/bin/conda install conda-forge::matplotlib + $CONDA/bin/conda init - name: Install Rust (rustup) run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} shell: bash diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..2cfd14a --- /dev/null +++ b/build.rs @@ -0,0 +1,30 @@ +use std::{env, + fs::File, + io::Write, + path::Path, + process::Command, +}; + +fn main() -> Result<(), Box> { + let outdir = env::var("OUT_DIR") + .expect("The OUT_DIR variable must be defined during compilation"); + let py = Path::new(&outdir).join("matplotlib_location.py"); + let mut fh = File::create(&py)?; + writeln!(fh, "import matplotlib\nprint(matplotlib.__file__)")?; + drop(fh); + + let plt_path = Command::new("python3") + .arg(py) + .output() + .expect("`python3` or package `matplotlib` not found.") + .stdout; + let plt_path = String::from_utf8_lossy(&plt_path); + let plt_path = Path::new(plt_path.as_ref()); + if let Some(d) = plt_path.parent() { + let d = d.to_str().unwrap(); + eprintln!("----------------------------{d}---------------"); + println!("cargo:rustc-env=ANACONDA_DIR={d}"); + } + + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index 459ca1d..946bdc4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ use pyo3::{ prelude::*, intern, exceptions::{PyFileNotFoundError, PyPermissionError}, - types::{PyDict, PyList}, + types::{PyDict, PyList, PyString}, }; use numpy::{ PyArray1, @@ -102,10 +102,28 @@ If you use Anaconda, see https://github.com/PyO3/pyo3/issues/1554"), impl std::error::Error for Error {} +/// Import the module `name`. Try to update the Python search path if +/// it fails. +fn pyimport(py: Python<'_>, name: N) -> Result, PyErr> +where N: IntoPy> + Clone { + match PyModule::import(py, name.clone()) { + Ok(m) => Ok(m.into()), + Err(e) => { + eprintln!("---------------------{:?}", option_env!("ANACONDA_DIR")); + if let Some(d) = option_env!("ANACONDA_DIR") { + py.import("sys")?.getattr("path")? + .call_method1("append", (d,)).unwrap(); + PyModule::import(py, name).map(|m| m.into()) + } else { + Err(e) + } + } + } +} + /// Import and return a handle to the module `$m`. macro_rules! pyimport { ($m: literal) => { - Python::with_gil(|py| - PyModule::import(py, intern!(py, $m)).map(|m| m.into())) + Python::with_gil(|py| pyimport(py, intern!(py, $m))) }} lazy_static! {