diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index ff1adb9..16a56de 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -63,6 +63,11 @@ jobs: - name: Install Matplotlib (Anaconda) if: startsWith(matrix.build, 'Anaconda') run: $CONDA/bin/conda install conda-forge::matplotlib + - run: python3 -c "import sys; print('\n'.join(sys.path))" + - run: python3 --version + - run: python3 -c "import matplotlib; print(matplotlib.__file__)" + - run: $($CONDA/bin/conda info --base)/bin/python3 -c "import matplotlib; print(matplotlib.__file__)" + - run: ls -R $($CONDA/bin/conda info --base) - 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..24c3817 --- /dev/null +++ b/build.rs @@ -0,0 +1,21 @@ +use std::{ + path::Path, + process::Command, +}; + +fn main() { + let matplotlib = "import matplotlib; print(matplotlib.__file__)"; + let plt_init = Command::new("python3").args(["-c", matplotlib]).output() + .map(|o| o.stdout) + .or_else(|_| { + Command::new("python").args(["-c", matplotlib]).output() + .map(|o| o.stdout) + }) + .expect("Pyhon or package matplotlib not found"); + let plt_path = String::from_utf8_lossy(&plt_init); + let plt_path = Path::new(plt_path.as_ref()); + if let Some(d) = plt_path.parent() { + let d = d.to_str().unwrap(); + println!("cargo:rustc-env=MATPLOTLIB_DIR={d}"); + } +} diff --git a/src/lib.rs b/src/lib.rs index 459ca1d..fde743d 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 { + println!("---------------------{:?}", option_env!("MATPLOTLIB_DIR")); + match PyModule::import(py, name.clone()) { + Ok(m) => Ok(m.into()), + Err(e) => { + if let Some(d) = option_env!("MATPLOTLIB_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! {