Skip to main content

High-performance version string parsing and comparison across all major package ecosystems

Project description

anyver

CI PyPI Python License: MIT

A high-performance Python library (written in Rust via PyO3) for parsing and comparing software version strings across all major package ecosystems.

Handles: SemVer, PEP 440, npm, Go modules, Debian/dpkg, RPM, Ruby Gems, Maven, NuGet, Composer, Crates.io, Hex, Swift PM, CalVer, Alpine, Docker, Conda, Arch/pacman, Gentoo/Portage, R/CRAN, Spack, Dart pub, Julia Pkg, Terraform/OpenTofu, Helm, CPAN, Nix, Homebrew, FreeBSD pkg — with a single generic parser, ecosystem-specific modes, range helpers, and security-interoperability utilities.

Installation

pip install anyver

Build from source (requires Rust toolchain):

pip install maturin
maturin develop --release

Quick Start

from anyver import Version
import anyver

# Parse and compare versions
Version("1.2.3") < Version("2.0.0")          # True
Version("1.0.0-alpha") < Version("1.0.0")    # True
Version("1.0") == Version("1.0.0")           # True (trailing zero equivalence)
Version("v1.0") == Version("1.0")            # True (v-prefix stripped)
Version("1.0+build") == Version("1.0+other") # True (build metadata ignored)

# Module-level compare
anyver.compare("1.0", "2.0")                 # -1
anyver.compare("2.0", "1.0")                 #  1
anyver.compare("1.0", "1.0.0")               #  0

Version Object

v = Version("1.2.3-rc.1+build.42")

# Properties
v.raw              # "1.2.3-rc.1+build.42"
v.ecosystem        # "generic" (detected ecosystem name)
v.epoch            # 0
v.build            # "build.42"
v.major            # 1
v.minor            # 2
v.patch            # 3
v.is_prerelease    # True
v.is_postrelease   # False
v.is_stable        # False (opposite of is_prerelease)

# Segments
v.segments()       # (1, 2, 3, "rc", 1)
v.release()        # (1, 2, 3)
len(v)             # 5
v[0]               # 1
v[3]               # "rc"
v[-1]              # 1

# String representations
str(v)             # "1.2.3-rc.1+build.42"
repr(v)            # "Version('1.2.3-rc.1+build.42')"

# Compare using the Version's own detected ecosystem
v.compare("1.2.3")      # 0
v.compare("2.0.0")      # -1
v.compare("0.1.0")      # 1

Sorting and Batch Operations

anyver.sort_versions(["2.0", "1.0-alpha", "1.0", "0.1"])
# ["0.1", "1.0-alpha", "1.0", "2.0"]

anyver.batch_compare([("1.0", "2.0"), ("2.0", "1.0"), ("1.0", "1.0")])
# [-1, 1, 0]

anyver.max_version(["1.0", "3.0", "2.0"])  # "3.0"
anyver.min_version(["1.0", "3.0", "2.0"])  # "1.0"

Boolean Helpers

anyver.gt("2.0", "1.0")    # True
anyver.ge("1.0", "1.0.0")  # True
anyver.lt("1.0", "2.0")    # True
anyver.le("1.0", "1.0.0")  # True
anyver.eq("1.0", "1.0.0")  # True
anyver.ne("1.0", "2.0")    # True

Version Constraints

Check whether a version satisfies a constraint expression. Supports >=, <=, >, <, ==, != operators, combined with commas for AND logic:

anyver.satisfies("1.5.0", ">=1.0.0,<2.0.0")   # True
anyver.satisfies("2.0.0", ">=1.0.0,<2.0.0")   # False
anyver.satisfies("1.0.0", ">=1.0.0")           # True
anyver.satisfies("1.0.0", "!=1.0.0")           # False
anyver.satisfies("1.0.0-alpha", ">1.0.0")      # False

# Works with any ecosystem
anyver.satisfies("5.14.0-503.19.1.el9_5", ">=5.14.0-427.0.0.el9_4", ecosystem="rpm")

Range helpers also support OR with ||, npm/Cargo-style caret and tilde ranges, x-ranges, Maven/NuGet interval notation, and Terraform-style ~>:

anyver.range_contains("1.5.0", ">=1.0.0,<2.0.0")    # True
anyver.range_contains("1.2.7", "1.2.x")              # True
anyver.range_contains("1.5.0", "[1.0.0,2.0.0)")      # True
anyver.ranges_intersect(">=1.0,<2.0", ">=1.5,<3.0")  # True

Stable Version Filtering

Filter out pre-release versions or find the latest stable:

anyver.stable_versions(["2.0.0-rc1", "1.0.0", "2.0.0", "1.5.0-beta"])
# ["1.0.0", "2.0.0"]

anyver.latest_stable(["2.0.0-rc1", "1.0.0", "2.0.0", "1.5.0-beta"])
# "2.0.0"

Version Bumping

anyver.bump_major("1.2.3")          # "2.0.0"
anyver.bump_minor("1.2.3")          # "1.3.0"
anyver.bump_patch("1.2.3")          # "1.2.4"

# Pre-release tags are stripped
anyver.bump_major("1.2.3-alpha")    # "2.0.0"
anyver.bump_patch("1.0.0-rc1")     # "1.0.1"

Hashable (Sets and Dicts)

s = {Version("1.0"), Version("1.0.0"), Version("2.0")}
len(s)  # 2 — "1.0" and "1.0.0" are equal, so deduplicated

d = {Version("1.0"): "stable"}
d[Version("1.0.0")]  # "stable"

Ecosystem Auto-Detection

By default, Version() and anyver.version() use ecosystem="auto" — the library inspects the version string and picks the best ecosystem automatically:

# Auto-detected as PEP 440 (contains "!")
Version("1!2.0.0")                           # ecosystem=pep440

# Auto-detected as Debian (contains "~")
Version("1.0~rc1")                           # ecosystem=debian

# Auto-detected as RPM (contains ".fc" / ".el")
Version("5.14.0-362.24.1.el9_4")             # ecosystem=rpm

# Auto-detected as Go (ends with "+incompatible")
Version("v2.0.0+incompatible")               # ecosystem=go

# Auto-detected as Alpine (contains "_alpha", "_rc", "-rN")
Version("3.1.4-r5")                          # ecosystem=alpine

# Auto-detected as Maven (ends with "-SNAPSHOT")
Version("1.0-SNAPSHOT")                      # ecosystem=maven

# Auto-detected as CalVer (starts with year-like number)
Version("2024.1.15")                         # ecosystem=calver

# Falls back to generic when ambiguous
Version("1.2.3")                             # ecosystem=generic

Detection rules (in priority order):

  1. ! in string → PEP 440
  2. ~ → Debian, ^ → RPM
  3. .post, .dev → PEP 440
  4. +incompatible → Go, -SNAPSHOT → Maven
  5. _alpha, _beta, _rc, _p, -rN → Alpine
  6. +deb, +ubuntu → Debian; .el, .fc, .amzn → RPM
  7. Digit-letter patterns like 1a1, 1b2, 1rc1 → PEP 440
  8. Dot-separated .pre, .rc, .beta, .alpha (no hyphens) → Ruby
  9. Year-like first segment (1990-2100) → CalVer
  10. Otherwise → Generic

Ecosystem-Specific Comparison

You can also set the ecosystem explicitly:

# Strict SemVer (numeric < alpha in pre-release)
anyver.compare_semver_strict("1.0.0-alpha", "1.0.0")  # -1

# Debian/dpkg (tilde sorts before everything)
anyver.compare("1.0~rc1", "1.0", ecosystem="debian")   # -1

# RPM (caret for post-release snapshots)
anyver.compare("1.0", "1.0^git1", ecosystem="rpm")     # -1

# PEP 440 (epoch with !)
anyver.compare("1!0.1", "2.0", ecosystem="pep440")     # 1

# All supported ecosystems:
# auto (default for Version), generic (default for compare),
# semver, npm, pep440, debian, rpm, go, ruby/gem/rubygems,
# maven/mvn, nuget/dotnet, composer/php/packagist,
# crates/cargo, hex/elixir/erlang, swift/swiftpm,
# calver, alpine/apk, docker/oci,
# conda/mamba, arch/pacman, gentoo/portage, cran/r,
# spack, dart/pub/flutter, julia, terraform/opentofu, helm,
# cpan/perl, nix/nixpkgs, homebrew/brew, freebsd/freebsd-pkg

The mature exact-native comparators are Debian/dpkg, RPM, strict SemVer-family modes, and PEP 440 local-version handling. Newer ecosystem modes start with validation plus generic or SemVer-compatible ordering where their native algorithm is not yet fully specialized.

Database Integration

to_dict() — Structured Export

Version("1.2.3-rc.1+build.42").to_dict()
# {
#   "raw": "1.2.3-rc.1+build.42",
#   "epoch": 0,
#   "major": 1,
#   "minor": 2,
#   "patch": 3,
#   "build": "build.42",
#   "is_prerelease": True,
#   "is_postrelease": False
# }

sort_key() — Database-Friendly Sort Key

Version("1.2.3-rc.1").sort_key()
# Tuple of tuples that preserves comparison order when sorted lexically.
# Isomorphic with comparing two versions of the same ecosystem, including
# PEP 440 local labels (e.g. `1.0+abc` sorts above `1.0`).

Scope: the key reproduces the generic/SemVer and PEP 440 orderings exactly. Debian and RPM compare with their native dpkg/rpm algorithms, which the key approximates via the generic ordering — the same documented approximation the parser makes for those ecosystems. For Debian/RPM, sort with anyver.sort_versions(..., ecosystem=...) rather than by sort_key() when exact native ordering matters.

Security Interop

Helpers are provided for package-url (PURL), VERS-style version ranges, and OSV-shaped affected records:

anyver.parse_purl("pkg:npm/%40scope/name@1.2.3")
# {"type": "npm", "namespace": "%40scope", "name": "name",
#  "version": "1.2.3", "ecosystem": "npm", ...}

anyver.build_purl("npm", "name", "1.2.3", "%40scope")
# "pkg:npm/%40scope/name@1.2.3"

vers = anyver.build_vers("npm", ">=1.0.0,<2.0.0")
anyver.vers_contains(vers, "1.5.0")  # True

affected = {
    "package": {"ecosystem": "npm", "name": "demo"},
    "ranges": [{"events": [{"introduced": "1.0.0"}, {"fixed": "1.2.0"}]}],
}
anyver.osv_affected("1.1.0", affected)  # True

Cross-Ecosystem Examples

# PEP 440 (Python)
Version("1.0.dev1") < Version("1.0a1") < Version("1.0b1") < Version("1.0rc1") < Version("1.0") < Version("1.0.post1")

# Debian
Version("1.0~alpha") < Version("1.0~beta") < Version("1.0")

# RPM
Version("1.0~rc1") < Version("1.0") < Version("1.0^git1")

# Maven
Version("1.0-alpha-1") < Version("1.0-SNAPSHOT") < Version("1.0") < Version("1.0-sp-1")

# Go modules
Version("v2.0.0+incompatible") == Version("v2.0.0")

# Ruby Gems — numeric, not lexical
Version("3.2") < Version("3.10")

# Epoch overrides everything
Version("1:0.1") > Version("999.0")

Performance

Built in Rust for speed. Typical benchmarks (Apple M-series):

Operation Time
Version("1.2.3") construction ~330 ns
anyver.compare("1.2.3", "1.2.4") ~300 ns
Version < Version (pre-parsed) ~66 ns
sort_versions(1000) ~460 us
vs Python packaging.version ~14x faster
vs Python semver ~23x faster

Stability & Versioning

anyver follows Semantic Versioning. The public API surface covered by SemVer guarantees:

Stable (breaking changes require a major version bump):

  • The Version class constructor, operators, properties, and methods (raw, ecosystem, epoch, build, major/minor/patch, is_prerelease, is_postrelease, is_stable, count, segments(), release(), compare(), to_dict(), from_dict(), sort_key(), parse(), try_parse()).
  • Module-level functions: version, compare, compare_semver_strict, sort_versions, batch_compare, gt/ge/gte/lt/le/lte/eq/ne, max_version, min_version, stable_versions, latest_stable, satisfies, bump_major/bump_minor/bump_patch/bump_prerelease, next_stable.
  • The set of accepted ecosystem names (aliases may grow, but existing names keep their meaning).
  • The comparison result (-1/0/1) for any pair of versions within a given ecosystem, within a major version.
  • Type stubs (.pyi) and the py.typed marker.
  • Pickle format and __reduce__ output (stable across patch versions).

Experimental (may change within minor versions until documented stable):

  • Version.sort_key() tuple shape (the encoding scheme can evolve if new ecosystems require additional distinguishing fields).
  • The ecosystem="auto" detection heuristic. The rules may be refined to reduce false positives; the existing correct detections will not flip.
  • Error messages and exception attribute text.

Not covered by SemVer:

  • Rust internals (src/), benchmarks, CI configuration.
  • Performance numbers (we aim to improve them monotonically, but there are no guarantees tied to the public version).

See CHANGELOG.md for release history.

Author

Aleksandr Pavlov ckidoz@gmail.com

License

MIT — see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

anyver-1.1.0.tar.gz (68.9 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

anyver-1.1.0-cp311-abi3-win_amd64.whl (230.9 kB view details)

Uploaded CPython 3.11+Windows x86-64

anyver-1.1.0-cp311-abi3-musllinux_1_2_x86_64.whl (592.7 kB view details)

Uploaded CPython 3.11+musllinux: musl 1.2+ x86-64

anyver-1.1.0-cp311-abi3-musllinux_1_2_aarch64.whl (559.1 kB view details)

Uploaded CPython 3.11+musllinux: musl 1.2+ ARM64

anyver-1.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (386.6 kB view details)

Uploaded CPython 3.11+manylinux: glibc 2.17+ x86-64

anyver-1.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (383.9 kB view details)

Uploaded CPython 3.11+manylinux: glibc 2.17+ ARM64

anyver-1.1.0-cp311-abi3-macosx_11_0_arm64.whl (344.8 kB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

anyver-1.1.0-cp311-abi3-macosx_10_12_x86_64.whl (343.2 kB view details)

Uploaded CPython 3.11+macOS 10.12+ x86-64

File details

Details for the file anyver-1.1.0.tar.gz.

File metadata

  • Download URL: anyver-1.1.0.tar.gz
  • Upload date:
  • Size: 68.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for anyver-1.1.0.tar.gz
Algorithm Hash digest
SHA256 70e93d72c3e1926434f2f3022de37260128702bd46da533aa5e0e240918786fa
MD5 b1fc49f34748afed3aebcd1bdc05d067
BLAKE2b-256 efd9af7de09fc74ee0c1abb41e8aec873147591d81990f961b5d870317173695

See more details on using hashes here.

Provenance

The following attestation bundles were made for anyver-1.1.0.tar.gz:

Publisher: publish.yml on kidoz/anyver

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file anyver-1.1.0-cp311-abi3-win_amd64.whl.

File metadata

  • Download URL: anyver-1.1.0-cp311-abi3-win_amd64.whl
  • Upload date:
  • Size: 230.9 kB
  • Tags: CPython 3.11+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for anyver-1.1.0-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 23c85fb4f7764fa68c6f0315f0dd5316483c9dce766bf83ee746d5fd10983206
MD5 aaf9fa14373d062f9a15779e0f8bf755
BLAKE2b-256 4a9aa215023752be09ccdad0670948d5eb0140094ae7fdfeb8734d203fb334d7

See more details on using hashes here.

Provenance

The following attestation bundles were made for anyver-1.1.0-cp311-abi3-win_amd64.whl:

Publisher: publish.yml on kidoz/anyver

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file anyver-1.1.0-cp311-abi3-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for anyver-1.1.0-cp311-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 2e4fccd18540538c4fbd887267c652ac17c8847f616ad8d274e8f4dee72faed4
MD5 69c9b9fa9f67b6ea366cfbf071c87923
BLAKE2b-256 decfb19f168b24470ec22ca65e908cef68325f2129037623ed620ac6cf36344a

See more details on using hashes here.

Provenance

The following attestation bundles were made for anyver-1.1.0-cp311-abi3-musllinux_1_2_x86_64.whl:

Publisher: publish.yml on kidoz/anyver

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file anyver-1.1.0-cp311-abi3-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for anyver-1.1.0-cp311-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 0d234879beb996ee6efaa4ff9934b867199452e71683295894f1eda45ab6276b
MD5 c0e3d5c3871f66cc193d97d4112aa60b
BLAKE2b-256 9579a70def18cd66667a263a410e685074b4d6a44483ddff981097aee4d6e383

See more details on using hashes here.

Provenance

The following attestation bundles were made for anyver-1.1.0-cp311-abi3-musllinux_1_2_aarch64.whl:

Publisher: publish.yml on kidoz/anyver

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file anyver-1.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for anyver-1.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 4b60b2d15e74ed2b3df6444e2b8a714215acf650f459752f686e6eb34d8e036d
MD5 97736621c39759a02aa9d1954589c4a8
BLAKE2b-256 ee15e5938618449a5a429ff72d98ec390e1f75226a6fdec12922cf53c9a24645

See more details on using hashes here.

Provenance

The following attestation bundles were made for anyver-1.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: publish.yml on kidoz/anyver

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file anyver-1.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for anyver-1.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 1c97cb09e0496be008b4a4296d5ea1b2d4fef8ec353edd933d21b166fd406cb8
MD5 d4978e07e21ca53bba23183a3baf9a00
BLAKE2b-256 62b285d5cf57efb5bec5748ff0641fbed74638e1addd8b58ff8e998a80bc97b1

See more details on using hashes here.

Provenance

The following attestation bundles were made for anyver-1.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: publish.yml on kidoz/anyver

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file anyver-1.1.0-cp311-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for anyver-1.1.0-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 0f2fa90663b0203d3086c313d6384a6d74177e1f52508abf613cb17439edc4f9
MD5 422fd6deb32a521e771294360ff0d537
BLAKE2b-256 17b2bc88c1b3900fbd213fb95ae8904ac574a8e28e4899b67eaa835bc7011c4b

See more details on using hashes here.

Provenance

The following attestation bundles were made for anyver-1.1.0-cp311-abi3-macosx_11_0_arm64.whl:

Publisher: publish.yml on kidoz/anyver

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file anyver-1.1.0-cp311-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for anyver-1.1.0-cp311-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 f9e795e9c9df6ed647a2dd8a80003116857edbe665d77ee0884a73f04d410e5b
MD5 e1ada45a5c8db4ba3ea70a940b1be85e
BLAKE2b-256 5f4175daeff442cb41d9e9abecc09666d4e9d6bd27a8e64c695b1f9d4a378428

See more details on using hashes here.

Provenance

The following attestation bundles were made for anyver-1.1.0-cp311-abi3-macosx_10_12_x86_64.whl:

Publisher: publish.yml on kidoz/anyver

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page