diff --git a/crates/pep440-rs/Cargo.toml b/crates/pep440-rs/Cargo.toml index 87397b5940a29..0616de7cbe442 100644 --- a/crates/pep440-rs/Cargo.toml +++ b/crates/pep440-rs/Cargo.toml @@ -3,7 +3,6 @@ name = "pep440_rs" version = "0.3.12" description = "A library for python version numbers and specifiers, implementing PEP 440" license = "Apache-2.0 OR BSD-2-Clause" -include = ["/src", "Changelog.md", "License-Apache", "License-BSD", "README.md", "pyproject.toml"] edition = { workspace = true } rust-version = { workspace = true } diff --git a/crates/pep440-rs/README.md b/crates/pep440-rs/README.md deleted file mode 100644 index 295f0b4c5a587..0000000000000 --- a/crates/pep440-rs/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# PEP440 in rust - -[![Crates.io](https://img.shields.io/crates/v/pep440_rs.svg?logo=rust&style=flat-square)](https://crates.io/crates/pep440_rs) -[![PyPI](https://img.shields.io/pypi/v/pep440_rs.svg?logo=python&style=flat-square)](https://pypi.org/project/pep440_rs) - -A library for python version numbers and specifiers, implementing -[PEP 440](https://peps.python.org/pep-0440). See [Reimplementing PEP 440](https://cohost.org/konstin/post/514863-reimplementing-pep-4) for some background. - -Higher level bindings to the requirements syntax are available in [pep508_rs](https://github.com/konstin/pep508_rs). - -```rust -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.iter().all(|specifier| specifier.contains(&version))); -``` - -In python (`pip install pep440_rs`): - -```python -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` 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 diff --git a/crates/pep508-rs/Cargo.toml b/crates/pep508-rs/Cargo.toml index 3439d3de72745..3aa9c4c742738 100644 --- a/crates/pep508-rs/Cargo.toml +++ b/crates/pep508-rs/Cargo.toml @@ -2,7 +2,6 @@ name = "pep508_rs" version = "0.2.3" description = "A library for python dependency specifiers, better known as PEP 508" -include = ["/src", "Changelog.md", "License-Apache", "License-BSD", "Readme.md", "pyproject.toml"] license = "Apache-2.0 OR BSD-2-Clause" edition = { workspace = true } diff --git a/crates/pep508-rs/Readme.md b/crates/pep508-rs/Readme.md deleted file mode 100644 index c8948947a3ae6..0000000000000 --- a/crates/pep508-rs/Readme.md +++ /dev/null @@ -1,68 +0,0 @@ -# Dependency specifiers (PEP 508) in Rust - -[![Crates.io](https://img.shields.io/crates/v/pep508_rs.svg?logo=rust&style=flat-square)](https://crates.io/crates/pep508_rs) -[![PyPI](https://img.shields.io/pypi/v/pep508_rs.svg?logo=python&style=flat-square)](https://pypi.org/project/pep508_rs) - -A library for python [dependency specifiers](https://packaging.python.org/en/latest/specifications/dependency-specifiers/), better known as [PEP 508](https://peps.python.org/pep-0508/). - -## Usage - -**In Rust** - -```rust -use std::str::FromStr; -use pep508_rs::Requirement; - -let marker = r#"requests [security,tests] >= 2.8.1, == 2.8.* ; python_version > "3.8""#; -let dependency_specification = Requirement::from_str(marker).unwrap(); -assert_eq!(dependency_specification.name, "requests"); -assert_eq!(dependency_specification.extras, Some(vec!["security".to_string(), "tests".to_string()])); -``` - -**In Python** - -```python -from pep508_rs import Requirement - -requests = Requirement( - 'requests [security,tests] >= 2.8.1, == 2.8.* ; python_version > "3.8"' -) -assert requests.name == "requests" -assert requests.extras == ["security", "tests"] -assert [str(i) for i in requests.version_or_url] == [">= 2.8.1", "== 2.8.*"] -``` - -Python bindings are built with [maturin](https://github.com/PyO3/maturin), but you can also use the normal `pip install .` - -`Version` and `VersionSpecifier` from [pep440_rs](https://github.com/konstin/pep440-rs) are reexported to avoid type mismatches. - -## Markers - -Markers allow you to install dependencies only in specific environments (python version, operating system, architecture, etc.) or when a specific feature is activated. E.g. you can say `importlib-metadata ; python_version < "3.8"` or `itsdangerous (>=1.1.0) ; extra == 'security'`. Unfortunately, the marker grammar has some oversights (e.g. ) and the design of comparisons (PEP 440 comparisons with lexicographic fallback) leads to confusing outcomes. This implementation tries to carefully validate everything and emit warnings whenever bogus comparisons with unintended semantics are made. - -In python, warnings are by default sent to the normal python logging infrastructure: - -```python -from pep508_rs import Requirement, MarkerEnvironment - -env = MarkerEnvironment.current() -assert not Requirement("numpy; extra == 'science'").evaluate_markers(env, []) -assert Requirement("numpy; extra == 'science'").evaluate_markers(env, ["science"]) -assert not Requirement( - "numpy; extra == 'science' and extra == 'arrays'" -).evaluate_markers(env, ["science"]) -assert Requirement( - "numpy; extra == 'science' or extra == 'arrays'" -).evaluate_markers(env, ["science"]) -``` - - -```python -from pep508_rs import Requirement, MarkerEnvironment - -env = MarkerEnvironment.current() -Requirement("numpy; python_version >= '3.9.'").evaluate_markers(env, []) -# This will log: -# "Expected PEP 440 version to compare with python_version, found '3.9.', " -# "evaluating to false: Version `3.9.` doesn't match PEP 440 rules" -```