From 5d363132262c743585f6cc85a838ecc1cd359c26 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 18 Jan 2024 14:48:57 -0500 Subject: [PATCH] Revert "Try to remove READMEs" This reverts commit a348347704d27fd9fb5216be0183c1cf8c4b0288. --- .github/workflows/build-binaries.yml | 18 ++++---- crates/pep440-rs/Cargo.toml | 1 + crates/pep440-rs/README.md | 56 +++++++++++++++++++++++ crates/pep508-rs/Cargo.toml | 1 + crates/pep508-rs/Readme.md | 68 ++++++++++++++++++++++++++++ pyproject.toml | 1 + 6 files changed, 136 insertions(+), 9 deletions(-) create mode 100644 crates/pep440-rs/README.md create mode 100644 crates/pep508-rs/Readme.md diff --git a/.github/workflows/build-binaries.yml b/.github/workflows/build-binaries.yml index aca147256413d..0c7d57c50b69c 100644 --- a/.github/workflows/build-binaries.yml +++ b/.github/workflows/build-binaries.yml @@ -43,7 +43,7 @@ jobs: with: python-version: ${{ env.PYTHON_VERSION }} - name: "Prep README.md" - run: rm README.md + run: echo "# Puffin" > README.md - name: "Build sdist" uses: PyO3/maturin-action@v1 with: @@ -71,7 +71,7 @@ jobs: python-version: ${{ env.PYTHON_VERSION }} architecture: x64 - name: "Prep README.md" - run: rm README.md + run: echo "# Puffin" > README.md - name: "Build wheels - x86_64" uses: PyO3/maturin-action@v1 with: @@ -116,7 +116,7 @@ jobs: python-version: ${{ env.PYTHON_VERSION }} architecture: x64 - name: "Prep README.md" - run: rm README.md + run: echo "# Puffin" > README.md - name: "Build wheels - universal2" uses: PyO3/maturin-action@v1 with: @@ -171,7 +171,7 @@ jobs: python-version: ${{ env.PYTHON_VERSION }} architecture: ${{ matrix.platform.arch }} - name: "Prep README.md" - run: rm README.md + run: echo "# Puffin" > README.md - name: "Build wheels" uses: PyO3/maturin-action@v1 with: @@ -219,7 +219,7 @@ jobs: python-version: ${{ env.PYTHON_VERSION }} architecture: x64 - name: "Prep README.md" - run: rm README.md + run: echo "# Puffin" > README.md - name: "Build wheels" uses: PyO3/maturin-action@v1 with: @@ -302,12 +302,12 @@ jobs: with: python-version: ${{ env.PYTHON_VERSION }} - name: "Prep README.md" - run: rm README.md + run: echo "# Puffin" > README.md - name: "Build wheels" uses: PyO3/maturin-action@v1 with: target: ${{ matrix.platform.target }} - manylinux: manylinux2014 + manylinux: manylinux2018 docker-options: ${{ matrix.platform.maturin_docker_options }} args: --release --locked --out dist - uses: uraimo/run-on-arch-action@v2 @@ -366,7 +366,7 @@ jobs: python-version: ${{ env.PYTHON_VERSION }} architecture: x64 - name: "Prep README.md" - run: rm README.md + run: echo "# Puffin" > README.md - name: "Build wheels" uses: PyO3/maturin-action@v1 with: @@ -429,7 +429,7 @@ jobs: with: python-version: ${{ env.PYTHON_VERSION }} - name: "Prep README.md" - run: rm README.md + run: echo "# Puffin" > README.md - name: "Build wheels" uses: PyO3/maturin-action@v1 with: diff --git a/crates/pep440-rs/Cargo.toml b/crates/pep440-rs/Cargo.toml index 0616de7cbe442..87397b5940a29 100644 --- a/crates/pep440-rs/Cargo.toml +++ b/crates/pep440-rs/Cargo.toml @@ -3,6 +3,7 @@ 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 new file mode 100644 index 0000000000000..295f0b4c5a587 --- /dev/null +++ b/crates/pep440-rs/README.md @@ -0,0 +1,56 @@ +# 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 3aa9c4c742738..3439d3de72745 100644 --- a/crates/pep508-rs/Cargo.toml +++ b/crates/pep508-rs/Cargo.toml @@ -2,6 +2,7 @@ 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 new file mode 100644 index 0000000000000..c8948947a3ae6 --- /dev/null +++ b/crates/pep508-rs/Readme.md @@ -0,0 +1,68 @@ +# 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" +``` diff --git a/pyproject.toml b/pyproject.toml index d28eeeab5d8e5..4f23230c188da 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,7 @@ authors = [{ name = "Puffin" }] requires-python = ">=3.7" keywords = [] classifiers = [] +readme = "README.md" [tool.maturin] bindings = "bin"