Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

packaging.version as a CLI tool #795

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open

Conversation

mgaitan
Copy link

@mgaitan mgaitan commented Apr 16, 2024

I want to propose this simple CLI tool in the packaging.version module to perform semantic version comparisons directly from the command line. This utility is modeled after dpkg --compare-versions but designed to be platform-agnostic, filling a gap for non-Debian users and providing a Python-native solution.

Version comparison is a common requirement in deployment scripts, package management, and development workflows. Currently, developers resort to complex shell scripts or third-party tools to compare versions. Examples of community solutions include intricate bash functions and snippets found on Stack Overflow and GitHub Gists that, while functional for basic cases, vary in reliability and can be unnecessarily complex 1, 2, 3.

My proposal leverages the robustness of the packaging.version.Version class for parsing and comparing semantic versions, supporting standard comparison operators (e.g., lt, gt, eq) and provide straightforward syntax that resembles the mentioned dpkg command

Usage

$ python -m packaging.version --help
usage: version.py [-h] version1 {lt,le,eq,ne,ge,gt,lt-nl,le-nl,ge-nl,gt-nl,<,<<,<=,=,>=,>>,>} version2

Compare two semantic versions.

positional arguments:
  version1              First version to compare
  {lt,le,eq,ne,ge,gt,lt-nl,le-nl,ge-nl,gt-nl,<,<<,<=,=,>=,>>,>}
                        Comparison operator
  version2              Second version to compare

options:
  -h, --help            show this help message and exit

$ python -m packaging.version 1.0b gt 0.9   
$ echo $?
0

$ python -m packaging.version 1.0b eq 0.9   # Should exit with status 1
$ echo $?
1

$ python -m packaging.version 1.0b foo 0.9
usage: version.py [-h] version1 {lt,le,eq,ne,ge,gt,lt-nl,le-nl,ge-nl,gt-nl,<,<<,<=,=,>=,>>,>} version2
version.py: error: argument operator: invalid choice: 'foo' (choose from 'lt', 'le', 'eq', 'ne', 'ge', 'gt', 'lt-nl', 'le-nl', 'ge-nl', 'gt-nl', '<', '<<', '<=', '=', '>=', '>>', '>')
$ echo $?
2

$ python -m packaging.version non-version eq 0.9
usage: version.py [-h] version1 {lt,le,eq,ne,ge,gt,lt-nl,le-nl,ge-nl,gt-nl,<,<<,<=,=,>=,>>,>} version2
version.py: error: argument version1: invalid Version value: 'non-version'
$ echo $?
2

@brettcannon
Copy link
Member

What does "nl" mean for those variant comparators? And why do they mean the left-hand side is less than the right-hand no matter what? And what no e.g., eq-nl? And why both e.g., lt and < supported?

@mgaitan
Copy link
Author

mgaitan commented Sep 9, 2024

Hi @brettcannon,

The "nl" in those variant comparators comes from dpkg --compare-versions, which I originally intended to support as a drop-in replacement. From the manpage:

There are two groups of operators, which differ in how they treat an empty ver1 or ver2. These treat an empty version as earlier than any version: lt le eq ne ge gt. These treat an empty version as later than any version: lt-nl le-nl ge-nl gt-nl.

Regarding the lack of an eq-nl operator, it's likely because version equality doesn't depend on whether one of the versions is empty—if both versions are non-empty, eq handles it naturally.

However, I decided to remove support for *-nl in this tool because the version arguments are mandatory. If an invalid version is provided, the tool will exit with code 2. If needed, this can still be converted to exit code 0 using shell tools.

I also removed the non-textual operators <, <<, <=, =, >=, >>, >.

So, while the tool is still inspired by dpkg, it’s not a compatible API anymore, but it is simpler and still useful.

@uranusjr
Copy link
Member

I don’t really mind, but aren’t non-textual operators more readable than lt ge etc?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants