Parse editable installs (#564)

Parse `-e` for editable installs in `requirements.txt`.

Unlike all the other requirements, editable installs don't have the name
of the package specified.
This commit is contained in:
konsti 2023-12-06 18:21:15 +01:00 committed by GitHub
parent 3f4d7b7826
commit 366c389385
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 153 additions and 7 deletions

View file

@ -24,6 +24,7 @@ serde = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }
unscanny = { workspace = true }
url = { workspace = true }
[dev-dependencies]
anyhow = { version = "1.0.75" }

View file

@ -10,7 +10,6 @@
//! * `-e`
//!
//! Unsupported:
//! * `-e <path>`. TBD
//! * `<path>`. TBD
//! * `<archive_url>`. TBD
//! * Options without a requirement, such as `--find-links` or `--index-url`
@ -44,6 +43,7 @@ use fs_err as fs;
use serde::{Deserialize, Serialize};
use tracing::warn;
use unscanny::{Pattern, Scanner};
use url::Url;
use pep508_rs::{Pep508Error, Requirement};
@ -63,6 +63,14 @@ enum RequirementsTxtStatement {
},
/// PEP 508 requirement plus metadata
RequirementEntry(RequirementEntry),
/// `-e`
EditableRequirement(EditableRequirement),
}
#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Serialize)]
pub enum EditableRequirement {
Path(PathBuf),
Url(Url),
}
/// A [Requirement] with additional metadata from the requirements.txt, currently only hashes but in
@ -97,6 +105,8 @@ pub struct RequirementsTxt {
pub requirements: Vec<RequirementEntry>,
/// Constraints included with `-c`
pub constraints: Vec<Requirement>,
/// Editables with `-e`
pub editable: Vec<EditableRequirement>,
}
impl RequirementsTxt {
@ -182,6 +192,9 @@ impl RequirementsTxt {
RequirementsTxtStatement::RequirementEntry(requirement_entry) => {
data.requirements.push(requirement_entry);
}
RequirementsTxtStatement::EditableRequirement(editable) => {
data.editable.push(editable);
}
}
}
Ok(data)
@ -230,12 +243,13 @@ fn parse_entry(
end,
}
} else if s.eat_if("-e") {
let (requirement, hashes) = parse_requirement_and_hashes(s, content)?;
RequirementsTxtStatement::RequirementEntry(RequirementEntry {
requirement,
hashes,
editable: true,
})
let path_or_url = parse_value(s, |c: char| !['\n', '\r'].contains(&c))?;
let editable_requirement = if let Ok(url) = Url::from_str(path_or_url) {
EditableRequirement::Url(url)
} else {
EditableRequirement::Path(PathBuf::from(path_or_url))
};
RequirementsTxtStatement::EditableRequirement(editable_requirement)
} else if s.at(char::is_ascii_alphanumeric) {
let (requirement, hashes) = parse_requirement_and_hashes(s, content)?;
RequirementsTxtStatement::RequirementEntry(RequirementEntry {
@ -505,6 +519,7 @@ mod test {
#[test_case(Path::new("poetry-with-hashes.txt"))]
#[test_case(Path::new("small.txt"))]
#[test_case(Path::new("whitespace.txt"))]
#[test_case(Path::new("editable.txt"))]
fn line_endings(path: &Path) {
let working_dir = workspace_test_data_dir().join("requirements-txt");
let requirements_txt = working_dir.join(path);
@ -581,4 +596,28 @@ mod test {
fn workspace_test_data_dir() -> PathBuf {
PathBuf::from("./test-data")
}
#[test]
fn invalid_editable() {
let working_dir = workspace_test_data_dir().join("requirements-txt");
let basic = working_dir.join("invalid-requirement");
let err = RequirementsTxt::parse(&basic, &working_dir).unwrap_err();
let errors = anyhow::Error::new(err)
.chain()
.map(ToString::to_string)
.collect::<Vec<_>>();
let expected = &[
format!(
"Couldn't parse requirement in {} position 0 to 15",
basic.display()
),
indoc! {"
Expected an alphanumeric character starting the extra name, found 'ö'
numpy[ö]==1.29
^"
}
.to_string(),
];
assert_eq!(errors, expected);
}
}

View file

@ -208,4 +208,5 @@ RequirementsTxt {
},
],
constraints: [],
editable: [],
}

View file

@ -99,4 +99,5 @@ RequirementsTxt {
marker: None,
},
],
editable: [],
}

View file

@ -73,4 +73,5 @@ RequirementsTxt {
},
],
constraints: [],
editable: [],
}

View file

@ -0,0 +1,58 @@
---
source: crates/requirements-txt/src/lib.rs
expression: actual
---
RequirementsTxt {
requirements: [
RequirementEntry {
requirement: Requirement {
name: PackageName(
"numpy",
),
extras: None,
version_or_url: None,
marker: None,
},
hashes: [],
editable: false,
},
RequirementEntry {
requirement: Requirement {
name: PackageName(
"pandas",
),
extras: Some(
[
ExtraName(
"tabulate",
),
],
),
version_or_url: Some(
Url(
Url {
scheme: "https",
cannot_be_a_base: false,
username: "",
password: None,
host: Some(
Domain(
"github.com",
),
),
port: None,
path: "/pandas-dev/pandas",
query: None,
fragment: None,
},
),
),
marker: None,
},
hashes: [],
editable: false,
},
],
constraints: [],
editable: [],
}

View file

@ -5,4 +5,5 @@ expression: actual
RequirementsTxt {
requirements: [],
constraints: [],
editable: [],
}

View file

@ -136,4 +136,5 @@ RequirementsTxt {
},
],
constraints: [],
editable: [],
}

View file

@ -52,4 +52,5 @@ RequirementsTxt {
},
],
constraints: [],
editable: [],
}

View file

@ -18,4 +18,5 @@ RequirementsTxt {
},
],
constraints: [],
editable: [],
}

View file

@ -336,4 +336,5 @@ RequirementsTxt {
},
],
constraints: [],
editable: [],
}

View file

@ -74,4 +74,5 @@ RequirementsTxt {
},
],
constraints: [],
editable: [],
}

View file

@ -54,4 +54,5 @@ RequirementsTxt {
},
],
constraints: [],
editable: [],
}

View file

@ -208,4 +208,5 @@ RequirementsTxt {
},
],
constraints: [],
editable: [],
}

View file

@ -99,4 +99,5 @@ RequirementsTxt {
marker: None,
},
],
editable: [],
}

View file

@ -73,4 +73,5 @@ RequirementsTxt {
},
],
constraints: [],
editable: [],
}

View file

@ -5,4 +5,5 @@ expression: actual
RequirementsTxt {
requirements: [],
constraints: [],
editable: [],
}

View file

@ -136,4 +136,5 @@ RequirementsTxt {
},
],
constraints: [],
editable: [],
}

View file

@ -52,4 +52,5 @@ RequirementsTxt {
},
],
constraints: [],
editable: [],
}

View file

@ -18,4 +18,5 @@ RequirementsTxt {
},
],
constraints: [],
editable: [],
}

View file

@ -336,4 +336,5 @@ RequirementsTxt {
},
],
constraints: [],
editable: [],
}

View file

@ -74,4 +74,5 @@ RequirementsTxt {
},
],
constraints: [],
editable: [],
}

View file

@ -54,4 +54,5 @@ RequirementsTxt {
},
],
constraints: [],
editable: [],
}

View file

@ -0,0 +1,25 @@
# #
# #
# #
# #
# #
# #
# #
##
#
numpy # #
\
pandas [tabulate] @ https://github.com/pandas-dev/pandas \
# üh
#
# 안녕
#

View file

@ -0,0 +1 @@
numpy[ö]==1.29