Skip to main content

Versio

Latin

Noun 1. a turning, change, version

Versio is a generic version class that supports comparison and version bumping (incrementing by part, for example you may bump the minor part of ‘1.2.3’ yielding ‘1.3.0’).

Four version schemes are included:

  • Simple3VersionScheme which supports 3 numerical part versions (A.B.C where A, B, and C are integers)

  • Simple4VersionScheme which supports 4 numerical part versions (A.B.C.D where A, B, C, and D are integers)

  • Pep440VersionScheme which supports PEP 440 (http://www.python.org/dev/peps/pep-0440/) versions (N[.N]+[{a|b|c|rc}N][.postN][.devN][+local])

  • PerlVersionScheme which supports 2 numerical part versions where the second part is at least two digits (A.BB where A and B are integers and B is zero padded on the left. For example: 1.02, 1.34, 1.567)

If you don’t specify which version scheme the version instance uses, then it will use the first scheme from the SupportedVersionSchemes list that successfully parses the version string

By default, Pep440VersionScheme is the supported scheme. To change to a different list of schemes, use the Version.set_supported_version_schemes(schemes). For example:

from versio.version_scheme import Simple3VersionScheme, PerlVersionScheme
Version.set_supported_version_schemes([Simple3VersionScheme, PerlVersionScheme])

In addition, you may define your own version scheme by creating a new VersionScheme instance.

The VersionScheme class defines the version scheme.

A version scheme consists of:

  • a name,

  • a regular expression used to parse the version string,

  • the regular expression flags to use (mainly to allow verbose regexes),

  • a format string used to reassemble the parsed version into a string,

  • an optional list of field types (if not specified, assumes all fields are strings),

  • a list of field names used for accessing the components of the version.

  • an optional subfield dictionary with the key being a field name and the value being a list of sub field names. For example, in the Pep440VersionScheme, the “Release” field may contain multiple parts, so we use subfield names for the parts. Say we have a version of “1.2.3rc1”, the “1.2.3” is the release field, then “1” is the “major” subfield, “2” is the “minor” subfield, and “3” is the “tiny” subfield.

  • a “clear” value used to set the field values to the right of the field being bumped,

  • a sequence dictionary where the keys are the field names and the values are a list of allowed values. The list must be in bump order. Bumping the last value in the list has no effect.

Note, you need to manually maintain consistency between the regular expression, the format string, the optional field types, and the fields list. For example, if your version scheme has N parts, then the regular expression should match into N groups, the format string should expect N arguments to the str.format() method, and there must be N unique names in the fields list.

Installation

From pypi:

pip install Versio

Usage

First let’s just play with the comparing and bumping versions:

>>> from versio.version import Version
>>> from versio.version_scheme import Pep440VersionScheme
>>> v1 = Version('1.2.3rc4.post5.dev6', scheme=Pep440VersionScheme)
>>> v2 = Version('1.2.3rc4.post5.dev7', scheme=Pep440VersionScheme)
>>> v1 == v2
False
>>> v1 < v2
True
>>> v1.bump('dev')
True
>>> str(v1)
'1.2.3rc4.post5.dev7'
>>> v1 == v2
True
>>> v1.bump('pre')
True

Now let’s look in the PEP 440 scheme:

>>> Pep440VersionScheme.fields
['release', 'pre', 'post', 'dev', 'local']
>>> Pep440VersionScheme.format_str
'{0}{1}{2}{3}{4}'

The fields are used by the bump(field) method in the above example. We skipped bumping the release above so let’s do it here:

>>> v1 = Version('1.2.3rc4.post5.dev6', scheme=Pep440VersionScheme)
>>> str(v1)
'1.2.3rc4.post5.dev6'
>>> v1.bump('release')
True
>>> str(v1)
'1.2.4'

For PEP 440, the release part is defined as “N[.N]+”. We can bump specific parts of the release by using an index like:

>>> v1.bump('release', 2)
True
>>> str(v1)
'1.2.5'
>>> v1.bump('release', 1)
True
>>> str(v1)
'1.3.0'
>>> v1.bump('release', 0)
True
>>> str(v1)
'2.0.0'

To use a name directly, we use the concept of subfields which are mapped to a field/index pair:

>>> Pep440VersionScheme.subfields
{'tiny2': ['Release', 3], 'major': ['Release', 0], 'tiny': ['Release', 2], 'minor': ['Release', 1]}

>>> v1 = Version('1.2.3rc4.post5.dev6', scheme=Pep440VersionScheme)
>>> str(v1)
'1.2.3rc4.post5.dev6'
>>> v1.bump('tiny')
True
>>> str(v1)
'1.2.4'
>>> v1.bump('minor')
True
>>> str(v1)
'1.3.0'
>>> v1.bump('major')
True
>>> str(v1)
'2.0.0'

Now that you’ve seen the version scheme in action, let’s take a look at how it is defined:

Pep440VersionScheme = VersionScheme(name="pep440",
                                    parse_regex=r"""
                                    ^
                                    (\d[\.\d]*(?<= \d))
                                    ((?:[abc]|rc)\d+)?
                                    (?:(\.post\d+))?
                                    (?:(\.dev\d+))?
                                    (?:(\+(?![.])[a-zA-Z0-9\.]*[a-zA-Z0-9]))?
                                    $
                                    """,
                                    compare_order=[0, 1, 2, 3, 4],
                                    compare_fill=['~', '~', '', '~', ''],
                                    parse_flags=re.VERBOSE,
                                    clear_value=None,
                                    format_str='{0}{1}{2}{3}{4}',
                                    fields=['Release', 'Pre', 'Post', 'Dev', 'Local'],
                                    subfields={'Release': ['Major', 'Minor', 'Tiny', 'Tiny2']},
                                    sequences={'Pre': ['a', 'b', 'c', 'rc'],
                                               'Post': ['.post'],
                                               'Dev': ['.dev'],
                                               'Local': ['+']},
                                    description=dedent("""\
                                        PEP 440
                                        Public version identifiers MUST comply with the following scheme:

                                        N[.N]+[{a|b|c|rc}N][.postN][.devN][+local]

                                        Public version identifiers MUST NOT include leading or trailing whitespace.

                                        Public version identifiers MUST be unique within a given distribution.

                                        Public version identifiers are separated into up to five segments:

                                            Release segment: N[.N]+
                                            Pre-release segment: {a|b|c|rc}N
                                            Post-release segment: .postN
                                            Development release segment: .devN
                                            Local release segment: +local

                                        The local version labels MUST be limited to the following set of permitted
                                        characters:

                                            ASCII letters ( [a-zA-Z] )
                                            ASCII digits ( [0-9] )
                                            periods ( . )

                                        Local version labels MUST start and end with an ASCII letter or digit.
                                    """))

The parse_regex and parse_flags do what you think by parsing a string into a list containing regex groups, except the group list is zero indexed to the first matching group.

The format_str and format_types control how the version is converted to a string in __str__(). Basically format_str.format(*args) is called where the args is a list built by casting each of the version’s groups using the corresponding type from the format_types list. If you don’t specify a format_types, then each group is cast as a str.

The clear_value typically should be ‘0’ for numeric versions and None for non-numeric. Basically it specifies what to put in the groups to the right of the group being bumped.

The sequences dictionary maps text to prepend to a group when formatting. The dictionary keys must be in the fields list. To progress thru the sequence, bump the field with an index of 0. An index of 1 bumps the numeric part of the group. For example:

>>> v1 = Version('1.2.3a4.post5.dev6', scheme=Pep440VersionScheme)
>>> str(v1)
'1.2.3a4.post5.dev6'
>>> v1.bump('pre', 0)
True
>>> str(v1)
'1.2.3b1'
>>> v1.bump('pre', 1)
True
>>> str(v1)
'1.2.3b2'
>>> v1.bump('pre', 0)
True
>>> str(v1)
'1.2.3c1'
>>> v1.bump('pre', 0)
True
>>> str(v1)
'1.2.3rc1'
>>> v1.bump('pre', 0)
False
>>> str(v1)
'1.2.3rc1'

Notice that bumping fails at the end of the sequence and the version is not changed. You can override this behavior by setting the promote argument to True, resulting in the field being removed at the end of the field’s sequence. For example:

>>> v1 = Version('1.2.3rc1', scheme=Pep440VersionScheme)
>>> str(v1)
'1.2.3rc1'
>>> v1.bump('pre', 0)
False
>>> str(v1)
'1.2.3rc1'
>>> v1.bump('pre', 0, promote=True)
True
>>> str(v1)
'1.2.3'

That’s it.

There are more examples in tests/version_test.py. You may test directly with py.test or against multiple python versions with tox.

Enjoy!

Metadata

Release files for Versio 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for Versio 0.5.0
File Size Uploaded
Versio-0.5.0.tar.gz 31.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for Versio 0.5.0
File Interpreter ABI Platform
Versio-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 44.2 kB

Release files / Versio-0.5.0.tar.gz

Download URL Versio-0.5.0.tar.gz
Size 31.3 kB
Tags Source
SHA-256 checksum
How to use checksums
64b3bb4cc285b5c7cf3afb3ea63bc6b0df1e7cb1db14e77a8b7ec81b8c8b058e
BLAKE2b-256 checksum
How to use checksums
89837a7d329cb8939b3b8c05c45cbf2c2af73499a417aa6306da2ccbf2be8638
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.1.1 pkginfo/1.4.2 requests/2.22.0 setuptools/57.0.0 requests-toolbelt/0.8.0 tqdm/4.30.0 CPython/3.8.10

Release files / Versio-0.5.0-py3-none-any.whl

Download URL Versio-0.5.0-py3-none-any.whl
Size 12.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
68fde9c516bf352d9912a401202555dd9d7c4e2626f578fe41a7079159e43003
BLAKE2b-256 checksum
How to use checksums
cd122b9ca783aea66cb246b2997448a0842e11953037427e39731541cf439692
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.1.1 pkginfo/1.4.2 requests/2.22.0 setuptools/57.0.0 requests-toolbelt/0.8.0 tqdm/4.30.0 CPython/3.8.10

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

0.4.0

1 release file

0.3.0

1 release file

0.2.1

1 release file

0.1.2

1 release file

0.1.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page