From 555c7abfb10b02fd8bf1b059463d75c57769495e Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Fri, 2 Apr 2021 00:03:49 +0100 Subject: [PATCH] examples: maturin and setuptools_rust examples --- .github/workflows/ci.yml | 2 +- Cargo.toml | 6 ++- examples/maturin-starter/Cargo.toml | 27 ++++++++++ .../MANIFEST.in | 0 examples/maturin-starter/README.md | 24 +++++++++ .../maturin_starter/__init__.py | 7 +++ examples/maturin-starter/pyproject.toml | 3 ++ examples/maturin-starter/requirements-dev.txt | 1 + examples/maturin-starter/src/lib.rs | 35 ++++++++++++ examples/maturin-starter/src/submodule.rs | 22 ++++++++ .../tests/test_maturin_starter.py | 11 ++++ .../maturin-starter/tests/test_submodule.py | 6 +++ .../tox.ini | 4 +- .../Cargo.toml | 0 .../MANIFEST.in | 0 examples/pyo3-benchmarks/README.md | 18 +++++++ .../requirements-dev.txt | 2 - .../setup.py | 18 ------- .../src/lib.rs | 0 .../tests/test_benchmarks.py | 0 .../tox.ini | 0 examples/pyo3-pytests/Cargo.toml | 27 ++++++++++ examples/pyo3-pytests/MANIFEST.in | 2 + examples/pyo3-pytests/README.md | 19 +++++++ examples/pyo3-pytests/build.rs | 28 ++++++++++ .../requirements-dev.txt | 1 - .../src/buf_and_str.rs | 0 .../src/datetime.rs | 0 .../src/dict_iter.rs | 2 +- examples/pyo3-pytests/src/lib.rs | 49 +++++++++++++++++ .../src/misc.rs | 0 .../src/objstore.rs | 0 .../src/othermod.rs | 0 .../src/pyclass_iter.rs | 0 .../src/subclassing.rs | 0 .../tests/test_buf_and_str.py | 2 +- .../tests/test_datetime.py | 2 +- .../tests/test_dict_iter.py | 2 +- examples/pyo3-pytests/tests/test_misc.py | 6 +++ .../tests/test_objstore.py | 2 +- .../tests/test_othermod.py | 2 +- .../tests/test_pyclass_iter.py | 2 +- .../tests/test_subclassing.py | 2 +- examples/pyo3-pytests/tox.ini | 12 +++++ examples/pyo3_benchmarks/README.md | 17 ------ .../pyo3_benchmarks/__init__.py | 1 - examples/rustapi_module/Cargo.toml | 16 ------ examples/rustapi_module/README.md | 17 ------ examples/rustapi_module/pyproject.toml | 2 - .../rustapi_module/rustapi_module/__init__.py | 0 examples/rustapi_module/setup.py | 53 ------------------- examples/rustapi_module/src/lib.rs | 8 --- examples/rustapi_module/tests/test_misc.py | 6 --- examples/setuptools-rust-starter/Cargo.toml | 27 ++++++++++ examples/setuptools-rust-starter/MANIFEST.in | 2 + examples/setuptools-rust-starter/README.md | 24 +++++++++ .../requirements-dev.txt | 2 + examples/setuptools-rust-starter/setup.py | 26 +++++++++ .../setuptools_rust_starter/__init__.py | 7 +++ examples/setuptools-rust-starter/src/lib.rs | 35 ++++++++++++ .../setuptools-rust-starter/src/submodule.rs | 22 ++++++++ .../tests/test_setuptools_rust_starter.py | 11 ++++ .../tests/test_submodule.py | 6 +++ examples/setuptools-rust-starter/tox.ini | 12 +++++ src/class/iter.rs | 2 +- 65 files changed, 488 insertions(+), 154 deletions(-) create mode 100644 examples/maturin-starter/Cargo.toml rename examples/{pyo3_benchmarks => maturin-starter}/MANIFEST.in (100%) create mode 100644 examples/maturin-starter/README.md create mode 100644 examples/maturin-starter/maturin_starter/__init__.py create mode 100644 examples/maturin-starter/pyproject.toml create mode 100644 examples/maturin-starter/requirements-dev.txt create mode 100644 examples/maturin-starter/src/lib.rs create mode 100644 examples/maturin-starter/src/submodule.rs create mode 100644 examples/maturin-starter/tests/test_maturin_starter.py create mode 100644 examples/maturin-starter/tests/test_submodule.py rename examples/{rustapi_module => maturin-starter}/tox.ini (52%) rename examples/{pyo3_benchmarks => pyo3-benchmarks}/Cargo.toml (100%) rename examples/{rustapi_module => pyo3-benchmarks}/MANIFEST.in (100%) create mode 100644 examples/pyo3-benchmarks/README.md rename examples/{pyo3_benchmarks => pyo3-benchmarks}/requirements-dev.txt (70%) rename examples/{pyo3_benchmarks => pyo3-benchmarks}/setup.py (60%) rename examples/{pyo3_benchmarks => pyo3-benchmarks}/src/lib.rs (100%) rename examples/{pyo3_benchmarks => pyo3-benchmarks}/tests/test_benchmarks.py (100%) rename examples/{pyo3_benchmarks => pyo3-benchmarks}/tox.ini (100%) create mode 100644 examples/pyo3-pytests/Cargo.toml create mode 100644 examples/pyo3-pytests/MANIFEST.in create mode 100644 examples/pyo3-pytests/README.md create mode 100644 examples/pyo3-pytests/build.rs rename examples/{rustapi_module => pyo3-pytests}/requirements-dev.txt (68%) rename examples/{rustapi_module => pyo3-pytests}/src/buf_and_str.rs (100%) rename examples/{rustapi_module => pyo3-pytests}/src/datetime.rs (100%) rename examples/{rustapi_module => pyo3-pytests}/src/dict_iter.rs (93%) create mode 100644 examples/pyo3-pytests/src/lib.rs rename examples/{rustapi_module => pyo3-pytests}/src/misc.rs (100%) rename examples/{rustapi_module => pyo3-pytests}/src/objstore.rs (100%) rename examples/{rustapi_module => pyo3-pytests}/src/othermod.rs (100%) rename examples/{rustapi_module => pyo3-pytests}/src/pyclass_iter.rs (100%) rename examples/{rustapi_module => pyo3-pytests}/src/subclassing.rs (100%) rename examples/{rustapi_module => pyo3-pytests}/tests/test_buf_and_str.py (96%) rename examples/{rustapi_module => pyo3-pytests}/tests/test_datetime.py (99%) rename examples/{rustapi_module => pyo3-pytests}/tests/test_dict_iter.py (80%) create mode 100644 examples/pyo3-pytests/tests/test_misc.py rename examples/{rustapi_module => pyo3-pytests}/tests/test_objstore.py (91%) rename examples/{rustapi_module => pyo3-pytests}/tests/test_othermod.py (95%) rename examples/{rustapi_module => pyo3-pytests}/tests/test_pyclass_iter.py (88%) rename examples/{rustapi_module => pyo3-pytests}/tests/test_subclassing.py (85%) create mode 100644 examples/pyo3-pytests/tox.ini delete mode 100644 examples/pyo3_benchmarks/README.md delete mode 100644 examples/pyo3_benchmarks/pyo3_benchmarks/__init__.py delete mode 100644 examples/rustapi_module/Cargo.toml delete mode 100644 examples/rustapi_module/README.md delete mode 100644 examples/rustapi_module/pyproject.toml delete mode 100644 examples/rustapi_module/rustapi_module/__init__.py delete mode 100644 examples/rustapi_module/setup.py delete mode 100644 examples/rustapi_module/src/lib.rs delete mode 100644 examples/rustapi_module/tests/test_misc.py create mode 100644 examples/setuptools-rust-starter/Cargo.toml create mode 100644 examples/setuptools-rust-starter/MANIFEST.in create mode 100644 examples/setuptools-rust-starter/README.md create mode 100644 examples/setuptools-rust-starter/requirements-dev.txt create mode 100644 examples/setuptools-rust-starter/setup.py create mode 100644 examples/setuptools-rust-starter/setuptools_rust_starter/__init__.py create mode 100644 examples/setuptools-rust-starter/src/lib.rs create mode 100644 examples/setuptools-rust-starter/src/submodule.rs create mode 100644 examples/setuptools-rust-starter/tests/test_setuptools_rust_starter.py create mode 100644 examples/setuptools-rust-starter/tests/test_submodule.py create mode 100644 examples/setuptools-rust-starter/tox.ini diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 393a490289c..32201ea71c5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 - - run: pip install black==19.10b0 + - run: pip install black==20.8b1 - uses: actions-rs/toolchain@v1 with: toolchain: stable diff --git a/Cargo.toml b/Cargo.toml index fc3b811bf83..e48f49d1ad6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,7 +73,9 @@ nightly = [] members = [ "pyo3-macros", "pyo3-macros-backend", - "examples/pyo3_benchmarks", - "examples/rustapi_module", + "examples/pyo3-benchmarks", + "examples/pyo3-pytests", + "examples/maturin-starter", + "examples/setuptools-rust-starter", "examples/word-count" ] diff --git a/examples/maturin-starter/Cargo.toml b/examples/maturin-starter/Cargo.toml new file mode 100644 index 00000000000..5140ce043a9 --- /dev/null +++ b/examples/maturin-starter/Cargo.toml @@ -0,0 +1,27 @@ +[package] +authors = ["PyO3 Authors"] +name = "maturin-starter" +version = "0.1.0" +description = "An example project to get started using PyO3 with maturin" +edition = "2018" + +[dependencies] + +[dependencies.pyo3] +path = "../../" +features = ["extension-module"] + +[lib] +name = "maturin_starter" +crate-type = ["cdylib"] + +[package.metadata.maturin] +classifier=[ + "License :: OSI Approved :: MIT License", + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Programming Language :: Python", + "Programming Language :: Rust", + "Operating System :: POSIX", + "Operating System :: MacOS :: MacOS X", +] diff --git a/examples/pyo3_benchmarks/MANIFEST.in b/examples/maturin-starter/MANIFEST.in similarity index 100% rename from examples/pyo3_benchmarks/MANIFEST.in rename to examples/maturin-starter/MANIFEST.in diff --git a/examples/maturin-starter/README.md b/examples/maturin-starter/README.md new file mode 100644 index 00000000000..6eb908e3d39 --- /dev/null +++ b/examples/maturin-starter/README.md @@ -0,0 +1,24 @@ +# maturin-starter + +An example of a basic Python extension module built using PyO3 and `maturin`. + +## Building and Testing + +To build this package, first install `maturin`: + +```shell +pip install maturin +``` + +To build and test use `maturin develop`: + +```shell +pip install -r requirements-dev.txt +maturin develop && pytest +``` + +Alternatively, install tox and run the tests inside an isolated environment: + +```shell +tox -e py +``` diff --git a/examples/maturin-starter/maturin_starter/__init__.py b/examples/maturin-starter/maturin_starter/__init__.py new file mode 100644 index 00000000000..44ed5e113fb --- /dev/null +++ b/examples/maturin-starter/maturin_starter/__init__.py @@ -0,0 +1,7 @@ +# import the contents of the Rust library into the Python extension +from .maturin_starter import * + + +class PythonClass: + def __init__(self, value: int) -> None: + self.value = value diff --git a/examples/maturin-starter/pyproject.toml b/examples/maturin-starter/pyproject.toml new file mode 100644 index 00000000000..90cb176e804 --- /dev/null +++ b/examples/maturin-starter/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["maturin"] +build-backend = "maturin" diff --git a/examples/maturin-starter/requirements-dev.txt b/examples/maturin-starter/requirements-dev.txt new file mode 100644 index 00000000000..a1fa3684923 --- /dev/null +++ b/examples/maturin-starter/requirements-dev.txt @@ -0,0 +1 @@ +pytest>=3.5.0 diff --git a/examples/maturin-starter/src/lib.rs b/examples/maturin-starter/src/lib.rs new file mode 100644 index 00000000000..164a9b8a76f --- /dev/null +++ b/examples/maturin-starter/src/lib.rs @@ -0,0 +1,35 @@ +use pyo3::prelude::*; +use pyo3::types::PyDict; +use pyo3::wrap_pymodule; + +mod submodule; +use submodule::*; + +#[pyclass] +struct ExampleClass { + #[pyo3(get, set)] + value: i32, +} + +#[pymethods] +impl ExampleClass { + #[new] + pub fn new(value: i32) -> Self { + ExampleClass { value } + } +} + +#[pymodule] +fn maturin_starter(py: Python, m: &PyModule) -> PyResult<()> { + m.add_class::()?; + m.add_wrapped(wrap_pymodule!(submodule))?; + + // Inserting to sys.modules allows importing submodules nicely from Python + // e.g. from maturin_starter.submodule import SubmoduleClass + + let sys = PyModule::import(py, "sys")?; + let sys_modules: &PyDict = sys.getattr("modules")?.downcast()?; + sys_modules.set_item("maturin_starter.submodule", m.getattr("submodule")?)?; + + Ok(()) +} diff --git a/examples/maturin-starter/src/submodule.rs b/examples/maturin-starter/src/submodule.rs new file mode 100644 index 00000000000..8096e337755 --- /dev/null +++ b/examples/maturin-starter/src/submodule.rs @@ -0,0 +1,22 @@ +use pyo3::prelude::*; + +#[pyclass] +struct SubmoduleClass {} + +#[pymethods] +impl SubmoduleClass { + #[new] + pub fn __new__() -> Self { + SubmoduleClass {} + } + + pub fn greeting(&self) -> &'static str { + "Hello, world!" + } +} + +#[pymodule] +pub fn submodule(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_class::()?; + Ok(()) +} diff --git a/examples/maturin-starter/tests/test_maturin_starter.py b/examples/maturin-starter/tests/test_maturin_starter.py new file mode 100644 index 00000000000..961d2d54f32 --- /dev/null +++ b/examples/maturin-starter/tests/test_maturin_starter.py @@ -0,0 +1,11 @@ +from maturin_starter import PythonClass, ExampleClass + + +def test_python_class() -> None: + py_class = PythonClass(value=10) + assert py_class.value == 10 + + +def test_example_class() -> None: + example = ExampleClass(value=11) + assert example.value == 11 diff --git a/examples/maturin-starter/tests/test_submodule.py b/examples/maturin-starter/tests/test_submodule.py new file mode 100644 index 00000000000..5cf2f57c2cb --- /dev/null +++ b/examples/maturin-starter/tests/test_submodule.py @@ -0,0 +1,6 @@ +from maturin_starter.submodule import SubmoduleClass + + +def test_submodule_class() -> None: + submodule_class = SubmoduleClass() + assert submodule_class.greeting() == "Hello, world!" diff --git a/examples/rustapi_module/tox.ini b/examples/maturin-starter/tox.ini similarity index 52% rename from examples/rustapi_module/tox.ini rename to examples/maturin-starter/tox.ini index e0d45bbc7e4..d28e126d1d9 100644 --- a/examples/rustapi_module/tox.ini +++ b/examples/maturin-starter/tox.ini @@ -6,5 +6,7 @@ skipsdist = true description = Run the unit tests under {basepython} deps = -rrequirements-dev.txt commands = - python setup.py install + # Use pip master with in-tree-build feature (to be released in pip 21.0) + python -m pip install --upgrade git+https://github.com/pypa/pip.git + python -m pip install . --use-feature=in-tree-build pytest {posargs} diff --git a/examples/pyo3_benchmarks/Cargo.toml b/examples/pyo3-benchmarks/Cargo.toml similarity index 100% rename from examples/pyo3_benchmarks/Cargo.toml rename to examples/pyo3-benchmarks/Cargo.toml diff --git a/examples/rustapi_module/MANIFEST.in b/examples/pyo3-benchmarks/MANIFEST.in similarity index 100% rename from examples/rustapi_module/MANIFEST.in rename to examples/pyo3-benchmarks/MANIFEST.in diff --git a/examples/pyo3-benchmarks/README.md b/examples/pyo3-benchmarks/README.md new file mode 100644 index 00000000000..9bbc30407d8 --- /dev/null +++ b/examples/pyo3-benchmarks/README.md @@ -0,0 +1,18 @@ +# pyo3-benchmarks + +This extension module contains benchmarks for pieces of PyO3's API accessible from Python. + +## Running the benchmarks + +You can install the module in your Python environment and then run the benchmarks with pytest: + +```shell +python setup.py develop +pytest +``` + +Or with tox: + +```shell +tox -e py +``` diff --git a/examples/pyo3_benchmarks/requirements-dev.txt b/examples/pyo3-benchmarks/requirements-dev.txt similarity index 70% rename from examples/pyo3_benchmarks/requirements-dev.txt rename to examples/pyo3-benchmarks/requirements-dev.txt index 4dc9c74727f..6fb42762198 100644 --- a/examples/pyo3_benchmarks/requirements-dev.txt +++ b/examples/pyo3-benchmarks/requirements-dev.txt @@ -1,6 +1,4 @@ pip>=19.1 -hypothesis>=3.55 pytest>=3.5.0 setuptools-rust>=0.10.2 -psutil>=5.6 pytest-benchmark~=3.2 diff --git a/examples/pyo3_benchmarks/setup.py b/examples/pyo3-benchmarks/setup.py similarity index 60% rename from examples/pyo3_benchmarks/setup.py rename to examples/pyo3-benchmarks/setup.py index 0208e36974b..b16f1ed5170 100644 --- a/examples/pyo3_benchmarks/setup.py +++ b/examples/pyo3-benchmarks/setup.py @@ -1,24 +1,7 @@ -import sys -import platform - from setuptools import setup from setuptools_rust import RustExtension -def get_py_version_cfgs(): - # For now each Cfg Py_3_X flag is interpreted as "at least 3.X" - version = sys.version_info[0:2] - py3_min = 6 - out_cfg = [] - for minor in range(py3_min, version[1] + 1): - out_cfg.append("--cfg=Py_3_%d" % minor) - - if platform.python_implementation() == "PyPy": - out_cfg.append("--cfg=PyPy") - - return out_cfg - - setup( name="pyo3-benchmarks", version="0.1.0", @@ -35,7 +18,6 @@ def get_py_version_cfgs(): rust_extensions=[ RustExtension( "pyo3_benchmarks._pyo3_benchmarks", - rustc_flags=get_py_version_cfgs(), debug=False, ), ], diff --git a/examples/pyo3_benchmarks/src/lib.rs b/examples/pyo3-benchmarks/src/lib.rs similarity index 100% rename from examples/pyo3_benchmarks/src/lib.rs rename to examples/pyo3-benchmarks/src/lib.rs diff --git a/examples/pyo3_benchmarks/tests/test_benchmarks.py b/examples/pyo3-benchmarks/tests/test_benchmarks.py similarity index 100% rename from examples/pyo3_benchmarks/tests/test_benchmarks.py rename to examples/pyo3-benchmarks/tests/test_benchmarks.py diff --git a/examples/pyo3_benchmarks/tox.ini b/examples/pyo3-benchmarks/tox.ini similarity index 100% rename from examples/pyo3_benchmarks/tox.ini rename to examples/pyo3-benchmarks/tox.ini diff --git a/examples/pyo3-pytests/Cargo.toml b/examples/pyo3-pytests/Cargo.toml new file mode 100644 index 00000000000..41334f2c03a --- /dev/null +++ b/examples/pyo3-pytests/Cargo.toml @@ -0,0 +1,27 @@ +[package] +authors = ["PyO3 Authors"] +name = "pyo3-pytests" +version = "0.1.0" +description = "Python-based tests for PyO3" +edition = "2018" + +[dependencies] + +[dependencies.pyo3] +path = "../../" +features = ["extension-module"] + +[lib] +name = "pyo3_pytests" +crate-type = ["cdylib"] + +[package.metadata.maturin] +classifier=[ + "License :: OSI Approved :: MIT License", + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Programming Language :: Python", + "Programming Language :: Rust", + "Operating System :: POSIX", + "Operating System :: MacOS :: MacOS X", +] diff --git a/examples/pyo3-pytests/MANIFEST.in b/examples/pyo3-pytests/MANIFEST.in new file mode 100644 index 00000000000..becccf7bc9a --- /dev/null +++ b/examples/pyo3-pytests/MANIFEST.in @@ -0,0 +1,2 @@ +include pyproject.toml Cargo.toml +recursive-include src * diff --git a/examples/pyo3-pytests/README.md b/examples/pyo3-pytests/README.md new file mode 100644 index 00000000000..89268d249a5 --- /dev/null +++ b/examples/pyo3-pytests/README.md @@ -0,0 +1,19 @@ +# pyo3-pytests + +An extension module built using PyO3, used to test PyO3 from Python. + +## Testing + +This package is intended to be built using `maturin`. Once built, you can run the tests using `pytest`: + +```shell +pip install maturin +maturin develop +pytest +``` + +Alternatively, install tox and run the tests inside an isolated environment: + +```shell +tox -e py +``` diff --git a/examples/pyo3-pytests/build.rs b/examples/pyo3-pytests/build.rs new file mode 100644 index 00000000000..edd8b0ceb53 --- /dev/null +++ b/examples/pyo3-pytests/build.rs @@ -0,0 +1,28 @@ +use std::process::Command; + +fn main() { + let out = Command::new("python") + .args(&["-c", "import sys; import platform; print(sys.version_info[1]); print(platform.python_implementation())"]) + .output() + .expect("python version did not print"); + + let output = String::from_utf8_lossy(&out.stdout); + let mut lines = output.trim().lines(); + + println!("{}", output); + + let version: u8 = lines + .next() + .unwrap() + .parse() + .expect("python version was not parsed"); + let implementation = lines.next().unwrap(); + + for each in 6..version { + println!("cargo:rustc-cfg=Py_3_{}", each); + } + + if implementation == "PyPy" { + println!("cargo:rustc-cfg=PyPy"); + } +} diff --git a/examples/rustapi_module/requirements-dev.txt b/examples/pyo3-pytests/requirements-dev.txt similarity index 68% rename from examples/rustapi_module/requirements-dev.txt rename to examples/pyo3-pytests/requirements-dev.txt index b3b34d9d8b5..e540aff8297 100644 --- a/examples/rustapi_module/requirements-dev.txt +++ b/examples/pyo3-pytests/requirements-dev.txt @@ -1,5 +1,4 @@ pip>=19.1 hypothesis>=3.55 pytest>=3.5.0 -setuptools-rust>=0.10.2 psutil>=5.6 diff --git a/examples/rustapi_module/src/buf_and_str.rs b/examples/pyo3-pytests/src/buf_and_str.rs similarity index 100% rename from examples/rustapi_module/src/buf_and_str.rs rename to examples/pyo3-pytests/src/buf_and_str.rs diff --git a/examples/rustapi_module/src/datetime.rs b/examples/pyo3-pytests/src/datetime.rs similarity index 100% rename from examples/rustapi_module/src/datetime.rs rename to examples/pyo3-pytests/src/datetime.rs diff --git a/examples/rustapi_module/src/dict_iter.rs b/examples/pyo3-pytests/src/dict_iter.rs similarity index 93% rename from examples/rustapi_module/src/dict_iter.rs rename to examples/pyo3-pytests/src/dict_iter.rs index daca9676a48..e030f688ca0 100644 --- a/examples/rustapi_module/src/dict_iter.rs +++ b/examples/pyo3-pytests/src/dict_iter.rs @@ -3,7 +3,7 @@ use pyo3::prelude::*; use pyo3::types::PyDict; #[pymodule] -fn test_dict(_py: Python<'_>, m: &PyModule) -> PyResult<()> { +fn dict_iter(_py: Python<'_>, m: &PyModule) -> PyResult<()> { m.add_class::()?; Ok(()) } diff --git a/examples/pyo3-pytests/src/lib.rs b/examples/pyo3-pytests/src/lib.rs new file mode 100644 index 00000000000..0dea9c03679 --- /dev/null +++ b/examples/pyo3-pytests/src/lib.rs @@ -0,0 +1,49 @@ +use pyo3::prelude::*; +use pyo3::types::PyDict; +use pyo3::wrap_pymodule; + +pub mod buf_and_str; +pub mod datetime; +pub mod dict_iter; +pub mod misc; +pub mod objstore; +pub mod othermod; +pub mod pyclass_iter; +pub mod subclassing; + +use buf_and_str::*; +use datetime::*; +use dict_iter::*; +use misc::*; +use objstore::*; +use othermod::*; +use pyclass_iter::*; +use subclassing::*; + +#[pymodule] +fn pyo3_pytests(py: Python, m: &PyModule) -> PyResult<()> { + m.add_wrapped(wrap_pymodule!(buf_and_str))?; + m.add_wrapped(wrap_pymodule!(datetime))?; + m.add_wrapped(wrap_pymodule!(dict_iter))?; + m.add_wrapped(wrap_pymodule!(misc))?; + m.add_wrapped(wrap_pymodule!(objstore))?; + m.add_wrapped(wrap_pymodule!(othermod))?; + m.add_wrapped(wrap_pymodule!(pyclass_iter))?; + m.add_wrapped(wrap_pymodule!(subclassing))?; + + // Inserting to sys.modules allows importing submodules nicely from Python + // e.g. import pyo3_pytests.buf_and_str as bas + + let sys = PyModule::import(py, "sys")?; + let sys_modules: &PyDict = sys.getattr("modules")?.downcast()?; + sys_modules.set_item("pyo3_pytests.buf_and_str", m.getattr("buf_and_str")?)?; + sys_modules.set_item("pyo3_pytests.datetime", m.getattr("datetime")?)?; + sys_modules.set_item("pyo3_pytests.dict_iter", m.getattr("dict_iter")?)?; + sys_modules.set_item("pyo3_pytests.misc", m.getattr("misc")?)?; + sys_modules.set_item("pyo3_pytests.objstore", m.getattr("objstore")?)?; + sys_modules.set_item("pyo3_pytests.othermod", m.getattr("othermod")?)?; + sys_modules.set_item("pyo3_pytests.pyclass_iter", m.getattr("pyclass_iter")?)?; + sys_modules.set_item("pyo3_pytests.subclassing", m.getattr("subclassing")?)?; + + Ok(()) +} diff --git a/examples/rustapi_module/src/misc.rs b/examples/pyo3-pytests/src/misc.rs similarity index 100% rename from examples/rustapi_module/src/misc.rs rename to examples/pyo3-pytests/src/misc.rs diff --git a/examples/rustapi_module/src/objstore.rs b/examples/pyo3-pytests/src/objstore.rs similarity index 100% rename from examples/rustapi_module/src/objstore.rs rename to examples/pyo3-pytests/src/objstore.rs diff --git a/examples/rustapi_module/src/othermod.rs b/examples/pyo3-pytests/src/othermod.rs similarity index 100% rename from examples/rustapi_module/src/othermod.rs rename to examples/pyo3-pytests/src/othermod.rs diff --git a/examples/rustapi_module/src/pyclass_iter.rs b/examples/pyo3-pytests/src/pyclass_iter.rs similarity index 100% rename from examples/rustapi_module/src/pyclass_iter.rs rename to examples/pyo3-pytests/src/pyclass_iter.rs diff --git a/examples/rustapi_module/src/subclassing.rs b/examples/pyo3-pytests/src/subclassing.rs similarity index 100% rename from examples/rustapi_module/src/subclassing.rs rename to examples/pyo3-pytests/src/subclassing.rs diff --git a/examples/rustapi_module/tests/test_buf_and_str.py b/examples/pyo3-pytests/tests/test_buf_and_str.py similarity index 96% rename from examples/rustapi_module/tests/test_buf_and_str.py rename to examples/pyo3-pytests/tests/test_buf_and_str.py index 1ebd85d68ed..166e6ad068c 100644 --- a/examples/rustapi_module/tests/test_buf_and_str.py +++ b/examples/pyo3-pytests/tests/test_buf_and_str.py @@ -4,7 +4,7 @@ import psutil import pytest -from rustapi_module.buf_and_str import BytesExtractor +from pyo3_pytests.buf_and_str import BytesExtractor PYPY = platform.python_implementation() == "PyPy" diff --git a/examples/rustapi_module/tests/test_datetime.py b/examples/pyo3-pytests/tests/test_datetime.py similarity index 99% rename from examples/rustapi_module/tests/test_datetime.py rename to examples/pyo3-pytests/tests/test_datetime.py index 87e03ac8ca8..c8659835488 100644 --- a/examples/rustapi_module/tests/test_datetime.py +++ b/examples/pyo3-pytests/tests/test_datetime.py @@ -5,7 +5,7 @@ import sys import pytest -import rustapi_module.datetime as rdt +import pyo3_pytests.datetime as rdt from hypothesis import given, example from hypothesis import strategies as st diff --git a/examples/rustapi_module/tests/test_dict_iter.py b/examples/pyo3-pytests/tests/test_dict_iter.py similarity index 80% rename from examples/rustapi_module/tests/test_dict_iter.py rename to examples/pyo3-pytests/tests/test_dict_iter.py index 21c97883cbb..3704a65b447 100644 --- a/examples/rustapi_module/tests/test_dict_iter.py +++ b/examples/pyo3-pytests/tests/test_dict_iter.py @@ -1,5 +1,5 @@ import pytest -from rustapi_module.test_dict import DictSize +from pyo3_pytests.dict_iter import DictSize @pytest.mark.parametrize("size", [64, 128, 256]) diff --git a/examples/pyo3-pytests/tests/test_misc.py b/examples/pyo3-pytests/tests/test_misc.py new file mode 100644 index 00000000000..406c55ee5be --- /dev/null +++ b/examples/pyo3-pytests/tests/test_misc.py @@ -0,0 +1,6 @@ +import pyo3_pytests.misc + + +def test_issue_219(): + # Should not deadlock + pyo3_pytests.misc.issue_219() diff --git a/examples/rustapi_module/tests/test_objstore.py b/examples/pyo3-pytests/tests/test_objstore.py similarity index 91% rename from examples/rustapi_module/tests/test_objstore.py rename to examples/pyo3-pytests/tests/test_objstore.py index e95457e1cdc..99713948ad3 100644 --- a/examples/rustapi_module/tests/test_objstore.py +++ b/examples/pyo3-pytests/tests/test_objstore.py @@ -4,7 +4,7 @@ import pytest -from rustapi_module.objstore import ObjStore +from pyo3_pytests.objstore import ObjStore PYPY = platform.python_implementation() == "PyPy" diff --git a/examples/rustapi_module/tests/test_othermod.py b/examples/pyo3-pytests/tests/test_othermod.py similarity index 95% rename from examples/rustapi_module/tests/test_othermod.py rename to examples/pyo3-pytests/tests/test_othermod.py index f47c64b737a..08ac367a4e9 100644 --- a/examples/rustapi_module/tests/test_othermod.py +++ b/examples/pyo3-pytests/tests/test_othermod.py @@ -1,7 +1,7 @@ from hypothesis import given, assume from hypothesis import strategies as st -from rustapi_module import othermod +from pyo3_pytests import othermod INTEGER32_ST = st.integers(min_value=(-(2 ** 31)), max_value=(2 ** 31 - 1)) USIZE_ST = st.integers(min_value=othermod.USIZE_MIN, max_value=othermod.USIZE_MAX) diff --git a/examples/rustapi_module/tests/test_pyclass_iter.py b/examples/pyo3-pytests/tests/test_pyclass_iter.py similarity index 88% rename from examples/rustapi_module/tests/test_pyclass_iter.py rename to examples/pyo3-pytests/tests/test_pyclass_iter.py index f69eab361fb..e7d7d47c222 100644 --- a/examples/rustapi_module/tests/test_pyclass_iter.py +++ b/examples/pyo3-pytests/tests/test_pyclass_iter.py @@ -1,5 +1,5 @@ import pytest -from rustapi_module import pyclass_iter +from pyo3_pytests import pyclass_iter def test_iter(): diff --git a/examples/rustapi_module/tests/test_subclassing.py b/examples/pyo3-pytests/tests/test_subclassing.py similarity index 85% rename from examples/rustapi_module/tests/test_subclassing.py rename to examples/pyo3-pytests/tests/test_subclassing.py index 1f8ce06404e..e1c0b88feae 100644 --- a/examples/rustapi_module/tests/test_subclassing.py +++ b/examples/pyo3-pytests/tests/test_subclassing.py @@ -1,6 +1,6 @@ import platform -from rustapi_module.subclassing import Subclassable +from pyo3_pytests.subclassing import Subclassable PYPY = platform.python_implementation() == "PyPy" diff --git a/examples/pyo3-pytests/tox.ini b/examples/pyo3-pytests/tox.ini new file mode 100644 index 00000000000..d28e126d1d9 --- /dev/null +++ b/examples/pyo3-pytests/tox.ini @@ -0,0 +1,12 @@ +[tox] +# can't install from sdist because local pyo3 repo can't be included in the sdist +skipsdist = true + +[testenv] +description = Run the unit tests under {basepython} +deps = -rrequirements-dev.txt +commands = + # Use pip master with in-tree-build feature (to be released in pip 21.0) + python -m pip install --upgrade git+https://github.com/pypa/pip.git + python -m pip install . --use-feature=in-tree-build + pytest {posargs} diff --git a/examples/pyo3_benchmarks/README.md b/examples/pyo3_benchmarks/README.md deleted file mode 100644 index bf8867f5a04..00000000000 --- a/examples/pyo3_benchmarks/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# rustapi_module - -A simple extension module built using PyO3. - -## Build - -```shell -python setup.py install -``` - -## Testing - -To test install tox globally and run - -```shell -tox -e py -``` diff --git a/examples/pyo3_benchmarks/pyo3_benchmarks/__init__.py b/examples/pyo3_benchmarks/pyo3_benchmarks/__init__.py deleted file mode 100644 index cd0f9b65981..00000000000 --- a/examples/pyo3_benchmarks/pyo3_benchmarks/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from ._pyo3_benchmarks import * diff --git a/examples/rustapi_module/Cargo.toml b/examples/rustapi_module/Cargo.toml deleted file mode 100644 index 98e728ee8c0..00000000000 --- a/examples/rustapi_module/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -authors = ["PyO3 Authors"] -name = "rustapi-module" -version = "0.1.0" -description = "A Python wrapper for the Rust API for purposes of testing" -edition = "2018" - -[dependencies] - -[dependencies.pyo3] -path = "../../" -features = ["extension-module"] - -[lib] -name = "rustapi_module" -crate-type = ["cdylib"] diff --git a/examples/rustapi_module/README.md b/examples/rustapi_module/README.md deleted file mode 100644 index bf8867f5a04..00000000000 --- a/examples/rustapi_module/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# rustapi_module - -A simple extension module built using PyO3. - -## Build - -```shell -python setup.py install -``` - -## Testing - -To test install tox globally and run - -```shell -tox -e py -``` diff --git a/examples/rustapi_module/pyproject.toml b/examples/rustapi_module/pyproject.toml deleted file mode 100644 index 650da5faeeb..00000000000 --- a/examples/rustapi_module/pyproject.toml +++ /dev/null @@ -1,2 +0,0 @@ -[build-system] -requires = ["setuptools>=41.0.0", "wheel", "setuptools_rust>=0.10.2"] diff --git a/examples/rustapi_module/rustapi_module/__init__.py b/examples/rustapi_module/rustapi_module/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/examples/rustapi_module/setup.py b/examples/rustapi_module/setup.py deleted file mode 100644 index 50fb20175e1..00000000000 --- a/examples/rustapi_module/setup.py +++ /dev/null @@ -1,53 +0,0 @@ -import sys -import platform - -from setuptools import setup -from setuptools_rust import RustExtension - - -def get_py_version_cfgs(): - # For now each Cfg Py_3_X flag is interpreted as "at least 3.X" - version = sys.version_info[0:2] - py3_min = 6 - out_cfg = [] - for minor in range(py3_min, version[1] + 1): - out_cfg.append("--cfg=Py_3_%d" % minor) - - if platform.python_implementation() == "PyPy": - out_cfg.append("--cfg=PyPy") - - return out_cfg - - -def make_rust_extension(module_name): - return RustExtension( - module_name, "Cargo.toml", rustc_flags=get_py_version_cfgs(), debug=True - ) - - -setup( - name="rustapi-module", - version="0.1.0", - classifiers=[ - "License :: OSI Approved :: MIT License", - "Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "Programming Language :: Python", - "Programming Language :: Rust", - "Operating System :: POSIX", - "Operating System :: MacOS :: MacOS X", - ], - packages=["rustapi_module"], - rust_extensions=[ - make_rust_extension("rustapi_module.buf_and_str"), - make_rust_extension("rustapi_module.datetime"), - make_rust_extension("rustapi_module.misc"), - make_rust_extension("rustapi_module.objstore"), - make_rust_extension("rustapi_module.othermod"), - make_rust_extension("rustapi_module.pyclass_iter"), - make_rust_extension("rustapi_module.subclassing"), - make_rust_extension("rustapi_module.test_dict"), - ], - include_package_data=True, - zip_safe=False, -) diff --git a/examples/rustapi_module/src/lib.rs b/examples/rustapi_module/src/lib.rs deleted file mode 100644 index 257d31aefe8..00000000000 --- a/examples/rustapi_module/src/lib.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod buf_and_str; -pub mod datetime; -pub mod dict_iter; -pub mod misc; -pub mod objstore; -pub mod othermod; -pub mod pyclass_iter; -pub mod subclassing; diff --git a/examples/rustapi_module/tests/test_misc.py b/examples/rustapi_module/tests/test_misc.py deleted file mode 100644 index b4e05dd3534..00000000000 --- a/examples/rustapi_module/tests/test_misc.py +++ /dev/null @@ -1,6 +0,0 @@ -import rustapi_module.misc - - -def test_issue_219(): - # Should not deadlock - rustapi_module.misc.issue_219() diff --git a/examples/setuptools-rust-starter/Cargo.toml b/examples/setuptools-rust-starter/Cargo.toml new file mode 100644 index 00000000000..3a0b912dbad --- /dev/null +++ b/examples/setuptools-rust-starter/Cargo.toml @@ -0,0 +1,27 @@ +[package] +authors = ["PyO3 Authors"] +name = "setuptools-rust-starter" +version = "0.1.0" +description = "An example project to get started using PyO3 with maturin" +edition = "2018" + +[dependencies] + +[dependencies.pyo3] +path = "../../" +features = ["extension-module"] + +[lib] +name = "setuptools_rust_starter" +crate-type = ["cdylib"] + +[package.metadata.maturin] +classifier=[ + "License :: OSI Approved :: MIT License", + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Programming Language :: Python", + "Programming Language :: Rust", + "Operating System :: POSIX", + "Operating System :: MacOS :: MacOS X", +] diff --git a/examples/setuptools-rust-starter/MANIFEST.in b/examples/setuptools-rust-starter/MANIFEST.in new file mode 100644 index 00000000000..becccf7bc9a --- /dev/null +++ b/examples/setuptools-rust-starter/MANIFEST.in @@ -0,0 +1,2 @@ +include pyproject.toml Cargo.toml +recursive-include src * diff --git a/examples/setuptools-rust-starter/README.md b/examples/setuptools-rust-starter/README.md new file mode 100644 index 00000000000..57b3b2e4221 --- /dev/null +++ b/examples/setuptools-rust-starter/README.md @@ -0,0 +1,24 @@ +# setuptools-rust-starter + +An example of a basic Python extension module built using PyO3 and `setuptools_rust`. + +## Building and Testing + +To build this package, first install `setuptools_rust`: + +```shell +pip install setuptools_rust +``` + +To build and test use `python setup.py develop`: + +```shell +pip install -r requirements-dev.txt +python setup.py develop && pytest +``` + +Alternatively, install tox and run the tests inside an isolated environment: + +```shell +tox -e py +``` diff --git a/examples/setuptools-rust-starter/requirements-dev.txt b/examples/setuptools-rust-starter/requirements-dev.txt new file mode 100644 index 00000000000..7dc5c380fdb --- /dev/null +++ b/examples/setuptools-rust-starter/requirements-dev.txt @@ -0,0 +1,2 @@ +pytest>=3.5.0 +setuptools_rust~=0.11.0 diff --git a/examples/setuptools-rust-starter/setup.py b/examples/setuptools-rust-starter/setup.py new file mode 100644 index 00000000000..0c8a96587b6 --- /dev/null +++ b/examples/setuptools-rust-starter/setup.py @@ -0,0 +1,26 @@ +from setuptools import setup +from setuptools_rust import RustExtension + + +setup( + name="setuptools-rust-starter", + version="0.1.0", + classifiers=[ + "License :: OSI Approved :: MIT License", + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Programming Language :: Python", + "Programming Language :: Rust", + "Operating System :: POSIX", + "Operating System :: MacOS :: MacOS X", + ], + packages=["setuptools_rust_starter"], + rust_extensions=[ + RustExtension( + "setuptools_rust_starter._setuptools_rust_starter", + debug=False, + ), + ], + include_package_data=True, + zip_safe=False, +) diff --git a/examples/setuptools-rust-starter/setuptools_rust_starter/__init__.py b/examples/setuptools-rust-starter/setuptools_rust_starter/__init__.py new file mode 100644 index 00000000000..074483e5203 --- /dev/null +++ b/examples/setuptools-rust-starter/setuptools_rust_starter/__init__.py @@ -0,0 +1,7 @@ +# import the contents of the Rust library into the Python extension +from ._setuptools_rust_starter import * + + +class PythonClass: + def __init__(self, value: int) -> None: + self.value = value diff --git a/examples/setuptools-rust-starter/src/lib.rs b/examples/setuptools-rust-starter/src/lib.rs new file mode 100644 index 00000000000..0f28e6eeacd --- /dev/null +++ b/examples/setuptools-rust-starter/src/lib.rs @@ -0,0 +1,35 @@ +use pyo3::prelude::*; +use pyo3::types::PyDict; +use pyo3::wrap_pymodule; + +mod submodule; +use submodule::*; + +#[pyclass] +struct ExampleClass { + #[pyo3(get, set)] + value: i32, +} + +#[pymethods] +impl ExampleClass { + #[new] + pub fn new(value: i32) -> Self { + ExampleClass { value } + } +} + +#[pymodule] +fn _setuptools_rust_starter(py: Python, m: &PyModule) -> PyResult<()> { + m.add_class::()?; + m.add_wrapped(wrap_pymodule!(submodule))?; + + // Inserting to sys.modules allows importing submodules nicely from Python + // e.g. from setuptools_rust_starter.submodule import SubmoduleClass + + let sys = PyModule::import(py, "sys")?; + let sys_modules: &PyDict = sys.getattr("modules")?.downcast()?; + sys_modules.set_item("setuptools_rust_starter.submodule", m.getattr("submodule")?)?; + + Ok(()) +} diff --git a/examples/setuptools-rust-starter/src/submodule.rs b/examples/setuptools-rust-starter/src/submodule.rs new file mode 100644 index 00000000000..8096e337755 --- /dev/null +++ b/examples/setuptools-rust-starter/src/submodule.rs @@ -0,0 +1,22 @@ +use pyo3::prelude::*; + +#[pyclass] +struct SubmoduleClass {} + +#[pymethods] +impl SubmoduleClass { + #[new] + pub fn __new__() -> Self { + SubmoduleClass {} + } + + pub fn greeting(&self) -> &'static str { + "Hello, world!" + } +} + +#[pymodule] +pub fn submodule(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_class::()?; + Ok(()) +} diff --git a/examples/setuptools-rust-starter/tests/test_setuptools_rust_starter.py b/examples/setuptools-rust-starter/tests/test_setuptools_rust_starter.py new file mode 100644 index 00000000000..7ca33bba047 --- /dev/null +++ b/examples/setuptools-rust-starter/tests/test_setuptools_rust_starter.py @@ -0,0 +1,11 @@ +from setuptools_rust_starter import PythonClass, ExampleClass + + +def test_python_class() -> None: + py_class = PythonClass(value=10) + assert py_class.value == 10 + + +def test_example_class() -> None: + example = ExampleClass(value=11) + assert example.value == 11 diff --git a/examples/setuptools-rust-starter/tests/test_submodule.py b/examples/setuptools-rust-starter/tests/test_submodule.py new file mode 100644 index 00000000000..55bb922e8bd --- /dev/null +++ b/examples/setuptools-rust-starter/tests/test_submodule.py @@ -0,0 +1,6 @@ +from setuptools_rust_starter.submodule import SubmoduleClass + + +def test_submodule_class() -> None: + submodule_class = SubmoduleClass() + assert submodule_class.greeting() == "Hello, world!" diff --git a/examples/setuptools-rust-starter/tox.ini b/examples/setuptools-rust-starter/tox.ini new file mode 100644 index 00000000000..d28e126d1d9 --- /dev/null +++ b/examples/setuptools-rust-starter/tox.ini @@ -0,0 +1,12 @@ +[tox] +# can't install from sdist because local pyo3 repo can't be included in the sdist +skipsdist = true + +[testenv] +description = Run the unit tests under {basepython} +deps = -rrequirements-dev.txt +commands = + # Use pip master with in-tree-build feature (to be released in pip 21.0) + python -m pip install --upgrade git+https://github.com/pypa/pip.git + python -m pip install . --use-feature=in-tree-build + pytest {posargs} diff --git a/src/class/iter.rs b/src/class/iter.rs index 7f1e8f8cba3..6e51a7f7507 100644 --- a/src/class/iter.rs +++ b/src/class/iter.rs @@ -41,7 +41,7 @@ use crate::{ffi, IntoPy, IntoPyPointer, PyClass, PyObject, Python}; /// # Python::with_gil(|py| { /// # let inst = Py::new(py, Iter { count: 0 }).unwrap(); /// # pyo3::py_run!(py, inst, "assert next(inst) == 1"); -/// # }); // test of StopIteration is done in examples/rustapi_module/pyclass_iter.rs +/// # }); // test of StopIteration is done in examples/pyo3-pytests/pyclass_iter.rs /// ``` #[allow(unused_variables)] pub trait PyIterProtocol<'p>: PyClass {