Skip to content

Commit 7057dc5

Browse files
committed
Fix python-semver#244: Allow list & str for comparison
The VersionInfo.compare method allows already VersionInfo, dict, tuple/list and str. * Extend list of allowed types in comparator with list and str. * Rewrite case test_should_not_allow_to_compare_version_with_string -> test_should_compare_version_string * Add new test cases: - test_should_compare_version_list - test_should_not_allow_to_compare_invalid_versionstring * Use pytest.mark.parametrize for test_should_compare_version_tuples * Update usage.rst to document all possibilities * Update CHANGELOG
1 parent d69e7c4 commit 7057dc5

File tree

4 files changed

+139
-31
lines changed

4 files changed

+139
-31
lines changed

CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Bug Fixes
2424

2525
* :gh:`224` (:pr:`226`): In ``setup.py``, replaced in class ``clean``,
2626
``super(CleanCommand, self).run()`` with ``CleanCommand.run(self)``
27+
* :gh:`244` (:pr:`245`): Allow comparison with ``VersionInfo``, tuple/list, dict, and string.
2728

2829

2930
Additions

docs/usage.rst

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ To compare two versions depends on your type:
295295
The return value is negative if ``version1 < version2``, zero if
296296
``version1 == version2`` and strictly positive if ``version1 > version2``.
297297

298-
* **Two** :class:`semver.VersionInfo` **types**
298+
* **Two** :class:`semver.VersionInfo` **instances**
299299

300300
Use the specific operator. Currently, the operators ``<``,
301301
``<=``, ``>``, ``>=``, ``==``, and ``!=`` are supported::
@@ -307,24 +307,68 @@ To compare two versions depends on your type:
307307
>>> v1 > v2
308308
False
309309

310-
* **A** :class:`semver.VersionInfo` **type and a** ``tuple``
310+
* **A** :class:`semver.VersionInfo` **type and a** :func:`tuple` **or** :func:`list`
311311

312312
Use the operator as with two :class:`semver.VersionInfo` types::
313313

314314
>>> v = semver.VersionInfo.parse("3.4.5")
315315
>>> v > (1, 0)
316316
True
317-
>>> v < (3, 5)
317+
>>> v < [3, 5]
318318
True
319319

320320
The opposite does also work::
321321

322322
>>> (1, 0) < v
323323
True
324-
>>> (3, 5) > v
324+
>>> [3, 5] > v
325325
True
326326

327-
Other types cannot be compared (like dictionaries, lists etc).
327+
* **A** :class:`semver.VersionInfo` **type and a** :func:`str`
328+
329+
You can use also raw strings to compare::
330+
331+
>>> v > "1.0.0"
332+
True
333+
>>> v < "3.5.0"
334+
True
335+
336+
The opposite does also work::
337+
338+
>>> "1.0.0" < v
339+
True
340+
>>> "3.5.0" > v
341+
True
342+
343+
However, if you compare incomplete strings, you get a :class:`ValueError` exception::
344+
345+
>>> v > "1.0"
346+
Traceback (most recent call last):
347+
...
348+
ValueError: 1.0 is not valid SemVer string
349+
350+
* **A** :class:`semver.VersionInfo` **type and a** :func:`dict`
351+
352+
You can also use a dictionary. In contrast to strings, you can have an "incomplete"
353+
version (as the other parts are set to zero)::
354+
355+
>>> v > dict(major=1)
356+
True
357+
358+
The opposite does also work::
359+
360+
>>> dict(major=1) < v
361+
True
362+
363+
If the dictionary contains unknown keys, you get a :class:`TypeError` exception::
364+
365+
>>> v > dict(major=1, unknown=42)
366+
Traceback (most recent call last):
367+
...
368+
TypeError: __init__() got an unexpected keyword argument 'unknown'
369+
370+
371+
Other types cannot be compared.
328372

329373
If you need to convert some types into other, refer to :ref:`sec.convert.versions`.
330374

semver.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def comparator(operator):
112112

113113
@wraps(operator)
114114
def wrapper(self, other):
115-
comparable_types = (VersionInfo, dict, tuple)
115+
comparable_types = (VersionInfo, dict, tuple, list, str)
116116
if not isinstance(other, comparable_types):
117117
raise TypeError(
118118
"other type %r must be in %r" % (type(other), comparable_types)

test_semver.py

Lines changed: 88 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -557,37 +557,100 @@ def test_should_compare_version_dictionaries():
557557
assert not (v1 == v4)
558558

559559

560-
def test_should_compare_version_tuples():
561-
v0 = VersionInfo(major=0, minor=4, patch=5, prerelease="pre.2", build="build.4")
562-
v1 = VersionInfo(major=3, minor=4, patch=5, prerelease="pre.2", build="build.4")
563-
for t in (
560+
@pytest.mark.parametrize(
561+
"t", # fmt: off
562+
(
564563
(1, 0, 0),
565564
(1, 0),
566565
(1,),
567566
(1, 0, 0, "pre.2"),
568567
(1, 0, 0, "pre.2", "build.4"),
569-
):
570-
assert v0 < t
571-
assert v0 <= t
572-
assert v0 != t
573-
assert not v0 == t
574-
assert v1 > t
575-
assert v1 >= t
576-
# Symmetric
577-
assert t > v0
578-
assert t >= v0
579-
assert t < v1
580-
assert t <= v1
581-
assert t != v0
582-
assert not t == v0
583-
584-
585-
def test_should_not_allow_to_compare_version_with_string():
568+
), # fmt: on
569+
)
570+
def test_should_compare_version_tuples(t):
571+
v0 = VersionInfo(major=0, minor=4, patch=5, prerelease="pre.2", build="build.4")
586572
v1 = VersionInfo(major=3, minor=4, patch=5, prerelease="pre.2", build="build.4")
587-
with pytest.raises(TypeError):
588-
v1 > "1.0.0"
589-
with pytest.raises(TypeError):
590-
"1.0.0" > v1
573+
574+
assert v0 < t
575+
assert v0 <= t
576+
assert v0 != t
577+
assert not v0 == t
578+
assert v1 > t
579+
assert v1 >= t
580+
# Symmetric
581+
assert t > v0
582+
assert t >= v0
583+
assert t < v1
584+
assert t <= v1
585+
assert t != v0
586+
assert not t == v0
587+
588+
589+
@pytest.mark.parametrize(
590+
"lst", # fmt: off
591+
(
592+
[1, 0, 0],
593+
[1, 0],
594+
[1],
595+
[1, 0, 0, "pre.2"],
596+
[1, 0, 0, "pre.2", "build.4"],
597+
), # fmt: on
598+
)
599+
def test_should_compare_version_list(lst):
600+
v0 = VersionInfo(major=0, minor=4, patch=5, prerelease="pre.2", build="build.4")
601+
v1 = VersionInfo(major=3, minor=4, patch=5, prerelease="pre.2", build="build.4")
602+
603+
assert v0 < lst
604+
assert v0 <= lst
605+
assert v0 != lst
606+
assert not v0 == lst
607+
assert v1 > lst
608+
assert v1 >= lst
609+
# Symmetric
610+
assert lst > v0
611+
assert lst >= v0
612+
assert lst < v1
613+
assert lst <= v1
614+
assert lst != v0
615+
assert not lst == v0
616+
617+
618+
@pytest.mark.parametrize(
619+
"s", # fmt: off
620+
(
621+
"1.0.0",
622+
# "1.0",
623+
# "1",
624+
"1.0.0-pre.2",
625+
"1.0.0-pre.2+build.4",
626+
), # fmt: on
627+
)
628+
def test_should_compare_version_string(s):
629+
v0 = VersionInfo(major=0, minor=4, patch=5, prerelease="pre.2", build="build.4")
630+
v1 = VersionInfo(major=3, minor=4, patch=5, prerelease="pre.2", build="build.4")
631+
632+
assert v0 < s
633+
assert v0 <= s
634+
assert v0 != s
635+
assert not v0 == s
636+
assert v1 > s
637+
assert v1 >= s
638+
# Symmetric
639+
assert s > v0
640+
assert s >= v0
641+
assert s < v1
642+
assert s <= v1
643+
assert s != v0
644+
assert not s == v0
645+
646+
647+
@pytest.mark.parametrize("s", ("1", "1.0", "1.0.x"))
648+
def test_should_not_allow_to_compare_invalid_versionstring(s):
649+
v = VersionInfo(major=3, minor=4, patch=5, prerelease="pre.2", build="build.4")
650+
with pytest.raises(ValueError):
651+
v < s
652+
with pytest.raises(ValueError):
653+
s > v
591654

592655

593656
def test_should_not_allow_to_compare_version_with_int():

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy