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

Fix #241: Implement tilde and caret matching #367

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 25 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,29 @@ Version Handling :mod:`semver.version`

.. autoclass:: semver.version.Version
:members:
:inherited-members:
:special-members: __iter__, __eq__, __ne__, __lt__, __le__, __gt__, __ge__, __getitem__, __hash__, __repr__, __str__


Version Regular Expressions :mod:`semver.versionregex`
------------------------------------------------------

.. automodule:: semver.versionregex

.. autoclass:: semver.versionregex.VersionRegex
:members:
:private-members:


Spec Handling :mod:`semver.spec`
--------------------------------

.. automodule:: semver.spec

.. autoclass:: semver.spec.Spec
:members: match
:private-members: _caret, _tilde
:special-members: __eq__, __ne__, __lt__, __le__, __gt__, __ge__, __repr__, __str__

.. autoclass:: semver.spec.InvalidSpecifier

2 changes: 2 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,12 @@ def find_version(*file_paths):
(None, "inventories/pydantic.inv"),
),
}

# Avoid side-effects (namely that documentations local references can
# suddenly resolve to an external location.)
intersphinx_disabled_reftypes = ["*"]


# -- Options for HTML output ----------------------------------------------

# The theme to use for HTML and HTML Help pages. See the documentation for
Expand Down
111 changes: 103 additions & 8 deletions docs/usage/compare-versions-through-expression.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,120 @@ Currently, the match expression supports the following operators:
* ``<=`` smaller or equal than
* ``==`` equal
* ``!=`` not equal
* ``~`` for tilde ranges, see :ref:`tilde_expressions`
* ``^`` for caret ranges, see :ref:`caret_expressions`

That gives you the following possibilities to express your condition:

.. code-block:: python

>>> Version.parse("2.0.0").match(">=1.0.0")
>>> version = Version(2, 0, 0)
>>> version.match(">=1.0.0")
True
>>> Version.parse("1.0.0").match(">1.0.0")
>>> version.match("<1.0.0")
False

If no operator is specified, the match expression is interpreted as a
version to be compared for equality. This allows handling the common
case of version compatibility checking through either an exact version
or a match expression very easy to implement, as the same code will
handle both cases:
version to be compared for equality with the ``==`` operator.
This allows handling the common case of version compatibility checking
through either an exact version or a match expression very easy to
implement, as the same code will handle both cases:

.. code-block:: python

>>> Version.parse("2.0.0").match("2.0.0")
>>> version = Version(2, 0, 0)
>>> version.match("2.0.0")
True
>>> Version.parse("1.0.0").match("3.5.1")
>>> version.match("3.5.1")
False


Using the :class:`~semver.spec.Spec` class
------------------------------------------------

The :class:`~semver.spec.Spec` class is the underlying object
which makes comparison possible.

It supports comparisons through usual Python operators:

.. code-block:: python

>>> Spec("1.2") > '1.2.1'
True
>>> Spec("1.3") == '1.3.10'
False

If you need to reuse a ``Spec`` object, use the :meth:`~semver.spec.Spec.match` method:

.. code-block:: python

>>> spec = Spec(">=1.2.3")
>>> spec.match("1.3.1")
True
>>> spec.match("1.2.1")
False


.. _tilde_expressions:

Using tilde expressions
-----------------------

Tilde expressions are "approximately equivalent to a version".
They are expressions like ``~1``, ``~1.2``, or ``~1.2.3``.
Tilde expression freezes major and minor numbers. They are used if
you want to avoid potentially incompatible changes, but want to accept bug fixes.

Internally they are converted into two comparisons:

* ``~1`` is converted into ``>=1.0.0 <(1+1).0.0`` which is ``>=1.0.0 <2.0.0``
* ``~1.2`` is converted into ``>=1.2.0 <1.(2+1).0`` which is ``>=1.2.0 <1.3.0``
* ``~1.2.3`` is converted into ``>=1.2.3 <1.(2+1).0`` which is ``>=1.2.3 <1.3.0``

Only if both comparisions are true, the tilde expression as whole is true
as in the following examples:

.. code-block:: python

>>> version = Version(1, 2, 0)
>>> version.match("~1.2") # same as >=1.2.0 AND <1.3.0
True
>>> version.match("~1.3.2") # same as >=1.3.2 AND <1.4.0
False


.. _caret_expressions:

Using caret expressions
-----------------------

Caret expressions are "compatible with a version".
They are expressions like ``^1``, ``^1.2``, or ``^1.2.3``.
Caret expressions freezes the major number only.

Internally they are converted into two comparisons:

* ``^1`` is converted into ``>=1.0.0 <2.0.0``
* ``^1.2`` is converted into ``>=1.2.0 <2.0.0``
* ``^1.2.3`` is converted into ``>=1.2.3 <2.0.0``

.. code-block:: python

>>> version = Version(1, 2, 0)
>>> version.match("^1.2") # same as >=1.2.0 AND <2.0.0
True
>>> version.match("^1.3")
False

It is possible to add placeholders to the caret expression. Placeholders
are ``x``, ``X``, or ``*`` and are replaced by zeros like in the following examples:

.. code-block:: python

>>> version = Version(1, 2, 3)
>>> version.match("^1.x") # same as >=1.0.0 AND <2.0.0
True
>>> version.match("^1.2.x") # same as >=1.2.0 AND <2.0.0
True
>>> version.match("^1.3.*") # same as >=1.3.0 AND <2.0.0
False
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ ignore = F821,W503
extend-exclude =
.eggs
.env
.venv
build
docs
venv
Expand Down
1 change: 1 addition & 0 deletions src/semver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
main,
)
from .version import Version, VersionInfo
from .spec import Spec
from .__about__ import (
__version__,
__author__,
Expand Down