From 26edb1477af107080d34edcf0629680093918e95 Mon Sep 17 00:00:00 2001 From: messense Date: Tue, 6 Apr 2021 16:40:57 +0800 Subject: [PATCH] Support Rust extension as a submodule in mixed Python/Rust projects Co-authored-by: konstin --- src/build_context.rs | 64 +++- src/build_options.rs | 8 +- src/metadata.rs | 14 +- src/module_writer.rs | 45 +-- test-crates/pyo3-mixed-submodule/Cargo.lock | 283 ++++++++++++++++++ test-crates/pyo3-mixed-submodule/Cargo.toml | 21 ++ test-crates/pyo3-mixed-submodule/Readme.md | 30 ++ .../check_installed/check_installed.py | 7 + .../pyo3_mixed_submodule/__init__.py | 6 + .../python_module/__init__.py | 0 .../python_module/double.py | 5 + .../rust_module/__init__.py | 0 .../pyo3-mixed-submodule/pyproject.toml | 3 + test-crates/pyo3-mixed-submodule/src/lib.rs | 14 + .../test_pyo3_mixed_submodule.py | 7 + test-crates/pyo3-mixed-submodule/tox.ini | 7 + test-dockerfile.sh | 8 + tests/run.rs | 16 + 18 files changed, 501 insertions(+), 37 deletions(-) create mode 100644 test-crates/pyo3-mixed-submodule/Cargo.lock create mode 100644 test-crates/pyo3-mixed-submodule/Cargo.toml create mode 100644 test-crates/pyo3-mixed-submodule/Readme.md create mode 100755 test-crates/pyo3-mixed-submodule/check_installed/check_installed.py create mode 100644 test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/__init__.py create mode 100644 test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/python_module/__init__.py create mode 100644 test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/python_module/double.py create mode 100644 test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/rust_module/__init__.py create mode 100644 test-crates/pyo3-mixed-submodule/pyproject.toml create mode 100644 test-crates/pyo3-mixed-submodule/src/lib.rs create mode 100644 test-crates/pyo3-mixed-submodule/test_pyo3_mixed_submodule.py create mode 100644 test-crates/pyo3-mixed-submodule/tox.ini diff --git a/src/build_context.rs b/src/build_context.rs index 09b83a7f0..18df8380e 100644 --- a/src/build_context.rs +++ b/src/build_context.rs @@ -55,27 +55,63 @@ impl BridgeModel { #[derive(Clone, Debug, PartialEq, Eq)] pub enum ProjectLayout { /// A rust crate compiled into a shared library with only some glue python for cffi - PureRust, - /// A python package that is extended by a native rust module. /// - /// Contains the canonicialized (i.e. absolute) path to the python part of the project - Mixed(PathBuf), + /// Contains the the rust extension name + PureRust(String), + /// A python package that is extended by a native rust module. + Mixed { + /// Contains the canonicialized (i.e. absolute) path to the python part of the project + python_module: PathBuf, + /// Contains the canonicialized (i.e. absolute) path to the rust part of the project + rust_module: PathBuf, + /// rust extension name + extension_name: String, + }, } 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() { + // A dot in the module name means the extension module goes into the module folder specified by the path + let parts: Vec<&str> = module_name.split('.').collect(); + let (python_module, rust_module, extension_name) = if parts.len() > 1 { + let mut rust_module = project_root.as_ref().to_path_buf(); + rust_module.extend(&parts[0..parts.len() - 1]); + ( + project_root.as_ref().join(parts[0]), + rust_module, + parts[parts.len() - 1].to_string(), + ) + } else { + ( + project_root.as_ref().join(module_name), + project_root.as_ref().join(module_name), + module_name.to_string(), + ) + }; + if python_module.is_dir() { + if !python_module.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_module, + rust_module, + extension_name, + }) } else { - Ok(ProjectLayout::PureRust) + Ok(ProjectLayout::PureRust(extension_name)) + } + } + + pub fn extension_name(&self) -> &str { + match *self { + ProjectLayout::PureRust(ref name) => name, + ProjectLayout::Mixed { + ref extension_name, .. + } => extension_name, } } } @@ -398,11 +434,15 @@ impl BuildContext { WheelWriter::new(&tag, &self.out, &self.metadata21, &self.scripts, &tags)?; match self.project_layout { - ProjectLayout::Mixed(ref python_module) => { - write_python_part(&mut builder, python_module, &self.module_name) + ProjectLayout::Mixed { + ref python_module, + ref extension_name, + .. + } => { + write_python_part(&mut builder, python_module, extension_name) .context("Failed to add the python module to the package")?; } - ProjectLayout::PureRust => {} + ProjectLayout::PureRust(_) => {} } // I wouldn't know of any case where this would be the wrong (and neither do diff --git a/src/build_options.rs b/src/build_options.rs index 423ff61b0..e431624f4 100644 --- a/src/build_options.rs +++ b/src/build_options.rs @@ -117,9 +117,10 @@ impl BuildOptions { let manifest_dir = manifest_file.parent().unwrap(); let metadata21 = Metadata21::from_cargo_toml(&cargo_toml, &manifest_dir) .context("Failed to parse Cargo.toml into python metadata")?; + let extra_metadata = cargo_toml.remaining_core_metadata(); let scripts = cargo_toml.scripts(); - let crate_name = cargo_toml.package.name; + let crate_name = &cargo_toml.package.name; // If the package name contains minuses, you must declare a module with // underscores as lib name @@ -129,8 +130,9 @@ impl BuildOptions { .and_then(|lib| lib.name.as_ref()) .unwrap_or(&crate_name) .to_owned(); + let extension_name = extra_metadata.name.as_ref().unwrap_or(&module_name); - let project_layout = ProjectLayout::determine(manifest_dir, &module_name)?; + let project_layout = ProjectLayout::determine(manifest_dir, &extension_name)?; let mut cargo_extra_args = split_extra_args(&self.cargo_extra_args)?; if let Some(ref target) = self.target { @@ -209,7 +211,7 @@ impl BuildOptions { project_layout, metadata21, scripts, - crate_name, + crate_name: crate_name.to_string(), module_name, manifest_path: self.manifest_path, out: wheel_dir, diff --git a/src/metadata.rs b/src/metadata.rs index 48c705438..7b643cfdc 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -112,14 +112,22 @@ impl Metadata21 { description = None; description_content_type = None; }; + let name = extra_metadata + .name + .map(|name| { + if let Some(pos) = name.find('.') { + name.split_at(pos).0.to_string() + } else { + name.clone() + } + }) + .unwrap_or_else(|| cargo_toml.package.name.clone()); Ok(Metadata21 { metadata_version: "2.1".to_owned(), // Mapped from cargo metadata - name: extra_metadata - .name - .unwrap_or_else(|| cargo_toml.package.name.clone()), + name, version: cargo_toml.package.version.clone(), summary: cargo_toml.package.description.clone(), description, diff --git a/src/module_writer.rs b/src/module_writer.rs index 96031cc28..39ea1c634 100644 --- a/src/module_writer.rs +++ b/src/module_writer.rs @@ -572,26 +572,31 @@ pub fn write_bindings_module( target: &Target, develop: bool, ) -> Result<()> { + let ext_name = project_layout.extension_name(); let so_filename = match python_interpreter { - Some(python_interpreter) => python_interpreter.get_library_name(&module_name), + Some(python_interpreter) => python_interpreter.get_library_name(&ext_name), // abi3 None => { if target.is_unix() { - format!("{base}.abi3.so", base = module_name) + format!("{base}.abi3.so", base = ext_name) } else { // Apparently there is no tag for abi3 on windows - format!("{base}.pyd", base = module_name) + format!("{base}.pyd", base = ext_name) } } }; match project_layout { - ProjectLayout::Mixed(ref python_module) => { + ProjectLayout::Mixed { + ref python_module, + ref rust_module, + .. + } => { write_python_part(writer, python_module, &module_name) .context("Failed to add the python module to the package")?; if develop { - let target = python_module.join(&so_filename); + let target = rust_module.join(&so_filename); fs::copy(&artifact, &target).context(format!( "Failed to copy {} to {}", artifact.display(), @@ -599,13 +604,10 @@ pub fn write_bindings_module( ))?; } - writer.add_file_with_permissions( - Path::new(&module_name).join(&so_filename), - &artifact, - 0o755, - )?; + let relative = rust_module.strip_prefix(python_module.parent().unwrap())?; + writer.add_file_with_permissions(relative.join(&so_filename), &artifact, 0o755)?; } - ProjectLayout::PureRust => { + ProjectLayout::PureRust(_) => { writer.add_file_with_permissions(so_filename, &artifact, 0o755)?; } } @@ -628,7 +630,11 @@ pub fn write_cffi_module( let module; match project_layout { - ProjectLayout::Mixed(ref python_module) => { + ProjectLayout::Mixed { + ref python_module, + ref rust_module, + ref extension_name, + } => { write_python_part(writer, python_module, &module_name) .context("Failed to add the python module to the package")?; @@ -646,9 +652,10 @@ pub fn write_cffi_module( File::create(base_path.join("ffi.py"))?.write_all(cffi_declarations.as_bytes())?; } - module = PathBuf::from(module_name).join(module_name); + let relative = rust_module.strip_prefix(python_module.parent().unwrap())?; + module = relative.join(extension_name); } - ProjectLayout::PureRust => module = PathBuf::from(module_name), + ProjectLayout::PureRust(_) => module = PathBuf::from(module_name), }; writer.add_directory(&module)?; @@ -690,24 +697,24 @@ pub fn write_python_part( for absolute in WalkDir::new(&python_module) { let absolute = absolute?.into_path(); - let relaitve = absolute.strip_prefix(python_module.as_ref().parent().unwrap())?; + let relative = absolute.strip_prefix(python_module.as_ref().parent().unwrap())?; // Ignore the cffi folder from develop, if any - if relaitve.starts_with(module_name.as_ref().join(&module_name)) { + if relative.starts_with(module_name.as_ref().join(&module_name)) { continue; } if absolute.is_dir() { - writer.add_directory(relaitve)?; + writer.add_directory(relative)?; } else { // Ignore native libraries from develop, if any - if let Some(extension) = relaitve.extension() { + if let Some(extension) = relative.extension() { if extension.to_string_lossy() == "so" { continue; } } writer - .add_file(relaitve, &absolute) + .add_file(relative, &absolute) .context(format!("File to add file from {}", absolute.display()))?; } } diff --git a/test-crates/pyo3-mixed-submodule/Cargo.lock b/test-crates/pyo3-mixed-submodule/Cargo.lock new file mode 100644 index 000000000..fb612d00b --- /dev/null +++ b/test-crates/pyo3-mixed-submodule/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.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d" +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.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" + +[[package]] +name = "lock_api" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" +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.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +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-mixed-submodule" +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.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" +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-mixed-submodule/Cargo.toml b/test-crates/pyo3-mixed-submodule/Cargo.toml new file mode 100644 index 000000000..18defc4e2 --- /dev/null +++ b/test-crates/pyo3-mixed-submodule/Cargo.toml @@ -0,0 +1,21 @@ +[package] +authors = ["konstin "] +name = "pyo3-mixed-submodule" +version = "2.1.3" +description = "Implements a dummy function combining rust and python" +readme = "Readme.md" +edition = "2018" + +[package.metadata.maturin] +name = "pyo3_mixed_submodule.rust_module.rust" +classifier = [ + "Programming Language :: Python", + "Programming Language :: Rust" +] + +[dependencies] +pyo3 = { version = "0.13.2", features = ["extension-module"] } + +[lib] +name = "pyo3_mixed_submodule" +crate-type = ["cdylib"] diff --git a/test-crates/pyo3-mixed-submodule/Readme.md b/test-crates/pyo3-mixed-submodule/Readme.md new file mode 100644 index 000000000..5cd1839da --- /dev/null +++ b/test-crates/pyo3-mixed-submodule/Readme.md @@ -0,0 +1,30 @@ +# pyo3-mixed-submodule + +A package for testing maturin with a mixed pyo3/python project with Rust submodule. + +## Usage + +```bash +pip install . +``` + +```python +import pyo3_mixed_submodule +assert pyo3_mixed_submodule.get_42() == 42 +``` + +## Testing + +Install tox: + +```bash +pip install tox +``` + +Run it: + +```bash +tox +``` + +The tests are in `test_pyo3_mixed_submodule.py`, while the configuration is in tox.ini diff --git a/test-crates/pyo3-mixed-submodule/check_installed/check_installed.py b/test-crates/pyo3-mixed-submodule/check_installed/check_installed.py new file mode 100755 index 000000000..a69749daf --- /dev/null +++ b/test-crates/pyo3-mixed-submodule/check_installed/check_installed.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +import pyo3_mixed_submodule + +assert pyo3_mixed_submodule.get_42() == 42 + +print("SUCCESS") diff --git a/test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/__init__.py b/test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/__init__.py new file mode 100644 index 000000000..003f027bb --- /dev/null +++ b/test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/__init__.py @@ -0,0 +1,6 @@ +from .python_module.double import double +from .rust_module.rust import get_21 + + +def get_42() -> int: + return double(get_21) diff --git a/test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/python_module/__init__.py b/test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/python_module/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/python_module/double.py b/test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/python_module/double.py new file mode 100644 index 000000000..2eed18d52 --- /dev/null +++ b/test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/python_module/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-mixed-submodule/pyo3_mixed_submodule/rust_module/__init__.py b/test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/rust_module/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/test-crates/pyo3-mixed-submodule/pyproject.toml b/test-crates/pyo3-mixed-submodule/pyproject.toml new file mode 100644 index 000000000..9a2f56d97 --- /dev/null +++ b/test-crates/pyo3-mixed-submodule/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["maturin>=0.10,<0.11"] +build-backend = "maturin" diff --git a/test-crates/pyo3-mixed-submodule/src/lib.rs b/test-crates/pyo3-mixed-submodule/src/lib.rs new file mode 100644 index 000000000..217130861 --- /dev/null +++ b/test-crates/pyo3-mixed-submodule/src/lib.rs @@ -0,0 +1,14 @@ +use pyo3::prelude::*; +use pyo3::wrap_pyfunction; + +#[pyfunction] +fn get_21() -> usize { + 21 +} + +#[pymodule] +fn rust(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_wrapped(wrap_pyfunction!(get_21))?; + + Ok(()) +} diff --git a/test-crates/pyo3-mixed-submodule/test_pyo3_mixed_submodule.py b/test-crates/pyo3-mixed-submodule/test_pyo3_mixed_submodule.py new file mode 100644 index 000000000..19bab7421 --- /dev/null +++ b/test-crates/pyo3-mixed-submodule/test_pyo3_mixed_submodule.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +import pyo3_mixed_submodule + + +def test_get_42(): + assert pyo3_mixed_submodule.get_42() == 42 diff --git a/test-crates/pyo3-mixed-submodule/tox.ini b/test-crates/pyo3-mixed-submodule/tox.ini new file mode 100644 index 000000000..fd19ca2b2 --- /dev/null +++ b/test-crates/pyo3-mixed-submodule/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/test-dockerfile.sh b/test-dockerfile.sh index 77ec0558a..a5363229e 100755 --- a/test-dockerfile.sh +++ b/test-dockerfile.sh @@ -53,4 +53,12 @@ if [[ $(venv-docker/bin/python test-crates/pyo3-mixed/check_installed/check_inst exit 1 fi +docker run -e RUST_BACKTRACE=1 --rm -v $(pwd)/test-crates/pyo3-mixed-submodule:/io maturin build --no-sdist -i python3.8 + +venv-docker/bin/pip install pyo3-mixed-submodule --find-links test-crates/pyo3-mixed-submodule/target/wheels/ + +if [[ $(venv-docker/bin/python test-crates/pyo3-mixed-submodule/check_installed/check_installed.py) != 'SUCCESS' ]]; then + exit 1 +fi + deactivate diff --git a/tests/run.rs b/tests/run.rs index 1c867390d..c3b31549a 100644 --- a/tests/run.rs +++ b/tests/run.rs @@ -14,6 +14,14 @@ fn develop_pyo3_mixed() { handle_result(develop::test_develop("test-crates/pyo3-mixed", None)); } +#[test] +fn develop_pyo3_mixed_submodule() { + handle_result(develop::test_develop( + "test-crates/pyo3-mixed-submodule", + None, + )); +} + #[test] fn develop_cffi_pure() { handle_result(develop::test_develop("test-crates/cffi-pure", None)); @@ -42,6 +50,14 @@ fn integration_pyo3_mixed() { )); } +#[test] +fn integration_pyo3_mixed_submodule() { + handle_result(integration::test_integration( + "test-crates/pyo3-mixed-submodule", + None, + )); +} + #[cfg(target_os = "windows")] #[test] #[ignore]