Versioning
The pyTooling.Versioning
package provides auxiliary classes to implement Semantic Versioning
(following SemVer rules) and Calendar Versioning (following
CalVer rules). The latter one has multiple variants due to the meaning of the version’s parts
like: year-month version or year-week version.
Versions can be grouped by version sets and version ranges.
Semantic Versioning
The SemanticVersion
class represents of a version number like v3.7.12
. It consists of
a major, minor and micro number. The micro number is also known as patch number. The minor and micro numbers are
optional, but usually used by most semantic version numbering schemes. In addition, optional parts can be added like a
prefix, a postfix or a build number.
Hint
Given a version number MAJOR.MINOR.MICRO
, increment the:
MAJOR
version when you make incompatible API changes,MINOR
version when you add functionality in a backwards compatible manner, andMICRO
version when you make backwards compatible bug fixes.Additional labels for pre-release and build metadata are available as extensions to the
MAJOR.MINOR.MICRO
format.
Summary taken from semver.org.
Direct Instantiation
A semantic version can be constructed from parts like major, minor and micro numbers.
# Construct from numbers
version = SemanticVersion(1, 5, 2)
Construction from String
Alternatively, a semantic version can be created from a string containing a semantic version number by using the
class-method Parse()
. The string is parsed and a semantic version gets
returned.
# Construct from string
version = SemanticVersion.Parse("0.22.8")
Usage
# Compare versions
if version2 > version1:
# Compare versions
if version2 >= "1.4.8":
Features
- Prefix string
Represents the prefix like:
v
(version),r
(revision),i
(internal version/release),ver
(version),rev
(revision).v1.2.3
- Major number
Represents the major version number in semantic version.
v1.2.3
- Minor number
Represents the minor version number in semantic version.
v1.2.3
- Micro number
Represents the micro or patch version number in semantic version.
v1.2.3
- Build number
Represents the build number.
v1.2.3.4
- Release Level / Release number
Distinguishes if a version is in alpha, beta, release candidate or final release level.
v1.2.3.alpha4
v1.2.3.beta4
v1.2.3.rc4- Post number
tbd
v1.2.3.post4
- Development number
tbd
v1.2.3.dev4
- Postfix string
v1.2.3+deb11u5
- Comparison operators
Operators for
==
,!=
,<
,<=
,>
,>=
,>>
.- String formatting
The version number can be formatted as a string with a fixed formatting pattern based on present version parts as well as a user-defined formatting via
__format__()
Examples
|
|
|
Condensed Class Definition
@export
class SemanticVersion(Version):
@classmethod
def Parse(cls, versionString: Nullable[str], validator: Nullable[Callable[["SemanticVersion"], bool]] = None) -> "Version":
pass
@readonly
def Parts(self) -> Parts:
pass
@readonly
def Prefix(self) -> str:
pass
@readonly
def Major(self) -> int:
pass
@readonly
def Minor(self) -> int:
pass
@readonly
def Micro(self) -> int:
pass
@readonly
def Patch(self) -> int:
pass
@readonly
def ReleaseLevel(self) -> ReleaseLevel:
pass
@readonly
def ReleaseNumber(self) -> int:
pass
@readonly
def Post(self) -> int:
pass
@readonly
def Dev(self) -> int:
pass
@readonly
def Build(self) -> int:
pass
@readonly
def Postfix(self) -> str:
pass
@readonly
def Hash(self) -> str:
pass
@readonly
def Flags(self) -> Flags:
pass
def __eq__(self, other: Union["SemanticVersion", str, int, None]) -> bool:
pass
def __ne__(self, other: Union["SemanticVersion", str, int, None]) -> bool:
pass
def __lt__(self, other: Union["SemanticVersion", str, int, None]) -> bool:
pass
def __le__(self, other: Union["SemanticVersion", str, int, None]) -> bool:
pass
def __gt__(self, other: Union["SemanticVersion", str, int, None]) -> bool:
pass
def __ge__(self, other: Union["SemanticVersion", str, int, None]) -> bool:
pass
def __imod__(self, other: Union["SemanticVersion", str, int, None]) -> bool:
pass
def __format__(self, formatSpec: str) -> str:
pass
def __repr__(self) -> str:
pass
def __str__(self) -> str:
pass
Variants
Examples
3.13.0
3.13.0a4
3.13.0b2
3.13.0rc2
Condensed Class Definition
@export
class PythonVersion(SemanticVersion):
@classmethod
def FromSysVersionInfo(cls) -> "PythonVersion":
pass
Calendar Versioning
The CalendarVersion
class represents of a version number like 2021.10
.
Direct Instantiation
Alternatively, a calendar version can be constructed from parts like major, minor and micro numbers. The unified naming of parts can be used to map years to major numbers, months to minor numbers, etc.
# Construct from numbers
version = CalendarVersion(2024, 5)
Construction from String
A calendar version can be created from a string containing a calendar version number by using the class-method
Parse()
. The string is parsed and a calendar version gets returned.
# Construct from string
version = CalendarVersion.Parse("2024.05")
Usage
# Compare versions
if version2 > version1:
# Compare versions
if version2 >= "2023.02":
Features
- Major number
Represents the major version number in semantic version.
- Minor number
Represents the minor version number in semantic version.
- Micro number
Represents the micro or patch version number in semantic version.
- Build number
Represents the build number.
- Prefix string
Represents the prefix like:
v
(version),r
(revision),i
(internal version/release),ver
(version),rev
(revision).- Comparison operators
Operators for
==
,!=
,<
,<=
,>
,>=
,%=
.
Missing Features
release-level: additional labels like
dev
,rc
,pl
,alpha
pre-version and post-version
Condensed Class Definition
@export
class CalendarVersion(Version):
@classmethod
def Parse(cls, versionString: Nullable[str], validator: Nullable[Callable[["CalendarVersion"], bool]] = None) -> "CalendarVersion":
pass
@readonly
def Parts(self) -> Parts:
pass
@readonly
def Major(self) -> int:
pass
@readonly
def Minor(self) -> int:
pass
@readonly
def Micro(self) -> int:
pass
@readonly
def Patch(self) -> int:
pass
@readonly
def Build(self) -> int:
pass
@readonly
def Flags(self) -> Flags:
pass
@readonly
def Prefix(self) -> str:
pass
@readonly
def Postfix(self) -> str:
pass
def __eq__(self, other: Union["CalendarVersion", str, int, None]) -> bool:
pass
def __ne__(self, other: Union["CalendarVersion", str, int, None]) -> bool:
pass
def __lt__(self, other: Union["CalendarVersion", str, int, None]) -> bool:
pass
def __le__(self, other: Union["CalendarVersion", str, int, None]) -> bool:
pass
def __gt__(self, other: Union["CalendarVersion", str, int, None]) -> bool:
pass
def __ge__(self, other: Union["CalendarVersion", str, int, None]) -> bool:
pass
def __imod__(self, other: Union["CalendarVersion", str, int, None]) -> bool:
pass
def __format__(self, formatSpec: str) -> str:
pass
def __repr__(self) -> str:
pass
def __str__(self) -> str:
pass
Variants
Hint
Calendar versions have multiple format variants:
YY.MINOR.MICRO
YYYY.MINOR.MICRO
YY.MM
YYYY.0M
YYYY.MM.DD
YYYY.MM.DD_MICRO
YYYY-MM-DD
Formats taken from calver.org.
Direct Instantiation
A year-month version can be constructed from year and month numbers.
# Construct from numbers
version = YearMonthVersion(2024, 5)
Construction from String
A semantic version can also be created from a string containing a year-month version number by using the
class-method Parse()
. The string is parsed and a year-month
version gets returned.
# Construct from string
version = YearMonthVersion.Parse("2024.05")
Examples
OSVVM: 2024.07
Ubuntu: 2024.10
Condensed Class Definition
@export
class YearMonthVersion(CalendarVersion):
@classmethod
def Parse(cls, versionString: Nullable[str], validator: Nullable[Callable[["YearMonthVersion"], bool]] = None) -> "YearMonthVersion":
pass
@readonly
def Year(self) -> int:
pass
@readonly
def Month(self) -> int:
pass
Direct Instantiation
A year-week version can be constructed from year and month numbers.
# Construct from numbers
version = YearWeekVersion(2024, 5)
Construction from String
A semantic version can also be created from a string containing a year-week version number by using the
class-method Parse()
. The string is parsed and a year-week
version gets returned.
# Construct from string
version = YearWeekVersion.Parse("2024.05")
Examples
Production date codes
Condensed Class Definition
@export
class YearWeekVersion(CalendarVersion):
@classmethod
def Parse(cls, versionString: Nullable[str], validator: Nullable[Callable[["YearWeekVersion"], bool]] = None) -> "YearWeekVersion":
pass
@readonly
def Year(self) -> int:
pass
@readonly
def Week(self) -> int:
pass
Direct Instantiation
A year-release version can be constructed from year and month numbers.
# Construct from numbers
version = YearReleaseVersion(2024, 2)
Construction from String
A semantic version can also be created from a string containing a year-release version number by using the
class-method Parse()
. The string is parsed and a year-release
version gets returned.
# Construct from string
version = YearReleaseVersion.Parse("2024.2")
Examples
Vivado: 2024.1
Condensed Class Definition
@export
class YearReleaseVersion(CalendarVersion):
@classmethod
def Parse(cls, versionString: Nullable[str], validator: Nullable[Callable[["YearReleaseVersion"], bool]] = None) -> "YearReleaseVersion":
pass
@readonly
def Year(self) -> int:
pass
@readonly
def Release(self) -> int:
pass
Direct Instantiation
A year-month-day version can be constructed from year, month and day numbers.
# Construct from numbers
version = YearMonthDayVersion(2024, 10, 5)
Construction from String
A semantic version can also be created from a string containing a year-month-day version number by using the
class-method Parse()
. The string is parsed and a
year-month-day version gets returned.
# Construct from string
version = YearMonthDayVersion.Parse("2024.10.05")
Examples
Furo: 2024.04.27
Condensed Class Definition
@export
class YearMonthDayVersion(CalendarVersion):
@classmethod
def Parse(cls, versionString: Nullable[str], validator: Nullable[Callable[["YearMonthDayVersion"], bool]] = None) -> "YearMonthDayVersion":
pass
@readonly
def Year(self) -> int:
pass
@readonly
def Month(self) -> int:
pass
@readonly
def Day(self) -> int:
pass
VersionRange
A VersionRange
defines a range of versions reaching from a lower to an upper bound.
It equivalently supports semantic and calendar
versions or derived subclasses thereof. When initializing a version range, an optional
RangeBoundHandling
flag specifies if the bounds are inclusive (default) or
exclusive.
Features
- Access bounds and bound handling behavior
The lower bound of the version range can be read or updated by accessing the
LowerBound
property. Similarly, the upper bound of the version range can be read or updated by accessing theUpperBound
property.The behavior how lower and upper bound are handled can be read or modified by accessing the
BoundHandling
property.- Comparison of two version ranges
A version range can be compare to another version range using comparison operators:
<
,<=
,>
,>=
.- Comparison of a version range and a version
A version can be compared with a version range and vise versa using comparison operators:
<
,<=
,>
,>=
.The behavior is influenced by the bound handling behavior.
- Contains checks
A version can be checked if it’s contained in a version range using contains operators:
in
,not in
.The behavior is influenced by the bound handling behavior.
- Intersection
Two version ranges can be intersected using the
&
operator creating a new version range.In case of an empty intersection result, an exception is raised.
Condensed Class Definition
@export
class VersionRange(Generic[V], metaclass=ExtendedType, slots=True):
def __init__(self, lowerBound: V, upperBound: V, boundHandling: RangeBoundHandling = RangeBoundHandling.BothBoundsInclusive) -> None:
@property
def LowerBound(self) -> V:
pass
@property
def UpperBound(self) -> V:
pass
@property
def BoundHandling(self) -> RangeBoundHandling:
pass
def __and__(self, other: Any) -> VersionRange[T]:
pass
def __lt__(self, other: Any) -> bool:
pass
def __le__(self, other: Any) -> bool:
pass
def __gt__(self, other: Any) -> bool:
pass
def __ge__(self, other: Any) -> bool:
pass
def __contains__(self, version: Version) -> bool:
pass
from pyTooling.Versioning import SemanticVersion, VersionRange
versionRange = VersionRange(
lowerBound=SemanticVersion(1, 0, 0),
upperBound=SemanticVersion(1, 9, 0)
)
testVersion = SemanticVersion(1, 4, 3)
if testVersion in versionRange:
pass
from pyTooling.Versioning import SemanticVersion, VersionRange
versionRange = VersionRange(
lowerBound=YearWeekVersion(2023, 34),
upperBound=YearWeekVersion(2023, 51),
boundHandling=RangeBoundHandling.UpperBoundExclusive)
)
testVersion = YearWeekVersion(2023, 51)
if testVersion not in versionRange:
pass
VersionSet
A VersionSet
defines an ordered set (actually a list) of versions. It equivalently
supports semantic and calendar versions or
derived subclasses thereof.
Features
- Accessing versions in the set
The versions within a version set can be accessed via index operation (
__getitem__
) or iterating (__iter__
) the version set.The number of elements is accessible via length operation (
__len__
).- Comparison of two version sets
A version set can be compare to another version set using comparison operators:
<
,<=
,>
,>=
.- Comparison of a version set and a version
A version can be compared with a version set and vise versa using comparison operators:
<
,<=
,>
,>=
.- Contains checks
A version can be checked if it’s contained in a version set using contains operators:
in
,not in
.- Intersection
Two version set can be intersected using the
&
operator creating a new version set.In case of an empty intersection result, an exception is raised.
- Union
Two version sets can be united using the
|
operator creating a new version set.
Condensed Class Definition
@export
class VersionSet(Generic[V], metaclass=ExtendedType, slots=True):
def __init__(self, versions: Union[Version, Iterable[V]]):
pass
def __and__(self, other: VersionSet[V]) -> VersionSet[T]:
pass
def __or__(self, other: VersionSet[V]) -> VersionSet[T]:
pass
def __lt__(self, other: Any) -> bool:
pass
def __le__(self, other: Any) -> bool:
pass
def __gt__(self, other: Any) -> bool:
pass
def __ge__(self, other: Any) -> bool:
pass
def __contains__(self, version: V) -> bool:
pass
def __len__(self) -> int:
pass
def __iter__(self) -> Iterator[V]:
pass
def __getitem__(self, index: int) -> V:
pass
from pyTooling.Versioning import SemanticVersion, VersionSet
versionSet = VersionSet((
YearMonthVersion(2024, 4),
YearMonthVersion(2025, 1),
YearMonthVersion(2019, 3)
))
testVersion = YearMonthVersion(2019, 3)
if testVersion in versionSet:
pass
from pyTooling.Versioning import SemanticVersion, VersionSet
versionSet = VersionSet((
YearMonthVersion(2024, 4),
YearMonthVersion(2025, 1),
YearMonthVersion(2019, 3)
))
for version in versionSet:
pass