From 1b3641128fb0475a2f62b00e5c218c7efdd7fd9d Mon Sep 17 00:00:00 2001 From: messense Date: Fri, 7 Oct 2022 12:17:24 +0800 Subject: [PATCH] Add support for python first `src` project layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ``` my-project ├── Readme.md ├── pyproject.toml ├── src │ └── my_project │ ├── __init__.py │ └── bar.py └── rust ├── Cargo.toml └── src └── lib.rs ``` --- Changelog.md | 5 +- src/module_writer.rs | 26 +- src/project_layout.rs | 48 ++- src/pyproject_toml.rs | 5 + test-crates/pyo3-mixed-src/README.md | 14 + .../check_installed/check_installed.py | 7 + test-crates/pyo3-mixed-src/pyproject.toml | 14 + test-crates/pyo3-mixed-src/rust/Cargo.lock | 275 ++++++++++++++++++ test-crates/pyo3-mixed-src/rust/Cargo.toml | 13 + test-crates/pyo3-mixed-src/rust/src/lib.rs | 13 + .../src/pyo3_mixed_src/__init__.py | 6 + .../pyo3_mixed_src/python_module/__init__.py | 0 .../pyo3_mixed_src/python_module/double.py | 5 + .../src/tests/test_pyo3_mixed.py | 7 + test-crates/pyo3-mixed-src/tox.ini | 7 + tests/common/develop.rs | 9 +- tests/common/editable.rs | 2 +- tests/common/integration.rs | 18 +- tests/common/mod.rs | 25 +- tests/run.rs | 61 ++-- 20 files changed, 493 insertions(+), 67 deletions(-) create mode 100644 test-crates/pyo3-mixed-src/README.md create mode 100755 test-crates/pyo3-mixed-src/check_installed/check_installed.py create mode 100644 test-crates/pyo3-mixed-src/pyproject.toml create mode 100644 test-crates/pyo3-mixed-src/rust/Cargo.lock create mode 100644 test-crates/pyo3-mixed-src/rust/Cargo.toml create mode 100644 test-crates/pyo3-mixed-src/rust/src/lib.rs create mode 100644 test-crates/pyo3-mixed-src/src/pyo3_mixed_src/__init__.py create mode 100644 test-crates/pyo3-mixed-src/src/pyo3_mixed_src/python_module/__init__.py create mode 100644 test-crates/pyo3-mixed-src/src/pyo3_mixed_src/python_module/double.py create mode 100644 test-crates/pyo3-mixed-src/src/tests/test_pyo3_mixed.py create mode 100644 test-crates/pyo3-mixed-src/tox.ini diff --git a/Changelog.md b/Changelog.md index 4bcc6f245..c22a5c4f8 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,7 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - * Initial support for shipping bin targets as wasm32-wasi binaries that are run through wasmtime in [#1107](https://github.com/PyO3/maturin/pull/1107). Note that wasmtime currently only support the five most popular platforms and that wasi binaries have restrictions when interacting with the host. Usage is by setting `--target wasm32-wasi`. + * Initial support for shipping bin targets as wasm32-wasi binaries that are run through wasmtime in [#1107](https://github.com/PyO3/maturin/pull/1107). + Note that wasmtime currently only support the five most popular platforms and that wasi binaries have restrictions when interacting with the host. + Usage is by setting `--target wasm32-wasi`. + * Add support for python first `src` project layout in [#1185](https://github.com/PyO3/maturin/pull/1185) ## [0.13.6] - 2022-10-08 diff --git a/src/module_writer.rs b/src/module_writer.rs index 73b9280fe..1082b5255 100644 --- a/src/module_writer.rs +++ b/src/module_writer.rs @@ -47,10 +47,6 @@ pub trait ModuleWriter { /// Copies the source file to the target path relative to the module base path fn add_file(&mut self, target: impl AsRef, source: impl AsRef) -> Result<()> { - let target = target.as_ref(); - let source = source.as_ref(); - debug!("Adding {} from {}", target.display(), source.display()); - self.add_file_with_permissions(target, source, 0o644) } @@ -62,12 +58,16 @@ pub trait ModuleWriter { source: impl AsRef, permissions: u32, ) -> Result<()> { - let read_failed_context = format!("Failed to read {}", source.as_ref().display()); - let mut file = File::open(source.as_ref()).context(read_failed_context.clone())?; + let target = target.as_ref(); + let source = source.as_ref(); + debug!("Adding {} from {}", target.display(), source.display()); + + let read_failed_context = format!("Failed to read {}", source.display()); + let mut file = File::open(source).context(read_failed_context.clone())?; let mut buffer = Vec::new(); file.read_to_end(&mut buffer).context(read_failed_context)?; - self.add_bytes_with_permissions(target.as_ref(), &buffer, permissions) - .context(format!("Failed to write to {}", target.as_ref().display()))?; + self.add_bytes_with_permissions(target, &buffer, permissions) + .context(format!("Failed to write to {}", target.display()))?; Ok(()) } } @@ -640,11 +640,6 @@ pub fn write_bindings_module( }; if let Some(python_module) = &project_layout.python_module { - if !editable { - write_python_part(writer, python_module) - .context("Failed to add the python module to the package")?; - } - if editable { let target = project_layout.rust_module.join(&so_filename); // Remove existing so file to avoid triggering SIGSEV in running process @@ -658,9 +653,10 @@ pub fn write_bindings_module( artifact.display(), target.display() ))?; - } + } else { + write_python_part(writer, python_module) + .context("Failed to add the python module to the package")?; - if !editable { let relative = project_layout .rust_module .strip_prefix(python_module.parent().unwrap())?; diff --git a/src/project_layout.rs b/src/project_layout.rs index 9c87f380f..7264487a7 100644 --- a/src/project_layout.rs +++ b/src/project_layout.rs @@ -63,6 +63,10 @@ impl ProjectResolver { manifest_file.display() ); } + + // Set Cargo manifest path + cargo_options.manifest_path = Some(manifest_file.clone()); + let cargo_toml = CargoToml::from_path(&manifest_file)?; cargo_toml.warn_deprecated_python_metadata(); @@ -123,7 +127,18 @@ impl ProjectResolver { Some(py_src) => py_src.to_path_buf(), None => match extra_metadata.python_source.as_ref() { Some(py_src) => manifest_dir.join(py_src), - None => project_root.to_path_buf(), + None => match pyproject.and_then(|x| x.project_name()) { + Some(project_name) => { + // Detect src layout + let import_name = project_name.replace('-', "_"); + if project_root.join("src").join(import_name).is_dir() { + project_root.join("src") + } else { + project_root.to_path_buf() + } + } + None => project_root.to_path_buf(), + }, }, }; let data = match pyproject.and_then(|x| x.data()) { @@ -166,8 +181,10 @@ impl ProjectResolver { // use command line argument if specified if let Some(path) = cargo_manifest_path { let workspace_root = Self::resolve_cargo_metadata(&path, cargo_options)?.workspace_root; + let workspace_parent = workspace_root.parent().unwrap_or(&workspace_root); for parent in fs::canonicalize(&path)?.ancestors().skip(1) { - if !parent.starts_with(&workspace_root) { + // Allow looking outside to the parent directory of Cargo workspace root + if !dunce::simplified(parent).starts_with(&workspace_parent) { break; } let pyproject_file = parent.join(PYPROJECT_TOML); @@ -196,6 +213,33 @@ impl ProjectResolver { bail!("Cargo.toml can not be placed outside of the directory containing pyproject.toml"); } return Ok((path.to_path_buf(), pyproject_file)); + } else { + // Detect src layout: + // + // my-project + // ├── Readme.md + // ├── pyproject.toml + // ├── src + // │ └── my_project + // │ ├── __init__.py + // │ └── bar.py + // └── rust + // ├── Cargo.toml + // └── src + // └── lib.rs + let path = current_dir.join("rust").join("Cargo.toml"); + if path.exists() { + if pyproject.python_source().is_some() { + // python source directory is specified in pyproject.toml + return Ok((path, pyproject_file)); + } else if let Some(project_name) = pyproject.project_name() { + // Check if python source directory in `src/` + let import_name = project_name.replace('-', "_"); + if current_dir.join("src").join(import_name).is_dir() { + return Ok((path, pyproject_file)); + } + } + } } } // check Cargo.toml in current directory diff --git a/src/pyproject_toml.rs b/src/pyproject_toml.rs index 573472caf..d323eb74d 100644 --- a/src/pyproject_toml.rs +++ b/src/pyproject_toml.rs @@ -86,6 +86,11 @@ impl PyProjectToml { Ok(pyproject) } + /// Returns the value of `[project.name]` in pyproject.toml + pub fn project_name(&self) -> Option<&str> { + self.project.as_ref().map(|project| project.name.as_str()) + } + /// Returns the values of `[tool.maturin]` in pyproject.toml #[inline] pub fn maturin(&self) -> Option<&ToolMaturin> { diff --git a/test-crates/pyo3-mixed-src/README.md b/test-crates/pyo3-mixed-src/README.md new file mode 100644 index 000000000..f585728bb --- /dev/null +++ b/test-crates/pyo3-mixed-src/README.md @@ -0,0 +1,14 @@ +# pyo3-mixed src layout + +A package for testing maturin with a src layout mixed pyo3/python project. + +## Usage + +```bash +pip install . +``` + +```python +import pyo3_mixed_src +assert pyo3_mixed_src.get_42() == 42 +``` diff --git a/test-crates/pyo3-mixed-src/check_installed/check_installed.py b/test-crates/pyo3-mixed-src/check_installed/check_installed.py new file mode 100755 index 000000000..7c03b5d15 --- /dev/null +++ b/test-crates/pyo3-mixed-src/check_installed/check_installed.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +import pyo3_mixed_src as pyo3_mixed + +assert pyo3_mixed.get_42() == 42 + +print("SUCCESS") diff --git a/test-crates/pyo3-mixed-src/pyproject.toml b/test-crates/pyo3-mixed-src/pyproject.toml new file mode 100644 index 000000000..f554654c3 --- /dev/null +++ b/test-crates/pyo3-mixed-src/pyproject.toml @@ -0,0 +1,14 @@ +[build-system] +requires = ["maturin>=0.13,<0.14"] +build-backend = "maturin" + +[project] +name = "pyo3-mixed-src" +classifiers = [ + "Programming Language :: Python", + "Programming Language :: Rust" +] +requires-python = ">=3.7" + +[project.scripts] +get_42 = "pyo3_mixed_src:get_42" diff --git a/test-crates/pyo3-mixed-src/rust/Cargo.lock b/test-crates/pyo3-mixed-src/rust/Cargo.lock new file mode 100644 index 000000000..cf606ece6 --- /dev/null +++ b/test-crates/pyo3-mixed-src/rust/Cargo.lock @@ -0,0 +1,275 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "indoc" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adab1eaa3408fb7f0c777a73e7465fd5656136fc93b670eb6df3c88c2c1344e3" + +[[package]] +name = "libc" +version = "0.2.134" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "proc-macro2" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pyo3" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201b6887e5576bf2f945fe65172c1fcbf3fcf285b23e4d71eb171d9736e38d32" +dependencies = [ + "cfg-if", + "indoc", + "libc", + "memoffset", + "parking_lot", + "pyo3-build-config", + "pyo3-ffi", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-build-config" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf0708c9ed01692635cbf056e286008e5a2927ab1a5e48cdd3aeb1ba5a6fef47" +dependencies = [ + "once_cell", + "python3-dll-a", + "target-lexicon", +] + +[[package]] +name = "pyo3-ffi" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90352dea4f486932b72ddf776264d293f85b79a1d214de1d023927b41461132d" +dependencies = [ + "libc", + "pyo3-build-config", +] + +[[package]] +name = "pyo3-macros" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb24b804a2d9e88bfcc480a5a6dd76f006c1e3edaf064e8250423336e2cd79d" +dependencies = [ + "proc-macro2", + "pyo3-macros-backend", + "quote", + "syn", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f22bb49f6a7348c253d7ac67a6875f2dc65f36c2ae64a82c381d528972bea6d6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pyo3-mixed-src" +version = "2.1.3" +dependencies = [ + "pyo3", +] + +[[package]] +name = "python3-dll-a" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a915bd72824962bf190bbd3e8a044cccb695d1409f73ff5493712eda5136c7a8" +dependencies = [ + "cc", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +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.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "syn" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-lexicon" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1" + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "unindent" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58ee9362deb4a96cef4d437d1ad49cffc9b9e92d202b6995674e928ce684f112" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" diff --git a/test-crates/pyo3-mixed-src/rust/Cargo.toml b/test-crates/pyo3-mixed-src/rust/Cargo.toml new file mode 100644 index 000000000..e4a773cdb --- /dev/null +++ b/test-crates/pyo3-mixed-src/rust/Cargo.toml @@ -0,0 +1,13 @@ +[package] +authors = ["konstin "] +name = "pyo3-mixed-src" +version = "2.1.3" +description = "Implements a dummy function combining rust and python" +edition = "2018" + +[dependencies] +pyo3 = { version = "0.17.2", features = ["extension-module", "generate-import-lib"] } + +[lib] +name = "pyo3_mixed_src" +crate-type = ["cdylib"] diff --git a/test-crates/pyo3-mixed-src/rust/src/lib.rs b/test-crates/pyo3-mixed-src/rust/src/lib.rs new file mode 100644 index 000000000..b7431aee0 --- /dev/null +++ b/test-crates/pyo3-mixed-src/rust/src/lib.rs @@ -0,0 +1,13 @@ +use pyo3::prelude::*; + +#[pyfunction] +fn get_21() -> usize { + 21 +} + +#[pymodule] +fn pyo3_mixed_src(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_wrapped(wrap_pyfunction!(get_21))?; + + Ok(()) +} diff --git a/test-crates/pyo3-mixed-src/src/pyo3_mixed_src/__init__.py b/test-crates/pyo3-mixed-src/src/pyo3_mixed_src/__init__.py new file mode 100644 index 000000000..a18d674bf --- /dev/null +++ b/test-crates/pyo3-mixed-src/src/pyo3_mixed_src/__init__.py @@ -0,0 +1,6 @@ +from .python_module.double import double +from .pyo3_mixed_src import get_21 + + +def get_42() -> int: + return double(get_21) diff --git a/test-crates/pyo3-mixed-src/src/pyo3_mixed_src/python_module/__init__.py b/test-crates/pyo3-mixed-src/src/pyo3_mixed_src/python_module/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/test-crates/pyo3-mixed-src/src/pyo3_mixed_src/python_module/double.py b/test-crates/pyo3-mixed-src/src/pyo3_mixed_src/python_module/double.py new file mode 100644 index 000000000..2eed18d52 --- /dev/null +++ b/test-crates/pyo3-mixed-src/src/pyo3_mixed_src/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-src/src/tests/test_pyo3_mixed.py b/test-crates/pyo3-mixed-src/src/tests/test_pyo3_mixed.py new file mode 100644 index 000000000..b4791fee1 --- /dev/null +++ b/test-crates/pyo3-mixed-src/src/tests/test_pyo3_mixed.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +import pyo3_mixed_src as pyo3_mixed + + +def test_get_42(): + assert pyo3_mixed.get_42() == 42 diff --git a/test-crates/pyo3-mixed-src/tox.ini b/test-crates/pyo3-mixed-src/tox.ini new file mode 100644 index 000000000..a7427eacf --- /dev/null +++ b/test-crates/pyo3-mixed-src/tox.ini @@ -0,0 +1,7 @@ +[tox] +envlist = py36,py37,py38 +isolated_build = True + +[testenv] +deps = pytest +commands = pytest src/tests/ diff --git a/tests/common/develop.rs b/tests/common/develop.rs index f2f543cd4..a2679f1cf 100644 --- a/tests/common/develop.rs +++ b/tests/common/develop.rs @@ -15,14 +15,15 @@ pub fn test_develop( ) -> Result<()> { maybe_mock_cargo(); + let package = package.as_ref(); let (venv_dir, python) = if conda { create_conda_env(&format!("maturin-{}", unique_name), 3, 10)? } else { - create_virtualenv(&package, "develop", None)? + create_virtualenv(unique_name, None)? }; // Ensure the test doesn't wrongly pass - check_installed(package.as_ref(), &python).unwrap_err(); + check_installed(package, &python).unwrap_err(); let output = Command::new(&python) .args(&["-m", "pip", "install", "cffi"]) @@ -36,7 +37,7 @@ pub fn test_develop( ); } - let manifest_file = package.as_ref().join("Cargo.toml"); + let manifest_file = package.join("Cargo.toml"); develop( bindings, CargoOptions { @@ -54,6 +55,6 @@ pub fn test_develop( vec![], )?; - check_installed(package.as_ref(), &python)?; + check_installed(package, &python)?; Ok(()) } diff --git a/tests/common/editable.rs b/tests/common/editable.rs index d69cc55e2..6f460f008 100644 --- a/tests/common/editable.rs +++ b/tests/common/editable.rs @@ -16,7 +16,7 @@ pub fn test_editable( let package_string = package.as_ref().join("Cargo.toml").display().to_string(); - let (venv_dir, python) = create_virtualenv(&package, "editable", None)?; + let (venv_dir, python) = create_virtualenv(unique_name, None)?; let interpreter = python.to_str().expect("invalid interpreter path"); let target_dir = format!("test-crates/targets/{}", unique_name); let wheel_dir = format!("test-crates/wheels/{}", unique_name); diff --git a/tests/common/integration.rs b/tests/common/integration.rs index 4a9418fdd..a9f01b44e 100644 --- a/tests/common/integration.rs +++ b/tests/common/integration.rs @@ -90,19 +90,19 @@ pub fn test_integration( }; assert!(filename.to_string_lossy().ends_with(file_suffix)) } - let mut venv_suffix = if supported_version == "py3" { - "py3".to_string() + let mut venv_name = if supported_version == "py3" { + format!("{}-py3", unique_name) } else { - format!("{}.{}", python_interpreter.major, python_interpreter.minor,) + format!( + "{}-py{}.{}", + unique_name, python_interpreter.major, python_interpreter.minor, + ) }; if let Some(target) = target { - venv_suffix = format!("{}-{}", venv_suffix, target); + venv_name = format!("{}-{}", venv_name, target); } - let (venv_dir, python) = create_virtualenv( - &package, - &venv_suffix, - Some(python_interpreter.executable.clone()), - )?; + let (venv_dir, python) = + create_virtualenv(&venv_name, Some(python_interpreter.executable.clone()))?; let command = [ "-m", diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 9a35b3480..95e64b8d6 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -21,9 +21,16 @@ pub fn check_installed(package: &Path, python: &Path) -> Result<()> { } else { python.parent().unwrap().to_path_buf() }; - let check_installed = Path::new(package) + let mut check_installed = Path::new(package) .join("check_installed") .join("check_installed.py"); + if !check_installed.is_file() { + check_installed = Path::new(package) + .parent() + .unwrap() + .join("check_installed") + .join("check_installed.py"); + } let output = Command::new(&python) .arg(check_installed) .env("PATH", path) @@ -85,22 +92,10 @@ pub fn handle_result(result: Result) -> T { } /// Create virtualenv -pub fn create_virtualenv( - package: impl AsRef, - venv_suffix: &str, - python_interp: Option, -) -> Result<(PathBuf, PathBuf)> { - let test_name = package - .as_ref() - .file_name() - .unwrap() - .to_str() - .unwrap() - .to_string(); - +pub fn create_virtualenv(name: &str, python_interp: Option) -> Result<(PathBuf, PathBuf)> { let venv_dir = fs::canonicalize(PathBuf::from("test-crates"))? .join("venvs") - .join(format!("{}-{}", test_name, venv_suffix)); + .join(name); let target = Target::from_target_triple(None)?; if venv_dir.is_dir() { diff --git a/tests/run.rs b/tests/run.rs index 205c85283..d3da8ec0e 100644 --- a/tests/run.rs +++ b/tests/run.rs @@ -22,7 +22,7 @@ fn develop_pyo3_pure_conda() { handle_result(develop::test_develop( "test-crates/pyo3-pure", None, - "develop-pyo3-pure", + "develop-pyo3-pure-conda", true, )); } @@ -58,6 +58,16 @@ fn develop_pyo3_mixed_py_subdir() { )); } +#[test] +fn develop_pyo3_mixed_src_layout() { + handle_result(develop::test_develop( + "test-crates/pyo3-mixed-src/rust", + None, + "develop-pyo3-mixed-src", + false, + )); +} + #[test] fn develop_cffi_pure() { handle_result(develop::test_develop( @@ -103,7 +113,7 @@ fn editable_pyo3_pure() { handle_result(editable::test_editable( "test-crates/pyo3-pure", None, - "editable_pyo3_pure", + "editable-pyo3-pure", )); } @@ -112,7 +122,7 @@ fn editable_pyo3_mixed() { handle_result(editable::test_editable( "test-crates/pyo3-mixed", None, - "editable_pyo3_mixed", + "editable-pyo3-mixed", )); } @@ -121,7 +131,7 @@ fn editable_pyo3_mixed_py_subdir() { handle_result(editable::test_editable( "test-crates/pyo3-mixed-py-subdir", None, - "editable_pyo3_mixed_py_subdir", + "editable-pyo3-mixed-py-subdir", )); } @@ -130,7 +140,7 @@ fn editable_pyo3_ffi_pure() { handle_result(editable::test_editable( "test-crates/pyo3-ffi-pure", None, - "editable_pyo3_ffi_pure", + "editable-pyo3-ffi-pure", )); } @@ -139,7 +149,7 @@ fn integration_pyo3_bin() { handle_result(integration::test_integration( "test-crates/pyo3-bin", None, - "integration_pyo3_bin", + "integration-pyo3-bin", false, None, )); @@ -150,7 +160,7 @@ fn integration_pyo3_pure() { handle_result(integration::test_integration( "test-crates/pyo3-pure", None, - "integration_pyo3_pure", + "integration-pyo3-pure", false, None, )); @@ -161,7 +171,7 @@ fn integration_pyo3_mixed() { handle_result(integration::test_integration( "test-crates/pyo3-mixed", None, - "integration_pyo3_mixed", + "integration-pyo3-mixed", false, None, )); @@ -172,7 +182,7 @@ fn integration_pyo3_mixed_submodule() { handle_result(integration::test_integration( "test-crates/pyo3-mixed-submodule", None, - "integration_pyo3_mixed_submodule", + "integration-pyo3-mixed-submodule", false, None, )); @@ -183,12 +193,23 @@ fn integration_pyo3_mixed_py_subdir() { handle_result(integration::test_integration( "test-crates/pyo3-mixed-py-subdir", None, - "integration_pyo3_mixed_py_subdir", + "integration-pyo3-mixed-py-subdir", cfg!(unix), None, )); } +#[test] +fn integration_pyo3_mixed_src_layout() { + handle_result(integration::test_integration( + "test-crates/pyo3-mixed-src/rust", + None, + "integration-pyo3-mixed-src", + false, + None, + )); +} + #[test] fn integration_pyo3_pure_conda() { // Only run on GitHub Actions for now @@ -205,7 +226,7 @@ fn integration_cffi_pure() { handle_result(integration::test_integration( "test-crates/cffi-pure", None, - "integration_cffi_pure", + "integration-cffi-pure", false, None, )); @@ -216,7 +237,7 @@ fn integration_cffi_mixed() { handle_result(integration::test_integration( "test-crates/cffi-mixed", None, - "integration_cffi_mixed", + "integration-cffi-mixed", false, None, )); @@ -227,7 +248,7 @@ fn integration_hello_world() { handle_result(integration::test_integration( "test-crates/hello-world", None, - "integration_hello_world", + "integration-hello-world", false, None, )); @@ -238,7 +259,7 @@ fn integration_pyo3_ffi_pure() { handle_result(integration::test_integration( "test-crates/pyo3-ffi-pure", None, - "integration_pyo3_ffi_pure", + "integration-pyo3-ffi-pure", false, None, )); @@ -249,7 +270,7 @@ fn integration_with_data() { handle_result(integration::test_integration( "test-crates/with-data", None, - "integration_with_data", + "integration-with-data", false, None, )); @@ -274,7 +295,7 @@ fn integration_wasm_hello_world() { handle_result(integration::test_integration( "test-crates/hello-world", None, - "integration_wasm_hello_world", + "integration-wasm-hello-world", false, Some("wasm32-wasi"), )); @@ -282,7 +303,7 @@ fn integration_wasm_hello_world() { // Make sure we're actually running wasm assert!(Path::new("test-crates") .join("venvs") - .join("hello-world-py3-wasm32-wasi") + .join("integration-wasm-hello-world-py3-wasm32-wasi") .join(if cfg!(target_os = "windows") { "Scripts" } else { @@ -343,7 +364,7 @@ fn lib_with_path_dep_sdist() { "sdist_with_path_dep-0.1.0/src/lib.rs", "sdist_with_path_dep-0.1.0/PKG-INFO", ], - "lib_with_path_dep_sdist", + "sdist-lib-with-path-dep", )) } @@ -361,7 +382,7 @@ fn workspace_with_path_dep_sdist() { "workspace_with_path_dep-0.1.0/src/lib.rs", "workspace_with_path_dep-0.1.0/PKG-INFO", ], - "workspace_with_path_dep_sdist", + "sdist-workspace-with-path-dep", )) } @@ -378,7 +399,7 @@ fn workspace_inheritance_sdist() { "workspace_inheritance-0.1.0/src/lib.rs", "workspace_inheritance-0.1.0/PKG-INFO", ], - "workspace_inheritance_sdist", + "sdist-workspace-inheritance", )) }