mirror of
https://github.com/astral-sh/uv.git
synced 2025-09-30 14:01:13 +00:00
Move RequirementsTxtRequirement to its own module (#3235)
Small refactoring, no functional changes.
This commit is contained in:
parent
bed730571d
commit
a653670d04
2 changed files with 122 additions and 110 deletions
|
@ -46,10 +46,10 @@ use unscanny::{Pattern, Scanner};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use pep508_rs::{
|
use pep508_rs::{
|
||||||
expand_env_vars, split_scheme, strip_host, Extras, MarkerEnvironment, MarkerTree, Pep508Error,
|
expand_env_vars, split_scheme, strip_host, Extras, Pep508Error, Pep508ErrorSource, Requirement,
|
||||||
Pep508ErrorSource, Requirement, Scheme, UnnamedRequirement, VerbatimUrl, VersionOrUrl,
|
Scheme, VerbatimUrl,
|
||||||
VersionOrUrlRef,
|
|
||||||
};
|
};
|
||||||
|
pub use requirement::RequirementsTxtRequirement;
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
use uv_client::BaseClient;
|
use uv_client::BaseClient;
|
||||||
use uv_client::BaseClientBuilder;
|
use uv_client::BaseClientBuilder;
|
||||||
|
@ -58,6 +58,8 @@ use uv_fs::{normalize_url_path, Simplified};
|
||||||
use uv_normalize::ExtraName;
|
use uv_normalize::ExtraName;
|
||||||
use uv_warnings::warn_user;
|
use uv_warnings::warn_user;
|
||||||
|
|
||||||
|
mod requirement;
|
||||||
|
|
||||||
/// We emit one of those for each requirements.txt entry
|
/// We emit one of those for each requirements.txt entry
|
||||||
enum RequirementsTxtStatement {
|
enum RequirementsTxtStatement {
|
||||||
/// `-r` inclusion filename
|
/// `-r` inclusion filename
|
||||||
|
@ -1281,6 +1283,7 @@ mod test {
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
use test_case::test_case;
|
use test_case::test_case;
|
||||||
use unscanny::Scanner;
|
use unscanny::Scanner;
|
||||||
|
|
||||||
use uv_client::BaseClientBuilder;
|
use uv_client::BaseClientBuilder;
|
||||||
use uv_fs::Simplified;
|
use uv_fs::Simplified;
|
||||||
|
|
||||||
|
@ -2184,110 +2187,3 @@ mod test {
|
||||||
assert_eq!(line_column, expected, "Issues with input: {input}");
|
assert_eq!(line_column, expected, "Issues with input: {input}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A requirement specifier in a `requirements.txt` file.
|
|
||||||
#[derive(Hash, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub enum RequirementsTxtRequirement {
|
|
||||||
/// A PEP 508-compliant dependency specifier.
|
|
||||||
Pep508(Requirement),
|
|
||||||
/// A PEP 508-like, direct URL dependency specifier.
|
|
||||||
Unnamed(UnnamedRequirement),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for RequirementsTxtRequirement {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Pep508(requirement) => write!(f, "{requirement}"),
|
|
||||||
Self::Unnamed(requirement) => write!(f, "{requirement}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RequirementsTxtRequirement {
|
|
||||||
/// Returns whether the markers apply for the given environment
|
|
||||||
pub fn evaluate_markers(&self, env: &MarkerEnvironment, extras: &[ExtraName]) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::Pep508(requirement) => requirement.evaluate_markers(env, extras),
|
|
||||||
Self::Unnamed(requirement) => requirement.evaluate_markers(env, extras),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the extras for the requirement.
|
|
||||||
pub fn extras(&self) -> &[ExtraName] {
|
|
||||||
match self {
|
|
||||||
Self::Pep508(requirement) => requirement.extras.as_slice(),
|
|
||||||
Self::Unnamed(requirement) => requirement.extras.as_slice(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the markers for the requirement.
|
|
||||||
pub fn markers(&self) -> Option<&MarkerTree> {
|
|
||||||
match self {
|
|
||||||
Self::Pep508(requirement) => requirement.marker.as_ref(),
|
|
||||||
Self::Unnamed(requirement) => requirement.marker.as_ref(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the version specifier or URL for the requirement.
|
|
||||||
pub fn version_or_url(&self) -> Option<VersionOrUrlRef> {
|
|
||||||
match self {
|
|
||||||
Self::Pep508(requirement) => match requirement.version_or_url.as_ref() {
|
|
||||||
Some(VersionOrUrl::VersionSpecifier(specifiers)) => {
|
|
||||||
Some(VersionOrUrlRef::VersionSpecifier(specifiers))
|
|
||||||
}
|
|
||||||
Some(VersionOrUrl::Url(url)) => Some(VersionOrUrlRef::Url(url)),
|
|
||||||
None => None,
|
|
||||||
},
|
|
||||||
Self::Unnamed(requirement) => Some(VersionOrUrlRef::Url(&requirement.url)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Requirement> for RequirementsTxtRequirement {
|
|
||||||
fn from(requirement: Requirement) -> Self {
|
|
||||||
Self::Pep508(requirement)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<UnnamedRequirement> for RequirementsTxtRequirement {
|
|
||||||
fn from(requirement: UnnamedRequirement) -> Self {
|
|
||||||
Self::Unnamed(requirement)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for RequirementsTxtRequirement {
|
|
||||||
type Err = Pep508Error;
|
|
||||||
|
|
||||||
/// Parse a requirement as seen in a `requirements.txt` file.
|
|
||||||
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
|
||||||
match Requirement::from_str(input) {
|
|
||||||
Ok(requirement) => Ok(Self::Pep508(requirement)),
|
|
||||||
Err(err) => match err.message {
|
|
||||||
Pep508ErrorSource::UnsupportedRequirement(_) => {
|
|
||||||
Ok(Self::Unnamed(UnnamedRequirement::from_str(input)?))
|
|
||||||
}
|
|
||||||
_ => Err(err),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RequirementsTxtRequirement {
|
|
||||||
/// Parse a requirement as seen in a `requirements.txt` file.
|
|
||||||
pub fn parse(input: &str, working_dir: impl AsRef<Path>) -> Result<Self, Pep508Error> {
|
|
||||||
// Attempt to parse as a PEP 508-compliant requirement.
|
|
||||||
match Requirement::parse(input, &working_dir) {
|
|
||||||
Ok(requirement) => Ok(Self::Pep508(requirement)),
|
|
||||||
Err(err) => match err.message {
|
|
||||||
Pep508ErrorSource::UnsupportedRequirement(_) => {
|
|
||||||
// If that fails, attempt to parse as a direct URL requirement.
|
|
||||||
Ok(Self::Unnamed(UnnamedRequirement::parse(
|
|
||||||
input,
|
|
||||||
&working_dir,
|
|
||||||
)?))
|
|
||||||
}
|
|
||||||
_ => Err(err),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
116
crates/requirements-txt/src/requirement.rs
Normal file
116
crates/requirements-txt/src/requirement.rs
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
use pep508_rs::{
|
||||||
|
MarkerEnvironment, MarkerTree, Pep508Error, Pep508ErrorSource, Requirement, UnnamedRequirement,
|
||||||
|
VersionOrUrl, VersionOrUrlRef,
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
use std::path::Path;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use uv_normalize::ExtraName;
|
||||||
|
|
||||||
|
/// A requirement specifier in a `requirements.txt` file.
|
||||||
|
#[derive(Hash, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub enum RequirementsTxtRequirement {
|
||||||
|
/// A PEP 508-compliant dependency specifier.
|
||||||
|
Pep508(Requirement),
|
||||||
|
/// A PEP 508-like, direct URL dependency specifier.
|
||||||
|
Unnamed(UnnamedRequirement),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for RequirementsTxtRequirement {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Pep508(requirement) => write!(f, "{requirement}"),
|
||||||
|
Self::Unnamed(requirement) => write!(f, "{requirement}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RequirementsTxtRequirement {
|
||||||
|
/// Returns whether the markers apply for the given environment
|
||||||
|
pub fn evaluate_markers(&self, env: &MarkerEnvironment, extras: &[ExtraName]) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Pep508(requirement) => requirement.evaluate_markers(env, extras),
|
||||||
|
Self::Unnamed(requirement) => requirement.evaluate_markers(env, extras),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the extras for the requirement.
|
||||||
|
pub fn extras(&self) -> &[ExtraName] {
|
||||||
|
match self {
|
||||||
|
Self::Pep508(requirement) => requirement.extras.as_slice(),
|
||||||
|
Self::Unnamed(requirement) => requirement.extras.as_slice(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the markers for the requirement.
|
||||||
|
pub fn markers(&self) -> Option<&MarkerTree> {
|
||||||
|
match self {
|
||||||
|
Self::Pep508(requirement) => requirement.marker.as_ref(),
|
||||||
|
Self::Unnamed(requirement) => requirement.marker.as_ref(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the version specifier or URL for the requirement.
|
||||||
|
pub fn version_or_url(&self) -> Option<VersionOrUrlRef> {
|
||||||
|
match self {
|
||||||
|
Self::Pep508(requirement) => match requirement.version_or_url.as_ref() {
|
||||||
|
Some(VersionOrUrl::VersionSpecifier(specifiers)) => {
|
||||||
|
Some(VersionOrUrlRef::VersionSpecifier(specifiers))
|
||||||
|
}
|
||||||
|
Some(VersionOrUrl::Url(url)) => Some(VersionOrUrlRef::Url(url)),
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
|
Self::Unnamed(requirement) => Some(VersionOrUrlRef::Url(&requirement.url)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Requirement> for RequirementsTxtRequirement {
|
||||||
|
fn from(requirement: Requirement) -> Self {
|
||||||
|
Self::Pep508(requirement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<UnnamedRequirement> for RequirementsTxtRequirement {
|
||||||
|
fn from(requirement: UnnamedRequirement) -> Self {
|
||||||
|
Self::Unnamed(requirement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for RequirementsTxtRequirement {
|
||||||
|
type Err = Pep508Error;
|
||||||
|
|
||||||
|
/// Parse a requirement as seen in a `requirements.txt` file.
|
||||||
|
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
||||||
|
match Requirement::from_str(input) {
|
||||||
|
Ok(requirement) => Ok(Self::Pep508(requirement)),
|
||||||
|
Err(err) => match err.message {
|
||||||
|
Pep508ErrorSource::UnsupportedRequirement(_) => {
|
||||||
|
Ok(Self::Unnamed(UnnamedRequirement::from_str(input)?))
|
||||||
|
}
|
||||||
|
_ => Err(err),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RequirementsTxtRequirement {
|
||||||
|
/// Parse a requirement as seen in a `requirements.txt` file.
|
||||||
|
pub fn parse(input: &str, working_dir: impl AsRef<Path>) -> Result<Self, Pep508Error> {
|
||||||
|
// Attempt to parse as a PEP 508-compliant requirement.
|
||||||
|
match Requirement::parse(input, &working_dir) {
|
||||||
|
Ok(requirement) => Ok(Self::Pep508(requirement)),
|
||||||
|
Err(err) => match err.message {
|
||||||
|
Pep508ErrorSource::UnsupportedRequirement(_) => {
|
||||||
|
// If that fails, attempt to parse as a direct URL requirement.
|
||||||
|
Ok(Self::Unnamed(UnnamedRequirement::parse(
|
||||||
|
input,
|
||||||
|
&working_dir,
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
_ => Err(err),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue