8000 Fix #284: Implement tilde and caret matching · python-semver/python-semver@ac78ab2 · GitHub
[go: up one dir, main page]

Skip to content

Commit ac78ab2

Browse files
committed
Fix #284: Implement tilde and caret matching
* Introduce Spec class to deal with such comparisons * Improve documentation * Simplify code in Version.match (delegates to Spec.match)
1 parent 37326d5 commit ac78ab2

File tree

11 files changed

+1087
-203
lines changed

11 files changed

+1087
-203
lines changed

docs/api.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,29 @@ Version Handling :mod:`semver.version`
5454

5555
.. autoclass:: semver.version.Version
5656
:members:
57+
:inherited-members:
5758
:special-members: __iter__, __eq__, __ne__, __lt__, __le__, __gt__, __ge__, __getitem__, __hash__, __repr__, __str__
59+
60+
61+
Version Regular Expressions :mod:`semver.versionregex`
62+
------------------------------------------------------
63+
64+
.. automodule:: semver.versionregex
65+
66+
.. autoclass:: semver.versionregex.VersionRegex
67+
:members:
68+
:private-members:
69+
70+
71+
Spec Handling :mod:`semver.spec`
72+
--------------------------------
73+
74+
.. automodule:: semver.spec
75+
76+
.. autoclass:: semver.spec.Spec
77+
:members: match
78+
:private-members: _caret, _tilde
79+
:special-members: __eq__, __ne__, __lt__, __le__, __gt__, __ge__, __repr__, __str__
80+
81+
.. autoclass:: semver.spec.InvalidSpecifier
82+

docs/conf.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,11 @@ def find_version(*file_paths):
118118
# Markup to shorten external links
119119
# See https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html
120120
extlinks = {
121-
"gh": ("https://github.com/python-semver/python-semver/issues/%s", "#"),
122-
"pr": ("https://github.com/python-semver/python-semver/pull/%s", "PR #"),
121+
"gh": ("https://github.com/python-semver/python-semver/issues/%s", "#%s"),
122+
"pr": ("https://github.com/python-semver/python-semver/pull/%s", "PR #%s"),
123123
}
124124

125+
125126
# -- Options for HTML output ----------------------------------------------
126127

127128
# The theme to use for HTML and HTML Help pages. See the documentation for

docs/usage/compare-versions-through-expression.rst

Lines changed: 97 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ Currently, the match expression supports the following operators:
1616
* ``<=`` smaller or equal than
1717
* ``==`` equal
1818
* ``!=`` not equal
19+
* ``~`` for tilde ranges, see :ref:`tilde_expressions`
20+
* ``^`` for caret ranges, see :ref:`caret_expressions`
1921

2022
That gives you the following possibilities to express your condition:
2123

@@ -28,10 +30,10 @@ That gives you the following possibilities to express your condition:
2830
False
2931
3032
If no operator is specified, the match expression is interpreted as a
31-
version to be compared for equality. This allows handling the common
32-
case of version compatibility checking through either an exact version
33-
or a match expression very easy to implement, as the same code will
34-
handle both cases:
33+
version to be compared for equality with the ``==`` operator.
34+
This allows handling the common case of version compatibility checking
35+
through either an exact version or a match expression very easy to
36+
implement, as the same code will handle both cases:
3537

3638
.. code-block:: python
3739
@@ -40,3 +42,94 @@ handle both cases:
4042
True
4143
>>> version.match("3.5.1")
4244
False
45+
46+
47+
Using the :class:`Spec <semver.spec.Spec>` class
48+
------------------------------------------------
49+
50+
The :class:`Spec <semver.spec.Spec>` class is the underlying object
51+
which makes comparison possible.
52+
53+
It supports comparisons through usual Python operators:
54+
55+
.. code-block:: python
56+
57+
>>> Spec("1.2") > '1.2.1'
58+
True
59+
>>> Spec("1.3") == '1.3.10'
60+
False
61+
62+
If you need to reuse a ``Spec`` object, use the :meth:`match <semver.spec.Spec.match>` method:
63+
B41A 64+
.. code-block:: python
65+
66+
>>> spec = Spec(">=1.2.3")
67+
>>> spec.match("1.3.1")
68+
True
69+
>>> spec.match("1.2.1")
70+
False
71+
72+
73+
.. _tilde_expressions:
74+
75+
Using tilde expressions
76+
-----------------------
77+
78+
Tilde expressions are "approximately equivalent to a version".
79+
They are expressions like ``~1``, ``~1.2``, or ``~1.2.3``.
80+
Tilde expression freezes major and minor numbers. They are used if
81+
you want to avoid potentially incompatible changes, but want to accept bug fixes.
82+
83+
Internally they are converted into two comparisons:
84+
85+
* ``~1`` is converted into ``>=1.0.0 <(1+1).0.0`` which is ``>=1.0.0 <2.0.0``
86+
* ``~1.2`` is converted into ``>=1.2.0 <1.(2+1).0`` which is ``>=1.2.0 <1.3.0``
87+
* ``~1.2.3`` is converted into ``>=1.2.3 <1.(2+1).0`` which is ``>=1.2.3 <1.3.0``
88+
89+
Only if both comparisions are true, the tilde expression as whole is true
90+
as in the following examples:
91+
92+
.. code-block:: python
93+
94+
>>> version = Version(1, 2, 0)
95+
>>> version.match("~1.2") F438 # same as >=1.2.0 AND <1.3.0
96+
True
97+
>>> version.match("~1.3.2") # same as >=1.3.2 AND <1.4.0
98+
False
99+
100+
101+
.. _caret_expressions:
102+
103+
Using caret expressions
104+
-----------------------
105+
106+
Care expressions are "compatible with a version".
107+
They are expressions like ``^1``, ``^1.2``, or ``^1.2.3``.
108+
Care expressions freezes the major number only.
109+
110+
Internally they are converted into two comparisons:
111+
112+
* ``^1`` is converted into ``>=1.0.0 <2.0.0``
113+
* ``^1.2`` is converted into ``>=1.2.0 <2.0.0``
114+
* ``^1.2.3`` is converted into ``>=1.2.3 <2.0.0``
115+
116+
.. code-block:: python
117+
118+
>>> version = Version(1, 2, 0)
119+
>>> version.match("^1.2") # same as >=1.2.0 AND <2.0.0
120+
True
121+
>>> version.match("^1.3")
122+
False
123+
124+
It is possible to add placeholders to the care expression. Placeholders
125+
are ``x``, ``X``, or ``*`` and are replaced by zeros like in the following examples:
126+
127+
.. code-block:: python
128+
129+
>>> version = Version(1, 2, 3)
130+
>>> version.match("^1.x") # same as >=1.0.0 AND <2.0.0
131+
True
132+
>>> version.match("^1.2.x") # same as >=1.2.0 AND <2.0.0
133+
True
134+
>>> version.match("^1.3.*") # same as >=1.3.0 AND <2.0.0
135+
False

src/semver/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
main,
2929
)
3030
from .version import Version, VersionInfo
31+
from .spec import Spec
3132
from .__about__ import (
3233
__version__,
3334
__author__,

0 commit comments

Comments
 (0)
0