mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 21:35:00 +00:00
![]() In *some* places in our crates, `serde` (and `rkyv`) are optional dependencies. I believe this was done out of reasons of "good sense," that is, it follows a Rust ecosystem pattern where serde integration tends to be an opt-in crate feature. (And similarly for `rkyv`.) However, ultimately, `uv` itself requires `serde` and `rkyv` to function. Since our crates are strictly internal, there are limited consumers for our crates without `serde` (and `rkyv`) enabled. I think one possibility is that optional `serde` (and `rkyv`) integration means that someone can do this: cargo test -p pep440_rs And this will run tests _without_ `serde` or `rkyv` enabled. That in turn could lead to faster iteration time by reducing compile times. But, I'm not sure this is worth supporting. The iterative compilation times of individual crates are probably fast enough in debug mode, even with `serde` and `rkyv` enabled. Namely, `serde` and `rkyv` themselves shouldn't need to be re-compiled in most cases. On `main`: ``` from-scratch: `cargo test -p pep440_rs --lib` 0.685 incremental: `cargo test -p pep440_rs --lib` 0.278s from-scratch: `cargo test -p pep440_rs --features serde,rkyv --lib` 3.948s incremental: `cargo test -p pep440_rs --features serde,rkyv --lib` 0.321s ``` So while a from-scratch build does take significantly longer, an incremental build is about the same. The benefit of doing this change is two-fold: 1. It brings out crates into alignment with "reality." In particular, some crates were _implicitly_ relying on `serde` being enabled without explicitly declaring it. This technically means that our `Cargo.toml`s were wrong in some cases, but it is hard to observe it because of feature unification in a Cargo workspace. 2. We no longer need to deal with the cognitive burden of writing `#[cfg_attr(feature = "serde", ...)]` everywhere. |
||
---|---|---|
.. | ||
python | ||
src | ||
test | ||
Cargo.lock | ||
Cargo.toml | ||
CHANGELOG.md | ||
License-Apache | ||
License-BSD | ||
Readme.md |
PEP440 in rust
A library for python version numbers and specifiers, implementing PEP 440. See Reimplementing PEP 440 for some background.
Higher level bindings to the requirements syntax are available in pep508_rs.
use std::str::FromStr;
use pep440_rs::{parse_version_specifiers, Version, VersionSpecifier};
let version = Version::from_str("1.19").unwrap();
let version_specifier = VersionSpecifier::from_str("==1.*").unwrap();
assert!(version_specifier.contains(&version));
let version_specifiers = parse_version_specifiers(">=1.16, <2.0").unwrap();
assert!(version_specifiers.contains(&version));
In python (pip install pep440_rs
):
from pep440_rs import Version, VersionSpecifier
assert Version("1.1a1").any_prerelease()
assert Version("1.1.dev2").any_prerelease()
assert not Version("1.1").any_prerelease()
assert VersionSpecifier(">=1.0").contains(Version("1.1a1"))
assert not VersionSpecifier(">=1.1").contains(Version("1.1a1"))
# Note that python comparisons are the version ordering, not the version specifiers operators
assert Version("1.1") >= Version("1.1a1")
assert Version("2.0") in VersionSpecifier("==2")
PEP 440 has a lot of unintuitive features, including:
- An epoch that you can prefix the version which, e.g.
1!1.2.3
. Lower epoch always means lower version (1.0 <=2!0.1
) - post versions, which can be attached to both stable releases and prereleases
- dev versions, which can be attached to sbpth table releases and prereleases. When attached to a prerelease the dev version is ordered just below the normal prerelease, however when attached to a stable version, the dev version is sorted before a prereleases
- prerelease handling is a mess: "Pre-releases of any kind, including developmental releases, are implicitly excluded from all version specifiers, unless they are already present on the system, explicitly requested by the user, or if the only available version that satisfies the version specifier is a pre-release.". This means that we can't say whether a specifier matches without also looking at the environment
- prelease vs. prerelease incl. dev is fuzzy
- local versions on top of all the others, which are added with a + and have implicitly typed string and number segments
- no semver-caret (
^
), but a pseudo-semver tilde (~=
) - ordering contradicts matching: We have e.g.
1.0+local > 1.0
when sorting, but==1.0
matches1.0+local
. While the ordering of versions itself is a total order the version matching needs to catch all sorts of special cases