Add MatchSpec doc and fix errors (#3224)

* Add missing spec doc

* Add 2.0 changes to doc

* Cleanup spec usage doc

* Remove outdated documentation page

* Fix doc link

* Fix backticks in docs

* Add rst pre-commit checks
This commit is contained in:
Antoine Prouvost 2024-03-08 14:44:52 +01:00 committed by GitHub
parent fd42d8dd8e
commit a00ef35675
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 197 additions and 205 deletions

View File

@ -16,6 +16,12 @@ repos:
args: [--autofix] args: [--autofix]
- id: debug-statements - id: debug-statements
language_version: python3 language_version: python3
- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.9.0
hooks:
- id: rst-backticks
- id: rst-directive-colons
- id: rst-inline-touching-normal
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.6 rev: v0.1.6
hooks: hooks:

View File

@ -55,7 +55,7 @@ When a package gets installed, several steps are executed:
- the package is downloaded and placed into the ``$ROOT_PREFIX/pkgs`` folder - the package is downloaded and placed into the ``$ROOT_PREFIX/pkgs`` folder
- the package is extracted - the package is extracted
- the package is "linked" from the `pkgs` folder into the final destination - the package is "linked" from the ``pkgs`` folder into the final destination
When the package is linked to the final destination (for example, some newly created environment), most files are "hard"-linked. That means, there is no copy of the file created. This saves a considerable amount of disk-space when re-using the same package in multiple environments. When the package is linked to the final destination (for example, some newly created environment), most files are "hard"-linked. That means, there is no copy of the file created. This saves a considerable amount of disk-space when re-using the same package in multiple environments.

View File

@ -59,6 +59,6 @@ If we want to install ``python 3.7.*`` we would prefer ``python 3.7 HASH_cpython
On conda-forge, we're building "variant packages" for numpy (and other packages requiring the C API of Python). This means for a given version of numpy, we'll end up with ~5 almost equivalent variant packages, for cpython 3.6, 3.7 and 3.8 as well as pypy 3.6 and 3.7. On conda-forge, we're building "variant packages" for numpy (and other packages requiring the C API of Python). This means for a given version of numpy, we'll end up with ~5 almost equivalent variant packages, for cpython 3.6, 3.7 and 3.8 as well as pypy 3.6 and 3.7.
For this example the default is the cpython build of numpy. However, currently conda-forge does not apply the down-weigthing via track_feature on the terminal node (numpy), but only in some dependency package (such as python). For this example the default is the cpython build of numpy. However, currently conda-forge does not apply the down-weigthing via track_feature on the terminal node (numpy), but only in some dependency package (such as python).
For the case where we want to simply install `numpy`, we need to find which numpy variant installs the highest python package. In this case libsolv would decide for ``numpy-1.20-cpython38``. For the case where we want to simply install ``numpy``, we need to find which numpy variant installs the highest python package. In this case libsolv would decide for ``numpy-1.20-cpython38``.
If we install ``numpy python=3.7`` we have two potential variants: ``numpy-1.20-cpython37`` and ``numpy-1.20-pypy37``. In this case we need to inspect wether one of those two builds will require exclusively packages with a track_feature applied. And indeed, the ``pypy37`` package will have a requirement on ``python_abi 3.7 *pypy`` and **all** packages matching this requirement have a track_feature, so that it will be down-weighted. If we install ``numpy python=3.7`` we have two potential variants: ``numpy-1.20-cpython37`` and ``numpy-1.20-pypy37``. In this case we need to inspect wether one of those two builds will require exclusively packages with a track_feature applied. And indeed, the ``pypy37`` package will have a requirement on ``python_abi 3.7 *pypy`` and **all** packages matching this requirement have a track_feature, so that it will be down-weighted.

View File

@ -1,4 +1,3 @@
=================
Mamba 2.0 Changes Mamba 2.0 Changes
================= =================
.. ...................... .. .. ...................... ..
@ -9,11 +8,10 @@ Mamba 2.0 Changes
.. - OCI registries .. - OCI registries
.. - Mirrors .. - Mirrors
.. - Own implementation repodata.json .. - Own implementation repodata.json
.. - Fully feature implementation of MatchSpec
Command Line Executables Command Line Executables
======================== ------------------------
Mamba (executable) Mamba (executable)
****************** ******************
``mamba``, previously a Python executable mixing ``libmambapy``, ``conda``, and code to bridge both ``mamba``, previously a Python executable mixing ``libmambapy``, ``conda``, and code to bridge both
@ -37,14 +35,14 @@ Breaking changes include:
- ``micromamba shell init`` root prefix parameter ``--prefix`` (``-p``) was renamed - ``micromamba shell init`` root prefix parameter ``--prefix`` (``-p``) was renamed
``--root-prefix`` (``-r``). ``--root-prefix`` (``-r``).
Both options were supported in version ``1.5``. Both options were supported in version ``1.5``.
- A new config `order_solver_request` (default true) can be used to order the dependencies passed - A new config ``order_solver_request`` (default true) can be used to order the dependencies passed
to the solver, getting order independent solutions. to the solver, getting order independent solutions.
.. TODO is micromamba executable renamed mamba? .. TODO OCI and mirrors
Libraries Libraries
========= ---------
Mamba (Python package) Mamba (Python package)
********************** **********************
In version 2.0, all tools are fully written in C++. In version 2.0, all tools are fully written in C++.
@ -66,19 +64,21 @@ Changes inlcude:
``ChannelContext.make_conda_compatible`` (with ``Context.instance`` as argument in most cases) ``ChannelContext.make_conda_compatible`` (with ``Context.instance`` as argument in most cases)
and passed explicitly to a few functions. and passed explicitly to a few functions.
- A new ``Context`` independent submodule ``libmambapy.specs`` has been introduced with: - A new ``Context`` independent submodule ``libmambapy.specs`` has been introduced with:
- The redesign of the ``Channel`` and a new ``UnresolvedChannel`` used to describe unresolved - The redesign of the ``Channel`` and a new ``UnresolvedChannel`` used to describe unresolved
channel strings. channel strings.
A featureful ``libmambapy.specs.CondaURL`` is used to describe channel URLs. A featureful ``libmambapy.specs.CondaURL`` is used to describe channel URLs.
- The redesign``MatchSpec``. - The redesign of ``MatchSpec``.
The module also includes a platform enumeration, an implementation of ordered ``Version``, The module also includes a platform enumeration, an implementation of ordered ``Version``,
and a ``VersionSpec`` to match versions. and a ``VersionSpec`` to match versions.
- ``PackageInfo`` has been moved to this submodule. - ``PackageInfo`` has been moved to this submodule.
Some attributes have been given a more explicit name ``fn`` > ``filename``, Some attributes have been given a more explicit name ``fn`` > ``filename``,
``url`` > ``package_url``. ``url`` > ``package_url``.
- A new ``Context`` independent submodule ``libmambapy.solver`` has been introduced with the - A new ``Context`` independent submodule ``libmambapy.solver`` has been introduced with the
changes below. changes below.
A usage documentation page is available at A usage documentation page is available at :ref:`mamba_usage_solver`.
https://mamba.readthedocs.io/en/latest/usage/solver.html
- The redesign of the ``Pool``, which is now available as ``libmambapy.solver.libsolv.Database``. - The redesign of the ``Pool``, which is now available as ``libmambapy.solver.libsolv.Database``.
The new interfaces makes it easier to create repositories without using other ``libmambapy`` The new interfaces makes it easier to create repositories without using other ``libmambapy``
objects. objects.
@ -89,13 +89,12 @@ Changes inlcude:
high-level free functions such as ``load_subdir_in_database`` and high-level free functions such as ``load_subdir_in_database`` and
``load_installed_packages_in_database``. ``load_installed_packages_in_database``.
- The ``Solver`` has been moved to ``libmambapy.solver.libsolv.Solver``. - The ``Solver`` has been moved to ``libmambapy.solver.libsolv.Solver``.
- All jobs, pins, and flags must be passed as a single ``libmambapy.solver.Request``. - All jobs, pins, and flags must be passed as a single ``libmambapy.solver.Request``.
- The outcome of solving the request is either a ``libmambapy.solver.Solution`` or a - The outcome of solving the request is either a ``libmambapy.solver.Solution`` or a
``libmambapy.solver.libsolv.Unsolvable`` state from which rich error messages can be ``libmambapy.solver.libsolv.Unsolvable`` state from which rich error messages can be
extracted. extracted.
.. TODO include final decision for Channels as URLs.
For many changes, an exception throwing placeholder has ben kept to advise developpers on the new For many changes, an exception throwing placeholder has ben kept to advise developpers on the new
direction to take. direction to take.
@ -106,11 +105,14 @@ Due to the low usage of the C++ interface, all changes are not listed here.
The main changes are: The main changes are:
- Refactoring and testing of a large number of utilities into a ``util::`` namespace, - Refactoring and testing of a large number of utilities into a ``util::`` namespace,
- Creation of the ``specs::`` with: - Creation of the ``specs::`` the items below.
- Implementations of ``Version`` and ``VersionSpec`` for matching versions, A usage documentation (in Python) is available at :ref:`mamba_usage_specs`.
- A refactoring of a purely funcitonal ``Channel`` class,
- Implementaiton of a ``UnresolvedChannel`` to describe unresolved ``Channels``, - Implementations of ``Version`` and ``VersionSpec`` for matching versions,
- A refactored implementation of ``MatchSpec`` using the components above. - A refactoring of a purely funcitonal ``Channel`` class,
- Implementaiton of a ``UnresolvedChannel`` to describe unresolved ``Channels``,
- A refactored implementation of ``MatchSpec`` using the components above.
- A cleanup of ``ChannelContext`` for be a light proxy and parameter holder wrapping the - A cleanup of ``ChannelContext`` for be a light proxy and parameter holder wrapping the
``specs::Channel``. ``specs::Channel``.
- A new ``repodata.json`` parser using `simdjson <https://simdjson.org/>`_. - A new ``repodata.json`` parser using `simdjson <https://simdjson.org/>`_.
@ -118,15 +120,15 @@ The main changes are:
subnamespace and works independently of the ``Context``. subnamespace and works independently of the ``Context``.
The ``solver::libsolv`` sub-namespace has also been added for full isolation of libsolv, and a The ``solver::libsolv`` sub-namespace has also been added for full isolation of libsolv, and a
solver API without ``Context``. solver API without ``Context``.
The ``solver`` API redesign includes: The ``solver`` API redesign includes the items below.
- A refactoring of the ``MPool`` as a ``DataBase``, fully isolates libsolv, and simplifies A usage documentation (in Python) is available at :ref:`mamba_usage_solver`.
repository creation.
- A refactoring and thinning of ``MRepo`` as a new ``RepoInfo``. - A refactoring of the ``MPool`` as a ``DataBase``, fully isolates libsolv, and simplifies
- A solver ``Request`` with all requirements to solve is the new way to specify jobs. repository creation.
- A refactoring of ``Solver``. - A refactoring and thinning of ``MRepo`` as a new ``RepoInfo``.
- A solver outcome as either a ``Solution`` or an ``UnSolvable`` state. - A solver ``Request`` with all requirements to solve is the new way to specify jobs.
A usage documentation (in Python) is available at - A refactoring of ``Solver``.
https://mamba.readthedocs.io/en/latest/usage/solver.html - A solver outcome as either a ``Solution`` or an ``UnSolvable`` state.
- Improved downloaders. - Improved downloaders.
.. TODO OCI registry .. TODO OCI registry

View File

@ -28,7 +28,8 @@ Develop using Taskfile
====================== ======================
Many development operations can be automated and chained using `Taskfile <https://taskfile.dev/>`_. Many development operations can be automated and chained using `Taskfile <https://taskfile.dev/>`_.
You can follow the installation instructions there, or install it via `conda-forge`. You can follow the installation instructions there, or install it via ``conda-forge``.
.. code:: bash .. code:: bash
@ -63,15 +64,15 @@ At the time of writing, the following tasks are available:
* create-dev-env: Create a local development mamba environment with all needed dependencies * create-dev-env: Create a local development mamba environment with all needed dependencies
* create-test-env: Create a local test environment with as a copy of the dev environment. * create-test-env: Create a local test environment with as a copy of the dev environment.
* install-cpp: Install C++ targets into the test environment. * install-cpp: Install C++ targets into the test environment.
* install-py: Install the `libmambapy` Python package inside the test environment. * install-py: Install the ``libmambapy`` Python package inside the test environment.
* micromamba: Run the development `micromamba`. * micromamba: Run the development ``micromamba``.
* pre-commit: Run linters and code formatters. * pre-commit: Run linters and code formatters.
* reconfigure: Erase all CMake cache entries and run confiiguration again. * reconfigure: Erase all CMake cache entries and run confiiguration again.
* stubgen: Regenerate libmambapy typing stubs. * stubgen: Regenerate libmambapy typing stubs.
* test-docs: Test the documentation, for instance for dead links. * test-docs: Test the documentation, for instance for dead links.
* test-libmamba: Run `libmamba` C++ based tests. * test-libmamba: Run ``libmamba`` C++ based tests.
* test-libmambapy: Run `libmambapy` Python based unit tests. * test-libmambapy: Run ``libmambapy`` Python based unit tests.
* test-micromamba: Run `micromamba` integration tests. * test-micromamba: Run ``micromamba`` integration tests.
For instance to run ``libmamba`` tests, execute: For instance to run ``libmamba`` tests, execute:

View File

@ -55,7 +55,6 @@ You can try Mamba now by visiting the installation for
:maxdepth: 2 :maxdepth: 2
:hidden: :hidden:
python_api
usage/specs usage/specs
usage/solver usage/solver
@ -75,3 +74,4 @@ You can try Mamba now by visiting the installation for
developer_zone/contributing developer_zone/contributing
developer_zone/dev_environment developer_zone/dev_environment
developer_zone/internals developer_zone/internals
developer_zone/changes-2.0

View File

@ -7,7 +7,7 @@ Mamba Installation
Fresh install (recommended) Fresh install (recommended)
*************************** ***************************
We recommend that you start with the `Miniforge distribution <https://github.com/conda-forge/miniforge>`_ >= `Miniforge3-22.3.1-0`. We recommend that you start with the `Miniforge distribution <https://github.com/conda-forge/miniforge>`_ >= ``Miniforge3-22.3.1-0``.
If you need an older version of Mamba, please use the Mambaforge distribution. If you need an older version of Mamba, please use the Mambaforge distribution.
Miniforge comes with the popular ``conda-forge`` channel preconfigured, but you can modify the configuration to use any channel you like. Miniforge comes with the popular ``conda-forge`` channel preconfigured, but you can modify the configuration to use any channel you like.
@ -16,7 +16,7 @@ After successful installation, you can use the mamba commands as described in :r
.. note:: .. note::
1. After installation, please :ref:`make sure <defaults_channels>` that you do not have the Anaconda default channels configured. 1. After installation, please :ref:`make sure <defaults_channels>` that you do not have the Anaconda default channels configured.
2. Do not install anything into the `base` environment as this might break your installation. See :ref:`here <base_packages>` for details. 2. Do not install anything into the ``base`` environment as this might break your installation. See :ref:`here <base_packages>` for details.
Existing ``conda`` install (not recommended) Existing ``conda`` install (not recommended)

View File

@ -1,138 +0,0 @@
=======================
Python API of ``mamba``
=======================
Using internal mamba APIs
-------------------------
The core of ``mamba`` is written in C++, but we expose the internals of mamba with a Python API
(using ``pybind11``).
You can import ``libmambapy`` containing the Python API using ``import libmambapy`` without having ``mamba`` installed.
These bindings expose the following objects (`boa`_ has a full example):
- ``Context``: a singleton configuration object. All global configuration goes through this. From Python you can use the context object like so:
.. code:: python
import libmambapy
ctx = libmambapy.Context.instance()
ctx.conda_prefix = "/home/wolfv/conda"
print(ctx.root_prefix)
Here is an example usage of ``libmambapy``:
.. code:: python
def get_index(
channel_urls=(),
prepend=True,
platform=None,
use_local=False,
use_cache=False,
unknown=None,
prefix=None,
repodata_fn="repodata.json",
):
check_allowlist(channel_urls)
dlist = libmambapy.DownloadTargetList()
index = []
for idx, url in enumerate(channel_urls):
channel = Channel(url)
full_url = channel.url(with_credentials=True) + "/" + repodata_fn
full_path_cache = os.path.join(
create_cache_dir(), cache_fn_url(full_url, repodata_fn)
)
# Channels might not have a name.
if channel.name is None:
name_and_subdir = channel.subdir
else:
name_and_subdir = channel.name + "/" + channel.subdir
sd = libmambapy.SubdirData(name_and_subdir, full_url, full_path_cache)
index.append((sd, channel))
dlist.add(sd)
is_downloaded = dlist.download(libmambapy.MAMBA_DOWNLOAD_FAILFAST)
if not is_downloaded:
raise RuntimeError("Error downloading repodata.")
return index
class MambaSolver:
def __init__(self, prefix, channels, platform):
api_ctx = libmambapy.Context()
api_ctx.conda_prefix = prefix
self.channels = channels
self.platform = platform
self.index = get_index(channels, platform=platform)
self.local_index = []
self.pool = libmambapy.Pool()
self.repos = []
start_prio = len(channels)
priority = start_prio
subpriority = 0 # wrong! :)
for subdir, channel in self.index:
repo = libmambapy.Repo(
self.pool,
str(channel),
subdir.cache_path(),
channel.url(with_credentials=True),
)
repo.set_priority(start_prio, subpriority)
start_prio -= 1
self.repos.append(repo)
self.local_repos = {}
def solve(self, specs, prefix):
"""Solve given a set of specs.
Parameters
----------
specs : list of str
A list of package specs. You can use `conda.models.match_spec.MatchSpec`
to get them to the right form by calling
`MatchSpec(mypec).conda_build_form()`
Returns
-------
solvable : bool
True if the set of specs has a solution, False otherwise.
"""
solver_options = [(libmambapy.SOLVER_FLAG_ALLOW_DOWNGRADE, 1)]
api_solver = libmambapy.Solver(self.pool, solver_options)
_specs = specs
api_solver.add_jobs(_specs, libmambapy.SOLVER_INSTALL)
success = api_solver.try_solve()
if not success:
error_string = "Mamba failed to solve:\n"
for s in _specs:
error_string += f" - {s}\n"
error_string += "\nwith channels:\n"
for c in self.channels:
error_string += f" - {c}\n"
pstring = api_solver.problems_to_str()
pstring = "\n".join([" " + l for l in pstring.split("\n")])
error_string += f"\nThe reported errors are:\n⇟{pstring}"
print(error_string)
exit(1)
package_cache = libmambapy.MultiPackageCache(pkgs_dirs)
t = libmambapy.Transaction(api_solver, package_cache)
return t
.. _boa: https://github.com/mamba-org/boa/blob/main/boa/core/solver.py

View File

@ -1,3 +1,5 @@
.. _mamba_usage_solver:
Solving Package Environments Solving Package Environments
============================ ============================
@ -30,7 +32,7 @@ This serves to resolve explicit channel requirements or channel priority.
As such, the database constructor takes a set of As such, the database constructor takes a set of
:cpp:type:`ChannelResolveParams <mamba::specs::ChannelResolveParams>` :cpp:type:`ChannelResolveParams <mamba::specs::ChannelResolveParams>`
to work with :cpp:type:`Channel <mamba::specs::Channel>` work with Channel data to work with :cpp:type:`Channel <mamba::specs::Channel>` work with Channel data
internaly (see `the usage section on Channels <libmamba_usage_channel>`_ for more internaly (see :ref:`the usage section on Channels <libmamba_usage_channel>` for more
information). information).
The first way to add a repository is from a list of |PackageInfo| using The first way to add a repository is from a list of |PackageInfo| using

View File

@ -1,17 +1,29 @@
.. _mamba_usage_specs:
Describing Conda Objects Describing Conda Objects
======================== ========================
.. |CondaURL| replace:: :cpp:type:`CondaURL <mamba::specs::CondaURL>`
.. |UnresolvedChannel| replace:: :cpp:type:`UnresolvedChannel <mamba::specs::UnresolvedChannel>`
.. |Channel| replace:: :cpp:type:`Channel <mamba::specs::Channel>`
.. |Version| replace:: :cpp:type:`Version <mamba::specs::Version>`
.. |VersionSpec| replace:: :cpp:type:`VersionSpec <mamba::specs::VersionSpec>`
.. |BuildNumberSpec| replace:: :cpp:type:`BuildNumberSpec <mamba::specs::BuildNumberSpec>`
.. |GlobSpec| replace:: :cpp:type:`GlobSpec <mamba::specs::GlobSpec>`
.. |MatchSpec| replace:: :cpp:type:`MatchSpec <mamba::specs::MatchSpec>`
The :any:`libmambapy.specs <mamba::specs>` submodule contains object to *describe* abstraction in the Conda ecosystem. The :any:`libmambapy.specs <mamba::specs>` submodule contains object to *describe* abstraction in the Conda ecosystem.
They are purely functional and do not have any observable impact on the user system. They are purely functional and do not have any observable impact on the user system.
For instance :cpp:type:`libmambapy.specs.Channel <mamba::specs::Channel>` is used to describe a For instance |Channel| is used to describe a channel but does not download any file.
channel but does not download any file.
CondaURL CondaURL
-------- --------
The :cpp:type:`CondaURL <mamba::specs::CondaURL>` is a rich URL object that has additional The |CondaURL| is a rich URL object that has additional capabilities for dealing with tokens,
capabilities for dealing with tokens, platforms, and packages. platforms, and packages.
To parse a string into a ``CondaURL``, use ``CondaURL.parse`` as follows: To parse a string into a |CondaURL| use :cpp:func:`CondaURL.parse <mamba::specs::CondaURL::parse>`
as follows:
.. code:: python .. code:: python
@ -94,8 +106,8 @@ user-friendly string, but that may not be parsed back.
UnresolvedChannel UnresolvedChannel
----------------- -----------------
A :cpp:type:`UnresolvedChannel <mamba::specs::UnresolvedChannel>` is a lightweight object to represent A |UnresolvedChannel| is a lightweight object to represent a channel string, as in passed in
a channel string, as in passed in the CLI or configuration. the CLI or configuration.
Since channels rely heavily on configuration options, this type can be used as a placeholder for a Since channels rely heavily on configuration options, this type can be used as a placeholder for a
channel that has not been fully "resolved" to a specific location. channel that has not been fully "resolved" to a specific location.
It does minimal parsing and can detect the type of ressource (an unresolved name, a URL, a file) It does minimal parsing and can detect the type of ressource (an unresolved name, a URL, a file)
@ -125,15 +137,14 @@ Dynamic platforms (as in not known by Mamba) can only be detected with the ``[]`
.. _libmamba_usage_channel: .. _libmamba_usage_channel:
Channel Channel
------- -------
The :cpp:type:`Channel <mamba::specs::Channel>` are represented by a The |Channel| are represented by a |CondaURL| and a set of platform filters.
:cpp:type:`CondaURL <mamba::specs::CondaURL>` and a set of platform filters.
A display name is also available, but is not considered a stable identifiaction form of the A display name is also available, but is not considered a stable identifiaction form of the
channel, since it depends on the many configuration parameters, such as the channel alias. channel, since it depends on the many configuration parameters, such as the channel alias.
We construct a :cpp:type:`Channel <mamba::specs::Channel>` by *resolving* a We construct a |Channel| by *resolving* a |UnresolvedChannel|.
:cpp:type:`UnresolvedChannel <mamba::specs::UnresolvedChannel>`.
All parameters that influence this resolution must be provided explicitly. All parameters that influence this resolution must be provided explicitly.
@ -197,13 +208,12 @@ This is because of custom multichannel, a single name can return mutliple channe
.. note:: .. note::
Creating :cpp:type:`Channel <mamba::specs::Channel>` objects this way, while highly Creating |Channel| objects this way, while highly customizable, can be very verbose.
customizable, can be very verbose.
In practice, one can create a ``ChannelContext`` with ``ChannelContext.make_simple`` or In practice, one can create a ``ChannelContext`` with ``ChannelContext.make_simple`` or
``ChannelContext.make_conda_compatible`` to compute and hold all these parameters from a ``ChannelContext.make_conda_compatible`` to compute and hold all these parameters from a
``Context`` (itself getting its values from all the configuration sources). ``Context`` (itself getting its values from all the configuration sources).
``ChannelContext.make_channel`` can then directly construct a ``ChannelContext.make_channel`` can then directly construct a
:cpp:type:`Channel <mamba::specs::Channel>` from a string. |Channel| from a string.
Version Version
@ -240,7 +250,7 @@ so ``1.2``, ``1.2.0``, and ``1.2.0.0`` are all considered equal.
`calendar versioning <https://calver.org/>`_, or `calendar versioning <https://calver.org/>`_, or
`PEP440 <https://peps.python.org/pep-0440/>`_. `PEP440 <https://peps.python.org/pep-0440/>`_.
A :cpp:type:`Version <mamba::specs::Version>` can be created by parsing a string with A |Version| can be created by parsing a string with
:cpp:func:`Version.parse <mamba::specs::Version::parse>`. :cpp:func:`Version.parse <mamba::specs::Version::parse>`.
.. code:: python .. code:: python
@ -268,16 +278,16 @@ A version spec is a way to describe a set of versions.
We have the following primitives: We have the following primitives:
- ``*`` matches all versions (unrestricted). - ``*`` matches all versions (unrestricted).
- ``==`` for **equal** states matches versions equal to the given one (a singleton). - ``==`` for **equal** matches versions equal to the given one (a singleton).
For instance ``==1.2.4`` matches ``1.2.4`` only, and not ``1.2.4.1`` or ``1.2``. For instance ``==1.2.4`` matches ``1.2.4`` only, and not ``1.2.4.1`` or ``1.2``.
Note that since ``1.2.4.0`` is the same as ``1.2.4``, this is also matched. Note that since ``1.2.4.0`` is the same as ``1.2.4``, this is also matched.
- ``!=`` for ``not equal`` is the opposite, it matches all but the given version. - ``!=`` for **not equal** is the opposite, it matches all but the given version.
For instance ``=!1.2.4`` matches ``1.2.5`` and ``1!1.2.4`` but not ``1.2.4``. For instance ``=!1.2.4`` matches ``1.2.5`` and ``1!1.2.4`` but not ``1.2.4``.
- ``>`` for **greater** matches versions stricly greater than the current one, for instance - ``>`` for **greater** matches versions stricly greater than the current one, for instance
``>1.2.4`` matches ``2.0.0``, ``1!1.0.0``, but not ``1.1.0`` or ``1.2.4``. ``>1.2.4`` matches ``2.0.0``, ``1!1.0.0``, but not ``1.1.0`` or ``1.2.4``.
- ``>=`` for **greater or equal**. - ``>=`` for **greater or equal**.
- ``<`` for **less**. - ``<`` for **less**.
- ``<-`` for **less or equal**. - ``<=`` for **less or equal**.
- ``=`` for **starts with** matches versions that start with the same non zero parts of the version. - ``=`` for **starts with** matches versions that start with the same non zero parts of the version.
For instance ``=1.7`` matches ``1.7.8``, and ``1.7.0alpha1`` (beware since this is smaller For instance ``=1.7`` matches ``1.7.8``, and ``1.7.0alpha1`` (beware since this is smaller
than ``1.7.0``). than ``1.7.0``).
@ -287,7 +297,7 @@ We have the following primitives:
For instance ``!=1.7.*`` matches ``1.8.3`` but not ``1.7.2``. For instance ``!=1.7.*`` matches ``1.8.3`` but not ``1.7.2``.
- ``~=`` for **compatible with** matches versions that are greater or equal and starting with the - ``~=`` for **compatible with** matches versions that are greater or equal and starting with the
all but the last parts specified, including zeros. all but the last parts specified, including zeros.
For instance `~=2.0` matches ``2.0.0``, ``2.1.3``, but not ``3.0.1`` or ``2.0.0alpha``. For instance ``~=2.0`` matches ``2.0.0``, ``2.1.3``, but not ``3.0.1`` or ``2.0.0alpha``.
All version spec can be combine using a boolean grammar where ``|`` means **or** and ``,`` means All version spec can be combine using a boolean grammar where ``|`` means **or** and ``,`` means
**and**. **and**.
@ -299,10 +309,10 @@ For instance, ``(>2.1.0,<3.0)|==2.0.1`` means:
- greater that ``2.1.0`` - greater that ``2.1.0``
- and less than ``3.0``. - and less than ``3.0``.
To create a :cpp:type:`VersionSpec <mamba::specs::VersionSpec>` from a string, we parse it with To create a |VersionSpec| from a string, we parse it with
:cpp:type:`VersionSpec.parse <mamba::specs::VersionSpec::parse>`. :cpp:func:`VersionSpec.parse <mamba::specs::VersionSpec::parse>`.
To check if a given version matches a version spec, we use To check if a given version matches a version spec, we use
:cpp:type:`VersionSpec.contains <mamba::specs::VersionSpec::contains>`. :cpp:func:`VersionSpec.contains <mamba::specs::VersionSpec::contains>`.
.. code:: python .. code:: python
@ -313,3 +323,111 @@ To check if a given version matches a version spec, we use
assert vs.contains(specs.Version.parse("2.4.0")) assert vs.contains(specs.Version.parse("2.4.0"))
assert vs.contains(specs.Version.parse("2.0.1")) assert vs.contains(specs.Version.parse("2.0.1"))
assert not vs.contains(specs.Version.parse("3.0.1")) assert not vs.contains(specs.Version.parse("3.0.1"))
.. warning::
Single versions such as ``3.7`` are parsed by Conda and Mamba as ``==3.7``, which can seem
unintuitive.
As such, it is recommended to always specify an operator.
This mistake is especially likely when writing a match spec such as ``python 3.7``.
BuildNumberSpec
---------------
Similarily, a build number spec is a way to describe a set of build numbers.
It's much simpler than the |VersionSpec| in that it does not contain any boolean grammar
(the ``,`` and ``|`` operators).
|BuildNumberSpec| only contain primitives similar to that used in |VersionSpec|:
- ``*`` or ``=*`` matches all build numbers (unrestricted).
- ``=`` for **equal** matches build numbers equal to the given one (a singleton).
- ``!=`` for **not equal**.
- ``>`` for **greater** matches versions stricly greater than the current one.
- ``>=`` for **greater or equal**.
- ``<`` for **less**.
- ``<=`` for **less or equal**.
To create a |BuildNumberSpec| from a string, we parse it
with :cpp:func:`BuildNumberSpec.parse <mamba::specs::BuildNumberSpec::parse>`.
To check if a given build number matches a build number spec, we use
:cpp:func:`BuildNumberSpec.contains <mamba::specs::BuildNumberSpec::contains>`.
.. code:: python
import libmambapy.specs as specs
bs = specs.BuildNumberSpec.parse(">2")
assert bs.contains(3)
assert not bs.contains(2)
Other Specs
-----------
The |GlobSpec| is used to match glob expressions on strings.
The only wildcard currently supported is ``*`` which stands for any string (0 or more characters).
The glob spec is used as the basis for the |MatchSpec| package name and build string.
.. code:: python
import libmambapy.specs as specs
glob = specs.GlobSpec.parse("py*")
assert glob.contains("python")
assert glob.contains("pypy")
assert not vs.contains("rust-python")
MatchSpec
---------
Ultimately, the |MatchSpec| is the way to match on conda packages, that is a way to describe a
set of packages.
This is what is passed in a command line argument such as ``mamba install <match_spec>``.
Match specs have a complex string representation, which we can informally write as
``[[<channel>:]<namespace>:]<name>[<version>[=<build_string>]][[<attribute>=<value>, [...]]]``, or
with an example
``conda-forge:ns:python>=3.7=*cypthon[subdir="linux-64",fn=pkg.conda]``.
- ``<channel>``, here ``conda-forge`` describes an |UnresolvedChannel| of where the channel the
package should come from.
It accepts all values from an unresolved channel, such as ``conda-forge/label/micromamba_dev``,
URLs, local file path, and platforms filters in between brackets.
- ``<namespace>``, here ``ns`` is a future, not implemented, feature.
It is nonetheless parsed, and retrievable.
- ``<name>``, here ``python`` is the package name or glob expression and is the only mandatory
field.
- Following is the |VersionSpec| ``<version>`` or ``>=3.7`` here.
- When the version specification is written (but it could also be set to ``=*``), it can be
followed by a ``<build_string>`` glob specification, here ``*cpython``.
- Last, a bracket section of comma separated ``<attribute>`` = ``<value>``.
In the example, we have two attributes, ``subdir`` and ``fn``.
Attribute values support quaoting with ``"`` or ``'``.
As such, they can be useful to set previously mentioned field without ambiguity.
Valid attribute names are:
- ``channel``, similar to ``<channel>``.
- ``name``, similar to ``<name>``.
- ``version``, similar to ``<version>`` (can be useful to set version expression containing
parentheses and ``,`` and ``|`` operators).
- ``build``, similar to ``<build_string>``.
- ``build_number`` to set the |BuildNumberSpec|.
- ``subdir`` to select the channel subdirectory platform from which the package must come from.
- ``fn`` to select the filename the package must match.
- ``md5`` to specify the MD5 hash the package archive must have.
- ``sha256`` to specify the SHA256 hash the package archive must have.
- ``license`` to specify the license the package must have.
- ``track_features`` to specify a list of ``track_features`` specified at the package build time.
- ``optional`` to add the package as a constraint rather than a strict dependency.
.. warning::
Specifying some value mulitple time, such as in ``python>=3.7[version="(=3.9|>3.11)"]``, or
``python[build="foo"][build="bar"]`` is undefined and subject to change in the future.
.. warning::
When specifying a version in the attribute section, the first ``=`` is parsed as the attribute
assignment.
That is ``python[version=3.7]`` is equivalent to ``python 3.7``, which is equivalent to
``python==3.7`` (strong equality).
This is intuitively different from how we write ``python=3.7``, which we must write with
attributes as ``python[version="=3.7"]``.

View File

@ -14,7 +14,7 @@ rely on a pure C++ implementation.
The configuration is parsed/read from multiple sources types: The configuration is parsed/read from multiple sources types:
- **rc file**: a file using `YAML` syntax - **rc file**: a file using ``YAML`` syntax
- **environment variable**: a key/value pair set prior to mamba execution - **environment variable**: a key/value pair set prior to mamba execution
- **CLI**: a parsed argument/option from a CLI interface - **CLI**: a parsed argument/option from a CLI interface
- **API**: a value set programmatically by a program relying on mamba - **API**: a value set programmatically by a program relying on mamba
@ -26,7 +26,8 @@ The precedence order between those sources is:
:align: center :align: center
.. note:: .. note::
`rc` file stands historically for `run commands` which could also translate to `runtime configuration`. ``rc`` file stands historically for ``run commands`` which could also translate to
``runtime configuration``.
It's a convenient way to persist configuration on the filesystem and use it as default. It's a convenient way to persist configuration on the filesystem and use it as default.
@ -44,9 +45,9 @@ Example:
Running ``micromamba install xtensor -c my-channel`` with 3 sources of configuration: Running ``micromamba install xtensor -c my-channel`` with 3 sources of configuration:
- ``channels`` and ``always_yes`` set from rc file located at `~/.mambarc` - ``channels`` and ``always_yes`` set from rc file located at ``~/.mambarc``.
- ``channels`` set from CLI using `-c` option - ``channels`` set from CLI using ``-c`` option.
- ``always_yes`` set from environment variable using `MAMBA_ALWAYS_YES` env var - ``always_yes`` set from environment variable using ``MAMBA_ALWAYS_YES`` env var
.. code:: .. code::
@ -60,7 +61,7 @@ Running ``micromamba install xtensor -c my-channel`` with 3 sources of configura
$ echo $MAMBA_ALWAYS_YES $ echo $MAMBA_ALWAYS_YES
true true
The resulting configuration written using `YAML` syntax is: The resulting configuration written using ``YAML`` syntax is:
.. code:: .. code::

View File

@ -99,8 +99,8 @@ While we make our best effort to keep backward compatibility, it is not impossib
breaks the current installation. breaks the current installation.
The following actions can be tried: The following actions can be tried:
- Reinitializing your shell with `micromamba shell reinit`. - Reinitializing your shell with ``micromamba shell reinit``.
- Deleting the package cache (`"package cache"` entries in `micromamba info`) - Deleting the package cache (``"package cache"`` entries in ``micromamba info``)
libmamba.so.2: undefined symbol ... libmamba.so.2: undefined symbol ...
----------------------------------- -----------------------------------