Guide¶
This module covers the 2.0.0 version of the SemVer scheme, with additional extensions:
- Coercing any version string into a SemVer version, through
Version.coerce()
; - Comparing versions;
- Computing next versions;
- Modelling version range specifcations, and choosing the best match – for both its custom logic, and NPM semantics (custom range specification schemes can be added).
Version basics¶
Building Version
instances¶
The core of the module is the Version
class; it is usually instantiated
from a version string:
>>> import semantic_version as semver
>>> v = semver.Version("0.1.1")
The version’s components are available through its attributes:
major
,minor
,patch
are integers:>>> v.major 0 >>> v.minor 1 >>> v.patch 1
The
prerelease
andbuild
attributes are iterables of text elements:>>> v2 = semver.Version("0.1.1-dev+23.git2") >>> v2.prerelease ["dev"] >>> v2.build ["23", "git2"]
One may also build a Version
from named components directly:
>>> semantic_version.Version(major=0, minor=1, patch=2)
Version('0.1.2')
In that case, major
, minor
and patch
are mandatory, and must be integers.
prerelease
and build
, if provided, must be tuples of strings:
>>> semantic_version.Version(major=0, minor=1, patch=2, prerelease=('alpha', '2'))
Version('0.1.2-alpha.2')
If the provided version string is invalid, a ValueError
will be raised:
>>> semver.Version('0.1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/rbarrois/dev/semantic_version/src/semantic_version/base.py", line 64, in __init__
major, minor, patch, prerelease, build = self.parse(version_string, partial)
File "/Users/rbarrois/dev/semantic_version/src/semantic_version/base.py", line 86, in parse
raise ValueError('Invalid version string: %r' % version_string)
ValueError: Invalid version string: '0.1'
Working with non-SemVer version strings¶
Some user-supplied input might not match the semantic version scheme.
For such cases, the Version.coerce
method will try to convert any
version-like string into a valid semver version:
>>> semver.Version.coerce('0')
Version('0.0.0')
>>> semver.Version.coerce('0.1.2.3.4')
Version('0.1.2+3.4')
>>> semver.Version.coerce('0.1.2a3')
Version('0.1.2-a3')
Comparing versions¶
Versions can be compared, following the SemVer scheme:
>>> semver.Version("0.1.0") < semver.Version("0.1.1")
True
>>> max(
... semver.Version("0.1.0"),
... semver.Version("0.2.2"),
... semver.Version("0.1.1"),
... semver.Version("0.2.2-rc1"),
... )
Version("0.2.2")
Note
As defined in SemVer, build metadata is ignored in comparisons, but not in equalities:
>>> semver.Version("0.1.2") <= semver.Version("0.1.2+git2")
True
>>> semver.Version("0.1.2") >= semver.Version("0.1.2+git2")
True
>>> semver.Version("0.1.2") == semver.Version("0.1.2+git2")
False
Iterating versions¶
One can get a new version that represents a bump in one of the version levels
through the Version.next_major()
, Version.next_minor()
or
Version.next_patch()
functions:
>>> v = semver.Version('0.1.1+build')
>>> new_v = v.next_major()
>>> str(new_v)
'1.0.0'
>>> v = semver.Version('1.1.1+build')
>>> new_v = v.next_minor()
>>> str(new_v)
'1.2.0'
>>> v = semver.Version('1.1.1+build')
>>> new_v = v.next_patch()
>>> str(new_v)
'1.1.2'
Note
- If the version includes
build
orprerelease
metadata, that value will be empty in the next version; - The next patch following a version with a pre-release identifier
is the same version with its prerelease and build identifiers removed:
Version("0.1.1-rc1").next_patch() == Version("0.1.1")
- Pre-release and build naming schemes are often custom and specific
to a project’s internal design; thus, the library can’t provide a
next_xxx
method for those fields.
One may also truncate versions through the Version.truncate()
method,
removing components beyond the selected level:
>>> v = semver.Version("0.1.2-dev+git3")
>>> v.truncate("prerelease")
Version("0.1.2-dev")
>>> v.truncate("minor")
Version("0.1.0")
Range specifications¶
Comparing version numbers isn’t always enough; in many situations, one needs to define a range of acceptable versions.
That notion is not defined in SemVer; moreover, several systems exists, with their own notations.
The semantic_version
package provides a couple of implementations for these
notions:
SimpleSpec
is a simple implementation, with reasonable expectations;NpmSpec
sticks to the NPM specification.
Further schemes can be built in a similar manner, relying on the BaseSpec
class for basics.
Core API¶
The core API is provided by the BaseSpec
class.
Note
These examples use SimpleSpec
in order to be easily reproduced
by users, but only exhibit the standard parts of the interface.
It is possible to check whether a given Version
matches a
BaseSpec
through match()
:
>>> s = semver.SimpleSpec(">=0.1.1")
>>> s.match(Version("0.1.1"))
True
>>> s.match(Version("0.1.0"))
False
This feature is also available through the in
keyword:
>>> s = semver.SimpleSpec(">=0.1.1")
>>> Version("0.1.1") in s
True
>>> Version("0.1.0") in s
False
A specification can filter compatible values from an iterable of versions
with filter()
:
>>> s = semver.SimpleSpec(">=0.2.1")
>>> versions = [
... Version("0.1.0"),
... Version("0.2.0"),
... Version("0.3.0"),
... Version("0.4.0"),
... ]
>>> list(s.filter(versions))
[Version("0.3.0"), Version("0.4.0")]
It can also select the “best” version from such an iterable through
select()
:
>>> s = semver.SimpleSpec(">=0.2.1")
>>> versions = [
... Version("0.1.0"),
... Version("0.2.0"),
... Version("0.3.0"),
... Version("0.4.0"),
... ]
>>> s.select(versions)
Version("0.4.0")
The SimpleSpec
scheme¶
The SimpleSpec
provides a hopefully intuitive version range
specification scheme:
- A specification expression is composed of comma-separated clauses;
- Each clause can be:
- An equality match (
==
or!=
); - A comparison (
>
,>=
,<
,<=
); - A compatible release clause, PyPI style (
~=2.2
for>=2.2.0,<3.0.0
); - An NPM style clause:
~1.2.3
for>=1.2.3,<1.3.0
;^1.3.4
for>=1.3.4,<2.0.0
;
- An equality match (
- The range in each clause may include a wildcard:
==0.1.*
maps to>=0.1.0,<0.2.0
;==1.*
or==1.*.*
map to>=1.0.0,<2.0.0
Special matching rules
When testing a Version
against a SimpleSpec
, comparisons are
adjusted for common user expectations; thus, a pre-release version (1.0.0-alpha
)
will not satisfy the ==1.0.0
SimpleSpec
.
Pre-release identifiers will only be compared if included in the BaseSpec
definition or (for the empty pre-release number) if a single dash is appended
(1.0.0-
):
>>> Version('0.1.0-alpha') in SimpleSpec('<0.1.0') # No pre-release identifier
False
>>> Version('0.1.0-alpha') in SimpleSpec('<0.1.0-') # Include pre-release in checks
True
Build metadata has no ordering; thus, the only meaningful comparison including build metadata is equality:
>>> Version('1.0.0+build2') in SimpleSpec('<=1.0.0') # Build metadata ignored
True
>>> Version('1.0.0+build1') in SimpleSpec('==1.0.0+build2') # Include build in checks
False
Note
The full documentation is provided in the reference section
for the SimpleSpec
class.
The NpmSpec
scheme¶
The NpmSpec
class implements the full NPM specification (from
https://github.com/npm/node-semver#ranges):
>>> semver.Version("0.1.2") in semver.NpmSpec("0.1.0-alpha.2 .. 0.2.4")
True
>>> semver.Version('0.1.2') in semver.NpmSpec('>=0.1.1 <0.1.3 || 2.x')
True
>>> semver.Version('2.3.4') in semver.NpmSpec('>=0.1.1 <0.1.3 || 2.x')
True
Using with Django¶
The semantic_version.django_fields
module provides django fields to
store Version
or BaseSpec
objects.
More documentation is available in the Interaction with Django section.