Skip to content

Commit 7030341

Browse files
authored
fix: normalize extra names in optional dependencies (#50)
* fix: normalize extra names in optional dependencies * fix: some comments * fix: change test a bit
1 parent 4314a07 commit 7030341

File tree

1 file changed

+53
-2
lines changed

1 file changed

+53
-2
lines changed

src/resolution.rs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
use crate::{DependencyGroupSpecifier, DependencyGroups, ResolvedDependencies};
22
use indexmap::IndexMap;
3-
use pep508_rs::Requirement;
3+
use pep508_rs::{ExtraName, Requirement};
44
use std::fmt::Display;
5+
use std::str::FromStr;
56
use thiserror::Error;
67

8+
/// Normalize a group/extra name according to PEP 685.
9+
fn normalize_name(name: &str) -> String {
10+
ExtraName::from_str(name)
11+
.map(|extra| extra.to_string())
12+
.unwrap_or_else(|_| name.to_string())
13+
}
14+
715
#[derive(Debug, Error)]
816
#[error(transparent)]
917
pub struct ResolveError(#[from] ResolveErrorKind);
@@ -105,7 +113,16 @@ fn resolve_optional_dependency(
105113
return Ok(requirements.clone());
106114
}
107115

108-
let Some(unresolved_requirements) = optional_dependencies.get(extra) else {
116+
let normalized_extra = normalize_name(extra);
117+
118+
// Find the key in optional_dependencies by comparing normalized versions
119+
// TODO: next breaking release remove this once Extra is added
120+
let unresolved_requirements = optional_dependencies
121+
.iter()
122+
.find(|(key, _)| normalize_name(key) == normalized_extra)
123+
.map(|(_, reqs)| reqs);
124+
125+
let Some(unresolved_requirements) = unresolved_requirements else {
109126
let parent = parents
110127
.iter()
111128
.last()
@@ -460,4 +477,38 @@ mod tests {
460477
vec![Requirement::from_str("numpy").unwrap()]
461478
);
462479
}
480+
481+
#[test]
482+
fn optional_dependencies_with_underscores() {
483+
// Test that optional dependency group names with underscores are normalized
484+
// when referenced in extras. PEP 685 specifies that extras should be normalized
485+
// by replacing _, ., - with a single -.
486+
let source = r#"
487+
[project]
488+
name = "foo"
489+
490+
[project.optional-dependencies]
491+
all = [
492+
"foo[group-one]",
493+
"foo[group_two]",
494+
]
495+
group_one = [
496+
"anyio>=4.9.0",
497+
]
498+
group-two = [
499+
"trio>=0.31.0",
500+
]
501+
"#;
502+
let pyproject_toml = PyProjectToml::new(source).unwrap();
503+
let resolved_dependencies = pyproject_toml.resolve().unwrap();
504+
505+
// Both group-one and group_two should resolve correctly
506+
assert_eq!(
507+
resolved_dependencies.optional_dependencies["all"],
508+
vec![
509+
Requirement::from_str("anyio>=4.9.0").unwrap(),
510+
Requirement::from_str("trio>=0.31.0").unwrap(),
511+
]
512+
);
513+
}
463514
}

0 commit comments

Comments
 (0)