Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion crates/pixi_build_python/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ pub enum MetadataError {
PyProjectToml(#[from] toml::de::Error),
#[error("failed to parse version from pyproject.toml, {0}")]
ParseVersion(ParseVersionError),
#[error("`pixi-build-python` requires a `pyproject.toml` in {0}")]
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error message says "requires a pyproject.toml in {0}", but {0} is a full file path (…/pyproject.toml). Using "at {0}" (or changing {0} to be the directory) would read more clearly and avoid implying {0} is a directory.

Suggested change
#[error("`pixi-build-python` requires a `pyproject.toml` in {0}")]
#[error("`pixi-build-python` requires a `pyproject.toml` at {0}")]

Copilot uses AI. Check for mistakes.
#[diagnostic(help(
"Add a PEP 517/518 `pyproject.toml` to the package source directory, or use a different build backend."
))]
MissingPyProjectToml(PathBuf),
#[error(transparent)]
Io(#[from] std::io::Error),
}
Expand Down Expand Up @@ -72,8 +77,15 @@ impl PyprojectMetadataProvider {
/// Ensures that the manifest is loaded
fn ensure_manifest(&self) -> Result<&PyProjectToml, MetadataError> {
self.pyproject_manifest.get_or_try_init(move || {
let pyproject_toml_path = self.manifest_root.join("pyproject.toml");
let pyproject_toml_content =
fs_err::read_to_string(self.manifest_root.join("pyproject.toml"))?;
fs_err::read_to_string(&pyproject_toml_path).map_err(|err| {
if err.kind() == std::io::ErrorKind::NotFound {
MetadataError::MissingPyProjectToml(pyproject_toml_path.clone())
} else {
MetadataError::Io(err)
}
})?;
toml::from_str(&pyproject_toml_content).map_err(MetadataError::PyProjectToml)
})
}
Expand Down Expand Up @@ -750,6 +762,32 @@ version = "1.0.0"
}
}

#[test]
fn test_missing_pyproject_toml_errors_clearly() {
let temp_dir = TempDir::new().expect("Failed to create temp directory");
let mut provider = create_metadata_provider(temp_dir.path());

let err = provider
.name()
.expect_err("missing pyproject.toml should return an error");
let message = err.to_string();
let expected_path = temp_dir.path().join("pyproject.toml");

match &err {
MetadataError::MissingPyProjectToml(path) => assert_eq!(path, &expected_path),
other => panic!("Expected MissingPyProjectToml, got: {other:?}"),
}

assert!(
message.contains("requires a `pyproject.toml`"),
"unexpected error message: {message}"
);
assert!(
message.contains(&expected_path.display().to_string()),
"error should mention the manifest root: {message}"
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assertion checks that the error message contains the expected file path (.../pyproject.toml), but the failure text says "mention the manifest root". Updating the assertion message to match what’s actually being checked will make test failures less confusing.

Suggested change
"error should mention the manifest root: {message}"
"error should mention the `pyproject.toml` path: {message}"

Copilot uses AI. Check for mistakes.
);
}

#[test]
fn test_summary_equals_description() {
let pyproject_toml_content = r#"
Expand Down
Loading