Skip to content

Commit 990bbb5

Browse files
authored
Merge pull request #1537 from davidhewitt/maturin-examples-v2
examples: maturin and setuptools_rust examples
2 parents 7eb3aa3 + 0ae7b69 commit 990bbb5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+495
-157
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
steps:
1616
- uses: actions/checkout@v2
1717
- uses: actions/setup-python@v2
18-
- run: pip install black==19.10b0
18+
- run: pip install black==20.8b1
1919
- uses: actions-rs/toolchain@v1
2020
with:
2121
toolchain: stable
@@ -141,15 +141,13 @@ jobs:
141141
run: cargo test --manifest-path=pyo3-macros-backend/Cargo.toml
142142

143143
- name: Install python test dependencies
144-
run: |
145-
python -m pip install -U pip setuptools
146-
pip install setuptools-rust pytest pytest-benchmark tox
144+
run: python -m pip install -U pip tox
147145

148146
- name: Test example extension modules
149147
shell: bash
150148
run: |
151149
for example_dir in examples/*; do
152-
tox --discover $(which python) -c $example_dir -e py
150+
tox -c $example_dir -e py
153151
done
154152
env:
155153
TOX_TESTENV_PASSENV: "CARGO_BUILD_TARGET"

Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ nightly = []
7373
members = [
7474
"pyo3-macros",
7575
"pyo3-macros-backend",
76-
"examples/pyo3_benchmarks",
77-
"examples/rustapi_module",
76+
"examples/pyo3-benchmarks",
77+
"examples/pyo3-pytests",
78+
"examples/maturin-starter",
79+
"examples/setuptools-rust-starter",
7880
"examples/word-count"
7981
]

examples/maturin-starter/Cargo.toml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[package]
2+
authors = ["PyO3 Authors"]
3+
name = "maturin-starter"
4+
version = "0.1.0"
5+
description = "An example project to get started using PyO3 with maturin"
6+
edition = "2018"
7+
8+
[dependencies]
9+
10+
[dependencies.pyo3]
11+
path = "../../"
12+
features = ["extension-module"]
13+
14+
[lib]
15+
name = "maturin_starter"
16+
crate-type = ["cdylib"]
17+
18+
[package.metadata.maturin]
19+
classifier=[
20+
"License :: OSI Approved :: MIT License",
21+
"Development Status :: 3 - Alpha",
22+
"Intended Audience :: Developers",
23+
"Programming Language :: Python",
24+
"Programming Language :: Rust",
25+
"Operating System :: POSIX",
26+
"Operating System :: MacOS :: MacOS X",
27+
]

examples/maturin-starter/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# maturin-starter
2+
3+
An example of a basic Python extension module built using PyO3 and [`maturin`](https://github.com/PyO3/maturin).
4+
5+
## Building and Testing
6+
7+
To build this package, first install `maturin`:
8+
9+
```shell
10+
pip install maturin
11+
```
12+
13+
To build and test use `maturin develop`:
14+
15+
```shell
16+
pip install -r requirements-dev.txt
17+
maturin develop && pytest
18+
```
19+
20+
Alternatively, install tox and run the tests inside an isolated environment:
21+
22+
```shell
23+
tox -e py
24+
```
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# import the contents of the Rust library into the Python extension
2+
from .maturin_starter import *
3+
4+
5+
class PythonClass:
6+
def __init__(self, value: int) -> None:
7+
self.value = value
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[build-system]
2+
requires = ["maturin>=0.10,<0.11"]
3+
build-backend = "maturin"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pytest>=3.5.0

examples/maturin-starter/src/lib.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use pyo3::prelude::*;
2+
use pyo3::types::PyDict;
3+
use pyo3::wrap_pymodule;
4+
5+
mod submodule;
6+
use submodule::*;
7+
8+
#[pyclass]
9+
struct ExampleClass {
10+
#[pyo3(get, set)]
11+
value: i32,
12+
}
13+
14+
#[pymethods]
15+
impl ExampleClass {
16+
#[new]
17+
pub fn new(value: i32) -> Self {
18+
ExampleClass { value }
19+
}
20+
}
21+
22+
#[pymodule]
23+
fn maturin_starter(py: Python, m: &PyModule) -> PyResult<()> {
24+
m.add_class::<ExampleClass>()?;
25+
m.add_wrapped(wrap_pymodule!(submodule))?;
26+
27+
// Inserting to sys.modules allows importing submodules nicely from Python
28+
// e.g. from maturin_starter.submodule import SubmoduleClass
29+
30+
let sys = PyModule::import(py, "sys")?;
31+
let sys_modules: &PyDict = sys.getattr("modules")?.downcast()?;
32+
sys_modules.set_item("maturin_starter.submodule", m.getattr("submodule")?)?;
33+
34+
Ok(())
35+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use pyo3::prelude::*;
2+
3+
#[pyclass]
4+
struct SubmoduleClass {}
5+
6+
#[pymethods]
7+
impl SubmoduleClass {
8+
#[new]
9+
pub fn __new__() -> Self {
10+
SubmoduleClass {}
11+
}
12+
13+
pub fn greeting(&self) -> &'static str {
14+
"Hello, world!"
15+
}
16+
}
17+
18+
#[pymodule]
19+
pub fn submodule(_py: Python, m: &PyModule) -> PyResult<()> {
20+
m.add_class::<SubmoduleClass>()?;
21+
Ok(())
22+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from maturin_starter import PythonClass, ExampleClass
2+
3+
4+
def test_python_class() -> None:
5+
py_class = PythonClass(value=10)
6+
assert py_class.value == 10
7+
8+
9+
def test_example_class() -> None:
10+
example = ExampleClass(value=11)
11+
assert example.value == 11
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from maturin_starter.submodule import SubmoduleClass
2+
3+
4+
def test_submodule_class() -> None:
5+
submodule_class = SubmoduleClass()
6+
assert submodule_class.greeting() == "Hello, world!"

examples/rustapi_module/tox.ini renamed to examples/maturin-starter/tox.ini

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,7 @@ skipsdist = true
66
description = Run the unit tests under {basepython}
77
deps = -rrequirements-dev.txt
88
commands =
9-
python setup.py install
9+
# Use pip master with in-tree-build feature (to be released in pip 21.0)
10+
python -m pip install --upgrade git+https://github.com/pypa/pip.git
11+
python -m pip install . --use-feature=in-tree-build
1012
pytest {posargs}

examples/pyo3-benchmarks/MANIFEST.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
include Cargo.toml
2+
recursive-include src *
3+
recursive-include tests

examples/pyo3-benchmarks/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# pyo3-benchmarks
2+
3+
This extension module contains benchmarks for pieces of PyO3's API accessible from Python.
4+
5+
## Running the benchmarks
6+
7+
You can install the module in your Python environment and then run the benchmarks with pytest:
8+
9+
```shell
10+
python setup.py develop
11+
pytest
12+
```
13+
14+
Or with tox:
15+
16+
```shell
17+
tox -e py
18+
```
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
pip>=19.1
2-
hypothesis>=3.55
32
pytest>=3.5.0
43
setuptools-rust>=0.10.2
5-
psutil>=5.6
64
pytest-benchmark~=3.2

examples/pyo3_benchmarks/setup.py renamed to examples/pyo3-benchmarks/setup.py

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,7 @@
1-
import sys
2-
import platform
3-
41
from setuptools import setup
52
from setuptools_rust import RustExtension
63

74

8-
def get_py_version_cfgs():
9-
# For now each Cfg Py_3_X flag is interpreted as "at least 3.X"
10-
version = sys.version_info[0:2]
11-
py3_min = 6
12-
out_cfg = []
13-
for minor in range(py3_min, version[1] + 1):
14-
out_cfg.append("--cfg=Py_3_%d" % minor)
15-
16-
if platform.python_implementation() == "PyPy":
17-
out_cfg.append("--cfg=PyPy")
18-
19-
return out_cfg
20-
21-
225
setup(
236
name="pyo3-benchmarks",
247
version="0.1.0",
@@ -35,7 +18,6 @@ def get_py_version_cfgs():
3518
rust_extensions=[
3619
RustExtension(
3720
"pyo3_benchmarks._pyo3_benchmarks",
38-
rustc_flags=get_py_version_cfgs(),
3921
debug=False,
4022
),
4123
],
File renamed without changes.

examples/pyo3-pytests/Cargo.toml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[package]
2+
authors = ["PyO3 Authors"]
3+
name = "pyo3-pytests"
4+
version = "0.1.0"
5+
description = "Python-based tests for PyO3"
6+
edition = "2018"
7+
8+
[dependencies]
9+
10+
[dependencies.pyo3]
11+
path = "../../"
12+
features = ["extension-module"]
13+
14+
[lib]
15+
name = "pyo3_pytests"
16+
crate-type = ["cdylib"]
17+
18+
[package.metadata.maturin]
19+
classifier=[
20+
"License :: OSI Approved :: MIT License",
21+
"Development Status :: 3 - Alpha",
22+
"Intended Audience :: Developers",
23+
"Programming Language :: Python",
24+
"Programming Language :: Rust",
25+
"Operating System :: POSIX",
26+
"Operating System :: MacOS :: MacOS X",
27+
]

examples/pyo3-pytests/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# pyo3-pytests
2+
3+
An extension module built using PyO3, used to test PyO3 from Python.
4+
5+
## Testing
6+
7+
This package is intended to be built using `maturin`. Once built, you can run the tests using `pytest`:
8+
9+
```shell
10+
pip install maturin
11+
maturin develop
12+
pytest
13+
```
14+
15+
Alternatively, install tox and run the tests inside an isolated environment:
16+
17+
```shell
18+
tox -e py
19+
```

examples/pyo3-pytests/build.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use std::process::Command;
2+
3+
fn main() {
4+
let out = Command::new("python")
5+
.args(&["-c", "import sys; import platform; print(sys.version_info[1]); print(platform.python_implementation())"])
6+
.output()
7+
.expect("python version did not print");
8+
9+
let output = String::from_utf8_lossy(&out.stdout);
10+
let mut lines = output.trim().lines();
11+
12+
println!("{}", output);
13+
14+
let version: u8 = lines
15+
.next()
16+
.unwrap()
17+
.parse()
18+
.expect("python version was not parsed");
19+
let implementation = lines.next().unwrap();
20+
21+
for each in 6..version {
22+
println!("cargo:rustc-cfg=Py_3_{}", each);
23+
}
24+
25+
if implementation == "PyPy" {
26+
println!("cargo:rustc-cfg=PyPy");
27+
}
28+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .pyo3_pytests import *

examples/pyo3-pytests/pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[build-system]
2+
requires = ["maturin>=0.10,<0.11"]
3+
build-backend = "maturin"
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
pip>=19.1
22
hypothesis>=3.55
33
pytest>=3.5.0
4-
setuptools-rust>=0.10.2
54
psutil>=5.6

examples/rustapi_module/src/dict_iter.rs renamed to examples/pyo3-pytests/src/dict_iter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use pyo3::prelude::*;
33
use pyo3::types::PyDict;
44

55
#[pymodule]
6-
fn test_dict(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
6+
fn dict_iter(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
77
m.add_class::<DictSize>()?;
88
Ok(())
99
}

0 commit comments

Comments
 (0)