Reputation: 182
While following various tutorials on compiling Rust libraries for further import from Python (I've tried both PyO3 and rust-cpython), I've been able to build a simple libary and successfully import it from my main.py
and interactive Python shells.
However, when trying to test and benchmark pure Python vs. my Rust library, I consistently get import errors:
_____________________________________________ ERROR collecting main.py _____________________________________________
ImportError while importing test module '/Users/xxx/pyo3/sumlib/main.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/Users/xxx/.pyenv/versions/3.8.2/lib/python3.8/importlib/__init__.py:127: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
main.py:1: in <module>
import sumlib
E ModuleNotFoundError: No module named 'sumlib'
Again, the library imports just fine from the main python file and the interactive shells like IPython
.
I'm on macOS Big Sur, Python 3.8 installed using pyenv
. Here is my Cargo.toml
:
[package]
name = "sumlib"
version = "0.1.0"
edition = "2018"
[lib]
name = "sumlib"
# "cdylib" is necessary to produce a shared library for Python to import from.
#
# Downstream Rust code (including code in `bin/`, `examples/`, and `tests/`) will not be able
# to `use string_sum;` unless the "rlib" or "lib" crate type is also included, e.g.:
# crate-type = ["cdylib", "rlib"]
crate-type = ["cdylib", "rlib"]
[dependencies.pyo3]
version = "0.14.2"
features = ["extension-module"]
Everything else is very trivial, from the PyO3
and rust-cpython
, to the same result.
Upvotes: 2
Views: 1985
Reputation: 917
tl/dr: Invoke your tests using python -m pytest
instead of pytest
.
It sounds like you haven't installed your Python extension module (eg, using pip install
) and are instead relying on it being inside your working directory. This would allow you to import it using an interpreter or main.py
launched via python -m
,
$ tree .
.
├── bin
│ ├── __init__.py
│ └── sumlib.py
└── examples
└── main.py
2 directories, 3 files
$ ipython --no-banner
In [1]: from bin import sumlib
In [2]: exit()
$ python -m examples.main
Successfully imported sumlib!
but not using pytest examples/main.py
or python examples/main.py
.
$ pytest examples/main.py
======================================================= test session starts =======================================================
platform darwin -- Python 3.8.3, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
rootdir: ...
plugins: typeguard-2.10.0
collected 0 items / 1 error
============================================================= ERRORS ==============================================================
________________________________________________ ERROR collecting examples/main.py ________________________________________________
ImportError while importing test module '.../examples/main.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
.../python3.8/importlib/__init__.py:127: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
examples/main.py:5: in <module>
from bin import sumlib
E ModuleNotFoundError: No module named 'bin'
...
$ python examples/main.py
Traceback (most recent call last):
File "examples/main.py", line 5, in <module>
from bin import sumlib
ModuleNotFoundError: No module named 'bin'
This is because ipython
and python -m
both add the current directory, which contains your extension module, to Python's sys.path
, but pytest examples/main.py
and python examples/main.py
don't. (See the pytest docs.) You can solve this by either installing your extension module or running your tests using python -m pytest
instead of pytest
.
Upvotes: 1