From 62ab6b60df2cf4b846ff158f2a58efde66f7ab52 Mon Sep 17 00:00:00 2001 From: konstin Date: Mon, 12 Apr 2021 18:37:27 +0200 Subject: [PATCH 1/3] python_src layout --- src/build_context.rs | 25 +- test-crates/pyo3-mixed/pyo3_mixed/__init__.py | 2 +- .../__init__.py | 0 .../{python_module => my_submodule}/double.py | 0 test-crates/pyo3-src-layout/Cargo.lock | 283 ++++++++++++++++++ test-crates/pyo3-src-layout/Cargo.toml | 23 ++ test-crates/pyo3-src-layout/Readme.md | 30 ++ .../check_installed/check_installed.py | 7 + test-crates/pyo3-src-layout/pyproject.toml | 3 + .../python_src/pyo3_src_layout/__init__.py | 6 + .../pyo3_src_layout/my_submodule/__init__.py | 0 .../pyo3_src_layout/my_submodule/double.py | 5 + test-crates/pyo3-src-layout/src/lib.rs | 14 + .../pyo3-src-layout/test_pyo3_src_layout.py | 11 + test-crates/pyo3-src-layout/tox.ini | 7 + tests/run.rs | 13 + 16 files changed, 423 insertions(+), 6 deletions(-) rename test-crates/pyo3-mixed/pyo3_mixed/{python_module => my_submodule}/__init__.py (100%) rename test-crates/pyo3-mixed/pyo3_mixed/{python_module => my_submodule}/double.py (100%) create mode 100644 test-crates/pyo3-src-layout/Cargo.lock create mode 100644 test-crates/pyo3-src-layout/Cargo.toml create mode 100644 test-crates/pyo3-src-layout/Readme.md create mode 100755 test-crates/pyo3-src-layout/check_installed/check_installed.py create mode 100644 test-crates/pyo3-src-layout/pyproject.toml create mode 100644 test-crates/pyo3-src-layout/python_src/pyo3_src_layout/__init__.py create mode 100644 test-crates/pyo3-src-layout/python_src/pyo3_src_layout/my_submodule/__init__.py create mode 100644 test-crates/pyo3-src-layout/python_src/pyo3_src_layout/my_submodule/double.py create mode 100644 test-crates/pyo3-src-layout/src/lib.rs create mode 100644 test-crates/pyo3-src-layout/test_pyo3_src_layout.py create mode 100644 test-crates/pyo3-src-layout/tox.ini diff --git a/src/build_context.rs b/src/build_context.rs index 09b83a7f0..c9f530cd9 100644 --- a/src/build_context.rs +++ b/src/build_context.rs @@ -65,15 +65,30 @@ pub enum ProjectLayout { impl ProjectLayout { /// Checks whether a python module exists besides Cargo.toml with the right name pub fn determine(project_root: impl AsRef, module_name: &str) -> Result { - let python_package_dir = project_root.as_ref().join(module_name); - if python_package_dir.is_dir() { - if !python_package_dir.join("__init__.py").is_file() { - bail!("Found a directory with the module name ({}) next to Cargo.toml, which indicates a mixed python/rust project, but the directory didn't contain an __init__.py file.", module_name) + let python_dir_root = project_root.as_ref().join(module_name); + let python_dir_python = project_root.as_ref().join("python_src").join(module_name); + let python_dir; + if python_dir_root.is_dir() { + python_dir = Some(python_dir_root); + } else if python_dir_python.is_dir() { + python_dir = Some(python_dir_python); + } else { + python_dir = None; + } + + if let Some(python_dir) = python_dir { + if !python_dir.join("__init__.py").is_file() { + bail!( + "Found a directory with the module name ({}) next to Cargo.toml, \ + which indicates a mixed python/rust project, \ + but the directory didn't contain an __init__.py file.", + module_name + ) } println!("🍹 Building a mixed python/rust project"); - Ok(ProjectLayout::Mixed(python_package_dir)) + Ok(ProjectLayout::Mixed(python_dir)) } else { Ok(ProjectLayout::PureRust) } diff --git a/test-crates/pyo3-mixed/pyo3_mixed/__init__.py b/test-crates/pyo3-mixed/pyo3_mixed/__init__.py index c34ac83b4..d300d4889 100644 --- a/test-crates/pyo3-mixed/pyo3_mixed/__init__.py +++ b/test-crates/pyo3-mixed/pyo3_mixed/__init__.py @@ -1,4 +1,4 @@ -from .python_module.double import double +from .my_submodule.double import double from .pyo3_mixed import get_21 diff --git a/test-crates/pyo3-mixed/pyo3_mixed/python_module/__init__.py b/test-crates/pyo3-mixed/pyo3_mixed/my_submodule/__init__.py similarity index 100% rename from test-crates/pyo3-mixed/pyo3_mixed/python_module/__init__.py rename to test-crates/pyo3-mixed/pyo3_mixed/my_submodule/__init__.py diff --git a/test-crates/pyo3-mixed/pyo3_mixed/python_module/double.py b/test-crates/pyo3-mixed/pyo3_mixed/my_submodule/double.py similarity index 100% rename from test-crates/pyo3-mixed/pyo3_mixed/python_module/double.py rename to test-crates/pyo3-mixed/pyo3_mixed/my_submodule/double.py diff --git a/test-crates/pyo3-src-layout/Cargo.lock b/test-crates/pyo3-src-layout/Cargo.lock new file mode 100644 index 000000000..a03485137 --- /dev/null +++ b/test-crates/pyo3-src-layout/Cargo.lock @@ -0,0 +1,283 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "ctor" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8f45d9ad417bcef4817d614a501ab55cdd96a6fdb24f49aab89a54acfd66b19" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "ghost" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5bcf1bbeab73aa4cf2fde60a846858dc036163c7c33bec309f8d17de785479" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "indoc" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47741a8bc60fb26eb8d6e0238bbb26d8575ff623fdc97b1a2c00c050b9684ed8" +dependencies = [ + "indoc-impl", + "proc-macro-hack", +] + +[[package]] +name = "indoc-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", + "unindent", +] + +[[package]] +name = "instant" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "inventory" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0f7efb804ec95e33db9ad49e4252f049e37e8b0a4652e3cd61f7999f2eff7f" +dependencies = [ + "ctor", + "ghost", + "inventory-impl", +] + +[[package]] +name = "inventory-impl" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c094e94816723ab936484666968f5b58060492e880f3c8d00489a1e244fa51" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "libc" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae" + +[[package]] +name = "lock_api" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "paste" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880" +dependencies = [ + "paste-impl", + "proc-macro-hack", +] + +[[package]] +name = "paste-impl" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6" +dependencies = [ + "proc-macro-hack", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "pyo3" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4837b8e8e18a102c23f79d1e9a110b597ea3b684c95e874eb1ad88f8683109c3" +dependencies = [ + "cfg-if", + "ctor", + "indoc", + "inventory", + "libc", + "parking_lot", + "paste", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-macros" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47f2c300ceec3e58064fd5f8f5b61230f2ffd64bde4970c81fdd0563a2db1bb" +dependencies = [ + "pyo3-macros-backend", + "quote", + "syn", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87b097e5d84fcbe3e167f400fbedd657820a375b034c78bd852050749a575d66" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pyo3-src-layout" +version = "2.1.3" +dependencies = [ + "pyo3", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +dependencies = [ + "bitflags", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + +[[package]] +name = "syn" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "unindent" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/test-crates/pyo3-src-layout/Cargo.toml b/test-crates/pyo3-src-layout/Cargo.toml new file mode 100644 index 000000000..07c6c531a --- /dev/null +++ b/test-crates/pyo3-src-layout/Cargo.toml @@ -0,0 +1,23 @@ +[package] +authors = ["konstin "] +name = "pyo3-src-layout" +version = "2.1.3" +description = "Implements a dummy function combining rust and python using the python_src layout" +readme = "Readme.md" +edition = "2018" + +[package.metadata.maturin.scripts] +get_42 = "pyo3_mixed:get_42" + +[package.metadata.maturin] +classifier = [ + "Programming Language :: Python", + "Programming Language :: Rust" +] + +[dependencies] +pyo3 = { version = "0.13.2", features = ["extension-module"] } + +[lib] +name = "pyo3_src_layout" +crate-type = ["cdylib"] diff --git a/test-crates/pyo3-src-layout/Readme.md b/test-crates/pyo3-src-layout/Readme.md new file mode 100644 index 000000000..038375070 --- /dev/null +++ b/test-crates/pyo3-src-layout/Readme.md @@ -0,0 +1,30 @@ +# pyo3-mixed + +A package for testing maturin with a mixed pyo3/python project. + +## Usage + +```bash +pip install . +``` + +```python +import pyo3_mixed +assert pyo3_mixed.get_42() == 42 +``` + +## Testing + +Install tox: + +```bash +pip install tox +``` + +Run it: + +```bash +tox +``` + +The tests are in `test_pyo3_mixed.py`, while the configuration is in tox.ini diff --git a/test-crates/pyo3-src-layout/check_installed/check_installed.py b/test-crates/pyo3-src-layout/check_installed/check_installed.py new file mode 100755 index 000000000..eb52f966f --- /dev/null +++ b/test-crates/pyo3-src-layout/check_installed/check_installed.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +import pyo3_src_layout + +assert pyo3_src_layout.get_42() == 42 + +print("SUCCESS") diff --git a/test-crates/pyo3-src-layout/pyproject.toml b/test-crates/pyo3-src-layout/pyproject.toml new file mode 100644 index 000000000..9a2f56d97 --- /dev/null +++ b/test-crates/pyo3-src-layout/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["maturin>=0.10,<0.11"] +build-backend = "maturin" diff --git a/test-crates/pyo3-src-layout/python_src/pyo3_src_layout/__init__.py b/test-crates/pyo3-src-layout/python_src/pyo3_src_layout/__init__.py new file mode 100644 index 000000000..62b2c9697 --- /dev/null +++ b/test-crates/pyo3-src-layout/python_src/pyo3_src_layout/__init__.py @@ -0,0 +1,6 @@ +from .my_submodule.double import double +from .pyo3_src_layout import get_21 + + +def get_42() -> int: + return double(get_21) diff --git a/test-crates/pyo3-src-layout/python_src/pyo3_src_layout/my_submodule/__init__.py b/test-crates/pyo3-src-layout/python_src/pyo3_src_layout/my_submodule/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/test-crates/pyo3-src-layout/python_src/pyo3_src_layout/my_submodule/double.py b/test-crates/pyo3-src-layout/python_src/pyo3_src_layout/my_submodule/double.py new file mode 100644 index 000000000..2eed18d52 --- /dev/null +++ b/test-crates/pyo3-src-layout/python_src/pyo3_src_layout/my_submodule/double.py @@ -0,0 +1,5 @@ +from typing import Callable + + +def double(fn: Callable[[], int]) -> int: + return 2 * fn() diff --git a/test-crates/pyo3-src-layout/src/lib.rs b/test-crates/pyo3-src-layout/src/lib.rs new file mode 100644 index 000000000..84c321113 --- /dev/null +++ b/test-crates/pyo3-src-layout/src/lib.rs @@ -0,0 +1,14 @@ +use pyo3::prelude::*; +use pyo3::wrap_pyfunction; + +#[pyfunction] +fn get_21() -> usize { + 21 +} + +#[pymodule] +fn pyo3_src_layout(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_wrapped(wrap_pyfunction!(get_21))?; + + Ok(()) +} diff --git a/test-crates/pyo3-src-layout/test_pyo3_src_layout.py b/test-crates/pyo3-src-layout/test_pyo3_src_layout.py new file mode 100644 index 000000000..180f9b2c1 --- /dev/null +++ b/test-crates/pyo3-src-layout/test_pyo3_src_layout.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 + +import pyo3_mixed2 + + +def test_get_42(): + assert pyo3_mixed2.get_42() == 42 + + +if __name__ == '__main__': + test_get_42() diff --git a/test-crates/pyo3-src-layout/tox.ini b/test-crates/pyo3-src-layout/tox.ini new file mode 100644 index 000000000..fd19ca2b2 --- /dev/null +++ b/test-crates/pyo3-src-layout/tox.ini @@ -0,0 +1,7 @@ +[tox] +envlist = py36,py37,py38 +isolated_build = True + +[testenv] +deps = pytest +commands = pytest \ No newline at end of file diff --git a/tests/run.rs b/tests/run.rs index 1c867390d..d6b28a0a8 100644 --- a/tests/run.rs +++ b/tests/run.rs @@ -14,6 +14,11 @@ fn develop_pyo3_mixed() { handle_result(develop::test_develop("test-crates/pyo3-mixed", None)); } +#[test] +fn develop_pyo3_src_layout() { + handle_result(develop::test_develop("test-crates/pyo3-src-layout", None)); +} + #[test] fn develop_cffi_pure() { handle_result(develop::test_develop("test-crates/cffi-pure", None)); @@ -42,6 +47,14 @@ fn integration_pyo3_mixed() { )); } +#[test] +fn integration_pyo3_src_layout() { + handle_result(integration::test_integration( + "test-crates/pyo3-src-layout", + None, + )); +} + #[cfg(target_os = "windows")] #[test] #[ignore] From 4e9a74e57f72330e701240e7d0e3560b6272720d Mon Sep 17 00:00:00 2001 From: konstin Date: Mon, 12 Apr 2021 18:46:37 +0200 Subject: [PATCH 2/3] black --- test-crates/pyo3-src-layout/test_pyo3_src_layout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-crates/pyo3-src-layout/test_pyo3_src_layout.py b/test-crates/pyo3-src-layout/test_pyo3_src_layout.py index 180f9b2c1..5899a54c5 100644 --- a/test-crates/pyo3-src-layout/test_pyo3_src_layout.py +++ b/test-crates/pyo3-src-layout/test_pyo3_src_layout.py @@ -7,5 +7,5 @@ def test_get_42(): assert pyo3_mixed2.get_42() == 42 -if __name__ == '__main__': +if __name__ == "__main__": test_get_42() From 9d4f106524316900ffa5eb1e35b898ff26e529e0 Mon Sep 17 00:00:00 2001 From: konstin Date: Tue, 20 Apr 2021 17:12:31 +0200 Subject: [PATCH 3/3] Add documentation --- Readme.md | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Readme.md b/Readme.md index 2dbfd7e9e..e64809bad 100644 --- a/Readme.md +++ b/Readme.md @@ -83,11 +83,25 @@ To create a mixed rust/python project, create a folder with your module name (i. my-project ├── Cargo.toml ├── my_project -│   ├── __init__.py -│   └── bar.py +│ ├── __init__.py +│ └── bar.py ├── Readme.md └── src -    └── lib.rs + └── lib.rs +``` + +Alternatively, you can also put the python sources in a folder called `python_src`, which resembles the [src layout](https://hynek.me/articles/testing-packaging/#src) without conflicting with rust's `src` directory: + +``` +my-project +├── Cargo.toml +├── python_src +│ └── my_project +│ ├── __init__.py +│ └── bar.py +├── Readme.md +└── src + └── lib.rs ``` maturin will add the native extension as a module in your python folder. When using develop, maturin will copy the native library and for cffi also the glue code to your python folder. You should add those files to your gitignore.