Version Utilities¶
The version utilities provide a small, focused API for representing,
parsing, and comparing the package’s own version triple
(major, minor, patch) programmatically.
The module lives at _errortools.version and is re-exported from the
top-level errortools package so that downstream code can do::
from errortools import VersionInfo, get_version_tuple
Module-level constants¶
The _errortools.version module exposes the current release in three
forms, each duplicated under both a dunder name (PEP 396 / packaging
convention) and a lower-case alias:
Constant |
Type |
Description |
|---|---|---|
|
|
Dotted-decimal string such as |
|
|
Lower-case alias of |
|
|
|
|
|
Lower-case alias of |
|
|
Git commit hash for source builds, else |
|
|
Lower-case alias of |
The lower-case names refer to the same objects as their dunder
counterparts, so identity-based assertions (x is y) hold.
>>> import errortools
>>> errortools.version is errortools.__version__
True
>>> errortools.version_tuple is errortools.__version_tuple__
True
>>> errortools.commit_id is errortools.__commit_id__
True
>>> errortools.__version_tuple__
(3, 5, 1)
VersionInfo¶
- class errortools.VersionInfo(major, minor, patch)[source]¶
Bases:
objectA lightweight value object representing a dotted-decimal version.
The three components follow the standard
major.minor.patchconvention. Instances are fully comparable and hashable, so they can be used as dictionary keys or stored in sets.Example
>>> v = VersionInfo(3, 5, 1) >>> str(v) '3.5.1' >>> v < VersionInfo(4, 0, 0) True
Added in version 3.5.
- Parameters:
major (int)
minor (int)
patch (int)
- major: int¶
- minor: int¶
- patch: int¶
- classmethod from_str(version_str)[source]¶
Create a
VersionInfofrom a dotted-decimal string.Missing components default to
0and components past the third are silently discarded. AValueErroris raised when the string is empty, ends with a trailing dot, or contains a non-numeric component.Example
>>> VersionInfo.from_str("3.5.1") VersionInfo(major=3, minor=5, patch=1) >>> VersionInfo.from_str("3.2") VersionInfo(major=3, minor=2, patch=0)
Added in version 3.5.
- Parameters:
version_str (str)
- Return type:
Overview¶
VersionInfo is a small @dataclass (with __slots__) that holds
three integer components — major, minor, patch — and makes them
fully comparable and hashable.
>>> from errortools import VersionInfo
>>> v = VersionInfo(3, 5, 1)
>>> v
VersionInfo(major=3, minor=5, patch=1)
>>> str(v)
'3.5.1'
Construction¶
The dataclass accepts any three integers; the values are stored verbatim (no range validation is performed):
>>> VersionInfo(3, 5, 1)
VersionInfo(major=3, minor=5, patch=1)
>>> VersionInfo(0, 0, 0)
VersionInfo(major=0, minor=0, patch=0)
The from_str classmethod parses a dotted-decimal string into a
VersionInfo:
>>> VersionInfo.from_str("3.5.1")
VersionInfo(major=3, minor=5, patch=1)
>>> VersionInfo.from_str("3.2") # missing patch -> 0
VersionInfo(major=3, minor=2, patch=0)
>>> VersionInfo.from_str("3") # missing minor/patch -> 0/0
VersionInfo(major=3, minor=0, patch=0)
>>> VersionInfo.from_str("1.2.3.4.5") # extra components discarded
VersionInfo(major=1, minor=2, patch=3)
A ValueError is raised for empty strings, trailing dots, or any
non-numeric component:
>>> VersionInfo.from_str("")
Traceback (most recent call last):
...
ValueError: Invalid version string: ''
>>> VersionInfo.from_str("3.2.")
Traceback (most recent call last):
...
ValueError: Invalid version string: '3.2.'
>>> VersionInfo.from_str("3.2.a")
Traceback (most recent call last):
...
ValueError: Invalid version string: '3.2.a'
Conversion¶
to_tuple() returns the components as a plain (major, minor, patch)
tuple of ints:
>>> VersionInfo(3, 5, 1).to_tuple()
(3, 5, 1)
Equality and hashing¶
Two VersionInfo instances are equal iff their three components are
equal. Because the class defines __hash__, instances can be used as
dictionary keys or stored in sets:
>>> VersionInfo(3, 5, 1) == VersionInfo(3, 5, 1)
True
>>> VersionInfo(3, 5, 1) != VersionInfo(3, 5, 2)
True
>>> {VersionInfo(1, 0, 0), VersionInfo(1, 0, 0), VersionInfo(2, 0, 0)}
{VersionInfo(major=1, minor=0, patch=0), VersionInfo(major=2, minor=0, patch=0)}
>>> mapping = {VersionInfo(1, 0, 0): "v1", VersionInfo(2, 0, 0): "v2"}
>>> mapping[VersionInfo(2, 0, 0)]
'v2'
Equality against an unrelated type returns False (Python’s standard
fallback when both __eq__ methods return NotImplemented):
>>> VersionInfo(1, 0, 0) == "1.0.0"
False
>>> VersionInfo(1, 0, 0) == (1, 0, 0)
False
Ordering¶
VersionInfo is totally ordered, component by component, the same way
Python compares integer tuples:
Operator |
Meaning |
|---|---|
|
strictly less (lexicographic on components) |
|
less than or equal |
|
strictly greater (lexicographic on components) |
|
greater than or equal |
>>> VersionInfo(1, 9, 9) < VersionInfo(2, 0, 0) # by major
True
>>> VersionInfo(1, 2, 9) < VersionInfo(1, 3, 0) # by minor
True
>>> VersionInfo(1, 2, 3) < VersionInfo(1, 2, 4) # by patch
True
This makes VersionInfo work directly with the standard library:
>>> versions = [
... VersionInfo(2, 0, 0),
... VersionInfo(1, 1, 5),
... VersionInfo(1, 2, 0),
... VersionInfo(1, 2, 3),
... ]
>>> sorted(versions)
[VersionInfo(major=1, minor=1, patch=5), VersionInfo(major=1, minor=2, patch=0), VersionInfo(major=1, minor=2, patch=3), VersionInfo(major=2, minor=0, patch=0)]
>>> min(versions)
VersionInfo(major=1, minor=1, patch=5)
>>> max(versions)
VersionInfo(major=2, minor=0, patch=0)
Memory layout¶
VersionInfo declares __slots__ so instances do not carry a
__dict__. This makes the class a good fit for representing versions
in hot paths or in large in-memory collections:
>>> VersionInfo(1, 2, 3).__slots__
('major', 'minor', 'patch')
get_version_tuple¶
- errortools.get_version_tuple(version)[source]¶
Parse a dotted-decimal version string into an integer triple.
Examples
>>> get_version_tuple("3.5.1") (3, 5, 1) >>> get_version_tuple("3.2") (3, 2, 0) >>> get_version_tuple("3") (3, 0, 0) >>> get_version_tuple("1.2.3.4.5") (1, 2, 3)
- Parameters:
version (str) – A dotted-decimal version string such as
"3.5.1".- Returns:
A
(major, minor, patch)tuple. Missing components default to0and components past the third are discarded.- Raises:
ValueError – If the string is empty, ends with a trailing dot, or contains a non-numeric component.
- Return type:
tuple[int, int, int]
Changed in version 3.5: add it to the public API.
Overview¶
get_version_tuple is the parsing function that powers
VersionInfo.from_str. It is exposed on its own so callers that only
need the integer triple can skip the dataclass overhead.
>>> from errortools import get_version_tuple
>>> get_version_tuple("3.5.1")
(3, 5, 1)
>>> get_version_tuple("3.2") # missing patch -> 0
(3, 2, 0)
>>> get_version_tuple("3") # missing minor/patch -> 0/0
(3, 0, 0)
>>> get_version_tuple("1.2.3.4.5") # extra components discarded
(1, 2, 3)
Error handling¶
A ValueError is raised when the input cannot be parsed. The error
message includes the offending input for easier debugging:
>>> get_version_tuple("")
Traceback (most recent call last):
...
ValueError: Invalid version string: ''
>>> get_version_tuple("3.2.")
Traceback (most recent call last):
...
ValueError: Invalid version string: '3.2.'
>>> get_version_tuple("3.2.a")
Traceback (most recent call last):
...
ValueError: Invalid version string: '3.2.a'
>>> get_version_tuple("a.b.c")
Traceback (most recent call last):
...
ValueError: Invalid version string: 'a.b.c'
When to use which?¶
Need the live package version? Use
errortools.__version__,errortools.__version_tuple__, orerrortools.__commit_id__.Need to parse an external version string? Use
get_version_tuple(raw triple) orVersionInfo.from_str(object form, comparable / hashable).Need to compare or sort a collection of versions? Use
VersionInfodirectly so you can rely on==,<,<=,>,>=,sorted(),min(),max(), and hashable containers.
See also¶
PEP 396 – Module version numbers — the convention followed by
__version__and friends.PEP 440 – Version Identification and Dependency Specification — the broader versioning scheme used by
setuptoolsandpip.VersionInfois intentionally simpler (only the integer triple) and does not attempt to parse pre-release / post-release / dev segments.