Allow file:-relative paths in editable installs (#970)

Supports editable install via (e.g.) `puffin pip install -e file:.`,
which pip seems to support.

Closes #964.
This commit is contained in:
Charlie Marsh 2024-01-18 16:15:42 -05:00 committed by GitHub
parent a24bfd5418
commit a262936366
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 30 additions and 11 deletions

View file

@ -2587,9 +2587,10 @@ fn sync_editable_and_registry() -> Result<()> {
});
// Install the editable version of Black. This should remove the registry-based version.
// Use the `file:` syntax for extra coverage.
let requirements_txt = temp_dir.child("requirements.txt");
requirements_txt.write_str(indoc::indoc! {r"
-e ../../scripts/editable-installs/black_editable
-e file:../../scripts/editable-installs/black_editable
"
})?;

View file

@ -104,11 +104,7 @@ impl FromStr for EditableRequirement {
type Err = RequirementsTxtParserError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let editable_requirement = if let Ok(url) = VerbatimUrl::from_str(s) {
ParsedEditableRequirement::Url(url)
} else {
ParsedEditableRequirement::Path(s.to_string())
};
let editable_requirement = ParsedEditableRequirement::from_str(s)?;
editable_requirement.with_working_dir(".")
}
}
@ -162,6 +158,32 @@ impl ParsedEditableRequirement {
}
}
impl FromStr for ParsedEditableRequirement {
type Err = RequirementsTxtParserError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.trim_start().starts_with("file://") {
// Ex) `file:///home/ferris/project/scripts/...`
if let Ok(url) = VerbatimUrl::from_str(s) {
Ok(ParsedEditableRequirement::Url(url))
} else {
Err(RequirementsTxtParserError::UnsupportedUrl(
VerbatimUrl::from_str(s).unwrap(),
))
}
} else if let Some(s) = s.trim_start().strip_prefix("file:") {
// Ex) `file:../editable/`
Ok(ParsedEditableRequirement::Path(s.to_string()))
} else if let Ok(url) = VerbatimUrl::from_str(s) {
// Ex) `http://example.com/`
Ok(ParsedEditableRequirement::Url(url))
} else {
// Ex) `../editable/`
Ok(ParsedEditableRequirement::Path(s.to_string()))
}
}
}
impl Display for ParsedEditableRequirement {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
@ -352,11 +374,7 @@ fn parse_entry(
}
} else if s.eat_if("-e") {
let path_or_url = parse_value(s, |c: char| !['\n', '\r'].contains(&c))?;
let editable_requirement = if let Ok(url) = VerbatimUrl::from_str(path_or_url) {
ParsedEditableRequirement::Url(url)
} else {
ParsedEditableRequirement::Path(path_or_url.to_string())
};
let editable_requirement = ParsedEditableRequirement::from_str(path_or_url)?;
RequirementsTxtStatement::EditableRequirement(editable_requirement)
} else if s.at(char::is_ascii_alphanumeric) {
let (requirement, hashes) = parse_requirement_and_hashes(s, content)?;