uv/crates/pep440-rs
Andrew Gallant 1379b530f6 uv: migrate to rkyv 0.8
Recently, rkyv 0.8 was released. Its API is a fair bit simpler now for
higher level uses (like for us in `uv`) and results in us being able to
delete a fair bit of code. This also removes our last dependency on `syn
1.0`, and thus drops that dependency.

Performance (via testing on the `transformers` example) seems to remain
about the same, which is what was expected:

```
$ hyperfine -w5 -r100 'uv lock' 'uv-ag-rkyv-update lock'
Benchmark 1: uv lock
  Time (mean ± σ):      55.6 ms ±   6.4 ms    [User: 30.4 ms, System: 35.1 ms]
  Range (min … max):    43.0 ms …  73.1 ms    100 runs

Benchmark 2: uv-ag-rkyv-update lock
  Time (mean ± σ):      56.5 ms ±   7.2 ms    [User: 30.5 ms, System: 36.3 ms]
  Range (min … max):    39.1 ms …  71.5 ms    100 runs

Summary
  uv lock ran
    1.02 ± 0.18 times faster than uv-ag-rkyv-update lock
```

Closes #7415
2024-09-18 14:49:54 -04:00
..
python Fix typos (#6891) 2024-08-30 19:45:33 -04:00
src uv: migrate to rkyv 0.8 2024-09-18 14:49:54 -04:00
test Extend Ruff configuration to sort imports (#5528) 2024-07-28 21:49:28 +00:00
Cargo.lock Copy over pep440-rs crate (#30) 2023-10-06 20:11:52 -04:00
Cargo.toml Run cargo upgrade (#7448) 2024-09-17 12:39:58 +02:00
CHANGELOG.md Use prettier to format the documentation (#5708) 2024-08-02 08:58:31 -05:00
License-Apache Copy over pep440-rs crate (#30) 2023-10-06 20:11:52 -04:00
License-BSD Copy over pep440-rs crate (#30) 2023-10-06 20:11:52 -04:00
Readme.md Use prettier to format the documentation (#5708) 2024-08-02 08:58:31 -05:00

PEP440 in rust

Crates.io PyPI

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 pre-releases
  • dev versions, which can be attached to sbpth table releases and pre-releases. When attached to a pre-release the dev version is ordered just below the normal pre-release, however when attached to a stable version, the dev version is sorted before a pre-releases
  • pre-release 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
  • pre-release vs. pre-release 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 matches 1.0+local. While the ordering of versions itself is a total order the version matching needs to catch all sorts of special cases