0acae9bd9c
## Summary Externally, development dependencies are currently structured as a flat list of PEP 580-compatible requirements: ```toml [tool.uv] dev-dependencies = ["werkzeug"] ``` When locking, we lock all development dependencies; when syncing, users can provide `--dev`. Internally, though, we model them as dependency groups, similar to Poetry, PDM, and [PEP 735](https://peps.python.org/pep-0735). This enables us to change out the user-facing frontend without changing the internal implementation, once we've decided how these should be exposed to users. A few important decisions encoded in the implementation (which we can change later): 1. Groups are enabled globally, for all dependencies. This differs from extras, which are enabled on a per-requirement basis. Note, however, that we'll only discover groups for uv-enabled packages anyway. 2. Installing a group requires installing the base package. We rely on this in PubGrub to ensure that we resolve to the same version (even though we only expect groups to come from workspace dependencies anyway, which are unique). But anyway, that's encoded in the resolver right now, just as it is for extras.
57 lines
1.6 KiB
Rust
57 lines
1.6 KiB
Rust
use std::fmt;
|
|
use std::fmt::{Display, Formatter};
|
|
use std::str::FromStr;
|
|
|
|
use serde::{Deserialize, Deserializer, Serialize};
|
|
|
|
use crate::{validate_and_normalize_owned, validate_and_normalize_ref, InvalidNameError};
|
|
|
|
/// The normalized name of an extra dependency.
|
|
///
|
|
/// Converts the name to lowercase and collapses runs of `-`, `_`, and `.` down to a single `-`.
|
|
/// For example, `---`, `.`, and `__` are all converted to a single `-`.
|
|
///
|
|
/// See:
|
|
/// - <https://peps.python.org/pep-0685/#specification/>
|
|
/// - <https://packaging.python.org/en/latest/specifications/name-normalization/>
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize)]
|
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
|
pub struct ExtraName(String);
|
|
|
|
impl ExtraName {
|
|
/// Create a validated, normalized extra name.
|
|
pub fn new(name: String) -> Result<Self, InvalidNameError> {
|
|
validate_and_normalize_owned(name).map(Self)
|
|
}
|
|
}
|
|
|
|
impl FromStr for ExtraName {
|
|
type Err = InvalidNameError;
|
|
|
|
fn from_str(name: &str) -> Result<Self, Self::Err> {
|
|
validate_and_normalize_ref(name).map(Self)
|
|
}
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for ExtraName {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
let s = String::deserialize(deserializer)?;
|
|
Self::from_str(&s).map_err(serde::de::Error::custom)
|
|
}
|
|
}
|
|
|
|
impl Display for ExtraName {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
self.0.fmt(f)
|
|
}
|
|
}
|
|
|
|
impl AsRef<str> for ExtraName {
|
|
fn as_ref(&self) -> &str {
|
|
&self.0
|
|
}
|
|
}
|