Skip to content

Commit d7b12ad

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 0c08f75 commit d7b12ad

File tree

11 files changed

+1093
-200
lines changed

11 files changed

+1093
-200
lines changed

docs/api.rst

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

8484
.. autoclass:: semver.version.Version
8585
:members:
86+
:inherited-members:
8687
:special-members: __iter__, __eq__, __ne__, __lt__, __le__, __gt__, __ge__, __getitem__, __hash__, __repr__, __str__
88+
89+
90+
Version Regular Expressions :mod:`semver.versionregex`
91+
------------------------------------------------------
92+
93+
.. automodule:: semver.versionregex
94+
95+
.. autoclass:: semver.versionregex.VersionRegex
96+
:members:
97+
:private-members:
98+
99+
100+
Spec Handling :mod:`semver.spec`
101+
--------------------------------
102+
103+
.. automodule:: semver.spec
104+
105+
.. autoclass:: semver.spec.Spec
106+
:members: match
107+
:private-members: _caret, _tilde
108+
:special-members: __eq__, __ne__, __lt__, __le__, __gt__, __ge__, __repr__, __str__
109+
110+
.. autoclass:: semver.spec.InvalidSpecifier
111+

docs/conf.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,12 @@ def find_version(*file_paths):
129129
# wget -O docs/python-objects.inv https://docs.python.org/3/objects.inv
130130
"python": ("https://docs.python.org/3", (None, "inventories/python-objects.inv")),
131131
}
132+
132133
# Avoid side-effects (namely that documentations local references can
133134
# suddenly resolve to an external location.)
134135
intersphinx_disabled_reftypes = ["*"]
135136

137+
136138
# -- Options for HTML output ----------------------------------------------
137139

138140
# 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
@@ -15,6 +15,8 @@ Currently, the match expression supports the following operators:
1515
* ``<=`` smaller or equal than
1616
* ``==`` equal
1717
* ``!=`` not equal
18+
* ``~`` for tilde ranges, see :ref:`tilde_expressions`
19+
* ``^`` for caret ranges, see :ref:`caret_expressions`
1820

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

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

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