Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions docker/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
import shlex
import string
from datetime import datetime, timezone
from packaging.version import Version
from functools import lru_cache
from itertools import zip_longest

from .. import errors
from ..constants import DEFAULT_HTTP_HOST
Expand Down Expand Up @@ -43,6 +44,7 @@ def decode_json_header(header):
return json.loads(data)


@lru_cache(maxsize=None)
def compare_version(v1, v2):
"""Compare docker versions

Expand All @@ -55,14 +57,20 @@ def compare_version(v1, v2):
>>> compare_version(v2, v2)
0
"""
s1 = Version(v1)
s2 = Version(v2)
if s1 == s2:
if v1 == v2:
return 0
elif s1 > s2:
return -1
else:
return 1
# Split into `sys.version_info` like tuples.
s1 = tuple(int(p) for p in v1.split('.'))
s2 = tuple(int(p) for p in v2.split('.'))
# Compare each component, padding with 0 if necessary.
for c1, c2 in zip_longest(s1, s2, fillvalue=0):
if c1 == c2:
continue
elif c1 > c2:
return -1
else:
return 1
return 0


def version_lt(v1, v2):
Expand Down
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
SOURCE_DIR = os.path.join(ROOT_DIR)

requirements = [
'packaging >= 14.0',
'requests >= 2.26.0',
'urllib3 >= 1.26.0',
]
Expand Down
27 changes: 22 additions & 5 deletions tests/unit/utils_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@
from docker.api.client import APIClient
from docker.constants import IS_WINDOWS_PLATFORM, DEFAULT_DOCKER_API_VERSION
from docker.errors import DockerException
from docker.utils import (convert_filters, convert_volume_binds,
decode_json_header, kwargs_from_env, parse_bytes,
parse_devices, parse_env_file, parse_host,
parse_repository_tag, split_command, update_headers)
from docker.utils import (
compare_version, convert_filters, convert_volume_binds, decode_json_header,
format_environment, kwargs_from_env, parse_bytes, parse_devices,
parse_env_file, parse_host, parse_repository_tag, split_command,
update_headers, version_gte, version_lt
)
from docker.utils.ports import build_port_bindings, split_port
from docker.utils.utils import format_environment

TEST_CERT_DIR = os.path.join(
os.path.dirname(__file__),
Expand Down Expand Up @@ -629,3 +630,19 @@ def test_format_env_no_value(self):
'BAR': '',
}
assert sorted(format_environment(env_dict)) == ['BAR=', 'FOO']


def test_compare_versions():
assert compare_version('1.0', '1.1') == 1
assert compare_version('1.10', '1.1') == -1
assert compare_version('1.10', '1.10') == 0
assert compare_version('1.10.0', '1.10.1') == 1
assert compare_version('1.9', '1.10') == 1
assert compare_version('1.9.1', '1.10') == 1
# Test comparison helpers
assert version_lt('1.0', '1.27')
assert version_gte('1.27', '1.20')
# Test zero-padding
assert compare_version('1', '1.0') == 0
assert compare_version('1.10', '1.10.1') == 1
assert compare_version('1.10.0', '1.10') == 0