Skip to content

Commit

Permalink
Replace package.metadata.maturin.name with `tool.maturin.module-nam…
Browse files Browse the repository at this point in the history
…e` in `pyproject.toml`
  • Loading branch information
messense committed Mar 25, 2023
1 parent 5b0d9cd commit 1332779
Show file tree
Hide file tree
Showing 10 changed files with 29 additions and 115 deletions.
8 changes: 5 additions & 3 deletions guide/src/project_layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,13 @@ my-rust-and-python-project
```
#### Import Rust as a submodule of your project

If the Python module created by Rust has the same name as the Python package in a mixed Rust/Python project, IDEs might get confused. You might also want to discourage end users from using the Rust functions directly by giving it a different name, say '\_my_project'. This can be done by adding `name = <package name>.<rust pymodule name>` to the `[package.metadata.maturin]` in your `Cargo.toml`. For example:
If the Python module created by Rust has the same name as the Python package in a mixed Rust/Python project, IDEs might get confused.
You might also want to discourage end users from using the Rust functions directly by giving it a different name, say '\_my_project'.
This can be done by adding `module-name = <package name>.<rust pymodule name>` to the `[tool.maturin]` in your `pyproject.toml`. For example:

```toml
[package.metadata.maturin]
name = "my_project._my_project"
[tool.maturin]
module-name = "my_project._my_project"
```

You can then import your Rust module inside your Python source as follows:
Expand Down
8 changes: 2 additions & 6 deletions src/build_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ impl BuildOptions {
bail!(
"The module name must not contain a minus `-` \
(Make sure you have set an appropriate [lib] name or \
[package.metadata.maturin] name in your Cargo.toml)"
[tool.maturin] name in your pyproject.toml)"
);
}

Expand Down Expand Up @@ -1497,18 +1497,14 @@ mod test {

#[test]
fn test_get_min_python_minor() {
use crate::CargoToml;

// Nothing specified
let manifest_path = "test-crates/pyo3-pure/Cargo.toml";
let cargo_toml = CargoToml::from_path(manifest_path).unwrap();
let cargo_metadata = MetadataCommand::new()
.manifest_path(manifest_path)
.exec()
.unwrap();
let metadata21 =
Metadata21::from_cargo_toml(&cargo_toml, "test-crates/pyo3-pure", &cargo_metadata)
.unwrap();
Metadata21::from_cargo_toml("test-crates/pyo3-pure", &cargo_metadata).unwrap();
assert_eq!(get_min_python_minor(&metadata21), None);
}
}
1 change: 0 additions & 1 deletion src/cargo_toml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ struct CargoTomlMetadata {
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[serde(rename_all = "kebab-case")]
pub struct RemainingCoreMetadata {
pub name: Option<String>,
/// Cargo compile targets
pub targets: Option<Vec<CargoTarget>>,
#[serde(flatten)]
Expand Down
102 changes: 8 additions & 94 deletions src/metadata.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{CargoToml, PyProjectToml};
use crate::PyProjectToml;
use anyhow::{bail, Context, Result};
use fs_err as fs;
use regex::Regex;
Expand Down Expand Up @@ -281,7 +281,6 @@ impl Metadata21 {
///
/// manifest_path must be the directory, not the file
pub fn from_cargo_toml(
cargo_toml: &CargoToml,
manifest_path: impl AsRef<Path>,
cargo_metadata: &cargo_metadata::Metadata,
) -> Result<Metadata21> {
Expand All @@ -295,8 +294,6 @@ impl Metadata21 {
None
};

let extra_metadata = cargo_toml.remaining_core_metadata();

let mut description: Option<String> = None;
let mut description_content_type: Option<String> = None;
// See https://packaging.python.org/specifications/core-metadata/#description
Expand Down Expand Up @@ -329,16 +326,7 @@ impl Metadata21 {
}
}
};
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(|| package.name.clone());
let name = package.name.clone();
let mut project_url = HashMap::new();
if let Some(repository) = package.repository.as_ref() {
project_url.insert("Source Code".to_string(), repository.clone());
Expand Down Expand Up @@ -562,16 +550,14 @@ mod test {
};

let toml_with_path = cargo_toml.replace("REPLACE_README_PATH", &readme_path);
fs::write(&manifest_path, &toml_with_path).unwrap();
fs::write(&manifest_path, toml_with_path).unwrap();

let cargo_toml_struct: CargoToml = toml::from_str(&toml_with_path).unwrap();
let cargo_metadata = MetadataCommand::new()
.manifest_path(manifest_path)
.exec()
.unwrap();

let metadata =
Metadata21::from_cargo_toml(&cargo_toml_struct, crate_path, &cargo_metadata).unwrap();
let metadata = Metadata21::from_cargo_toml(crate_path, &cargo_metadata).unwrap();

let actual = metadata.to_file_contents().unwrap();

Expand All @@ -590,13 +576,6 @@ mod test {
"cargo_toml name and version string do not match hardcoded values, test will fail",
);

if cargo_toml_struct.remaining_core_metadata().name.is_none() {
assert_eq!(
metadata.get_dist_info_dir(),
PathBuf::from("info_project-0.1.0.dist-info"),
"Dist info dir differed from expected"
);
}
metadata
}

Expand Down Expand Up @@ -648,59 +627,6 @@ mod test {
assert_metadata_from_cargo_toml(readme, cargo_toml, expected);
}

#[test]
fn test_metadata_from_cargo_toml_name_override() {
let readme = indoc!(
r#"
Some test package
=================
"#
);

let cargo_toml = indoc!(
r#"
[package]
authors = ["konstin <[email protected]>"]
name = "info-project"
version = "0.1.0"
description = "A test project"
homepage = "https://example.org"
readme = "REPLACE_README_PATH"
[lib]
crate-type = ["cdylib"]
name = "pyo3_pure"
[package.metadata.maturin]
name = "info"
"#
);

let expected = indoc!(
r#"
Metadata-Version: 2.1
Name: info
Version: 0.1.0
Summary: A test project
Home-Page: https://example.org
Author: konstin <[email protected]>
Author-email: konstin <[email protected]>
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Some test package
=================
"#
);

let metadata = assert_metadata_from_cargo_toml(readme, cargo_toml, expected);

assert_eq!(
metadata.get_dist_info_dir(),
PathBuf::from("info-0.1.0.dist-info"),
"Dist info dir differed from expected"
);
}

#[test]
fn test_path_to_content_type() {
for (filename, expected) in &[
Expand All @@ -726,14 +652,11 @@ mod test {
#[test]
fn test_merge_metadata_from_pyproject_toml() {
let manifest_dir = PathBuf::from("test-crates").join("pyo3-pure");
let cargo_toml_str = fs_err::read_to_string(manifest_dir.join("Cargo.toml")).unwrap();
let cargo_toml: CargoToml = toml::from_str(&cargo_toml_str).unwrap();
let cargo_metadata = MetadataCommand::new()
.manifest_path(manifest_dir.join("Cargo.toml"))
.exec()
.unwrap();
let mut metadata =
Metadata21::from_cargo_toml(&cargo_toml, &manifest_dir, &cargo_metadata).unwrap();
let mut metadata = Metadata21::from_cargo_toml(&manifest_dir, &cargo_metadata).unwrap();
let pyproject_toml = PyProjectToml::new(manifest_dir.join("pyproject.toml")).unwrap();
metadata
.merge_pyproject_toml(&manifest_dir, &pyproject_toml)
Expand Down Expand Up @@ -777,14 +700,11 @@ mod test {
#[test]
fn test_merge_metadata_from_pyproject_toml_with_customized_python_source_dir() {
let manifest_dir = PathBuf::from("test-crates").join("pyo3-mixed-py-subdir");
let cargo_toml_str = fs_err::read_to_string(manifest_dir.join("Cargo.toml")).unwrap();
let cargo_toml: CargoToml = toml::from_str(&cargo_toml_str).unwrap();
let cargo_metadata = MetadataCommand::new()
.manifest_path(manifest_dir.join("Cargo.toml"))
.exec()
.unwrap();
let mut metadata =
Metadata21::from_cargo_toml(&cargo_toml, &manifest_dir, &cargo_metadata).unwrap();
let mut metadata = Metadata21::from_cargo_toml(&manifest_dir, &cargo_metadata).unwrap();
let pyproject_toml = PyProjectToml::new(manifest_dir.join("pyproject.toml")).unwrap();
metadata
.merge_pyproject_toml(&manifest_dir, &pyproject_toml)
Expand All @@ -801,14 +721,11 @@ mod test {
#[test]
fn test_implicit_readme() {
let manifest_dir = PathBuf::from("test-crates").join("pyo3-mixed");
let cargo_toml_str = fs_err::read_to_string(manifest_dir.join("Cargo.toml")).unwrap();
let cargo_toml = toml::from_str(&cargo_toml_str).unwrap();
let cargo_metadata = MetadataCommand::new()
.manifest_path(manifest_dir.join("Cargo.toml"))
.exec()
.unwrap();
let metadata =
Metadata21::from_cargo_toml(&cargo_toml, &manifest_dir, &cargo_metadata).unwrap();
let metadata = Metadata21::from_cargo_toml(&manifest_dir, &cargo_metadata).unwrap();
assert!(metadata.description.unwrap().starts_with("# pyo3-mixed"));
assert_eq!(
metadata.description_content_type.unwrap(),
Expand All @@ -819,14 +736,11 @@ mod test {
#[test]
fn test_merge_metadata_from_pyproject_dynamic_license_test() {
let manifest_dir = PathBuf::from("test-crates").join("license-test");
let cargo_toml_str = fs_err::read_to_string(manifest_dir.join("Cargo.toml")).unwrap();
let cargo_toml: CargoToml = toml::from_str(&cargo_toml_str).unwrap();
let cargo_metadata = MetadataCommand::new()
.manifest_path(manifest_dir.join("Cargo.toml"))
.exec()
.unwrap();
let mut metadata =
Metadata21::from_cargo_toml(&cargo_toml, &manifest_dir, &cargo_metadata).unwrap();
let mut metadata = Metadata21::from_cargo_toml(&manifest_dir, &cargo_metadata).unwrap();
let pyproject_toml = PyProjectToml::new(manifest_dir.join("pyproject.toml")).unwrap();
metadata
.merge_pyproject_toml(&manifest_dir, &pyproject_toml)
Expand Down
8 changes: 3 additions & 5 deletions src/project_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,12 @@ impl ProjectResolver {

let cargo_metadata = Self::resolve_cargo_metadata(&manifest_file, &cargo_options)?;

let mut metadata21 =
Metadata21::from_cargo_toml(&cargo_toml, manifest_dir, &cargo_metadata)
.context("Failed to parse Cargo.toml into python metadata")?;
let mut metadata21 = Metadata21::from_cargo_toml(manifest_dir, &cargo_metadata)
.context("Failed to parse Cargo.toml into python metadata")?;
if let Some(pyproject) = pyproject {
let pyproject_dir = pyproject_file.parent().unwrap();
metadata21.merge_pyproject_toml(pyproject_dir, pyproject)?;
}
let extra_metadata = cargo_toml.remaining_core_metadata();

let crate_name = &cargo_toml.package.name;

Expand All @@ -128,7 +126,7 @@ impl ProjectResolver {
.unwrap_or(crate_name)
.to_owned();

let extension_name = extra_metadata.name.as_ref().unwrap_or(&module_name);
let extension_name = pyproject.and_then(|x| x.name()).unwrap_or(&module_name);

let project_root = if pyproject_file.is_file() {
pyproject_file.parent().unwrap_or(manifest_dir)
Expand Down
7 changes: 7 additions & 0 deletions src/pyproject_toml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ impl GlobPattern {
#[serde(rename_all = "kebab-case")]
pub struct ToolMaturin {
// maturin specific options
// extension module name, accepts setuptools style import name like `foo.bar`
module_name: Option<String>,
include: Option<Vec<GlobPattern>>,
exclude: Option<Vec<GlobPattern>>,
bindings: Option<String>,
Expand Down Expand Up @@ -170,6 +172,11 @@ impl PyProjectToml {
self.tool.as_ref()?.maturin.as_ref()
}

/// Returns the value of `[tool.maturin.name]` in pyproject.toml
pub fn name(&self) -> Option<&str> {
self.maturin()?.module_name.as_deref()
}

/// Returns the value of `[tool.maturin.include]` in pyproject.toml
pub fn include(&self) -> Option<&[GlobPattern]> {
self.maturin()?.include.as_ref().map(AsRef::as_ref)
Expand Down
3 changes: 0 additions & 3 deletions test-crates/pyo3-mixed-py-subdir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,3 @@ pyo3 = { version = "0.18.0", features = ["extension-module"] }
[lib]
name = "pyo3_mixed_py_subdir"
crate-type = ["cdylib"]

[package.metadata.maturin]
name = "pyo3_mixed_py_subdir._pyo3_mixed"
1 change: 1 addition & 0 deletions test-crates/pyo3-mixed-py-subdir/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ requires-python = ">=3.6"
get_42 = "pyo3_mixed_py_subdir:get_42"

[tool.maturin]
module-name = "pyo3_mixed_py_subdir._pyo3_mixed"
python-source = "python"
3 changes: 0 additions & 3 deletions test-crates/pyo3-mixed-submodule/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ description = "Implements a dummy function combining rust and python"
readme = "README.md"
edition = "2021"

[package.metadata.maturin]
name = "pyo3_mixed_submodule.rust_module.rust"

[dependencies]
pyo3 = { version = "0.18.0", features = ["extension-module"] }

Expand Down
3 changes: 3 additions & 0 deletions test-crates/pyo3-mixed-submodule/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ classifiers = [
"Programming Language :: Python",
"Programming Language :: Rust"
]

[tool.maturin]
module-name = "pyo3_mixed_submodule.rust_module.rust"

0 comments on commit 1332779

Please sign in to comment.