mirror of https://github.com/mamba-org/mamba.git
139 lines
4.4 KiB
ReStructuredText
139 lines
4.4 KiB
ReStructuredText
=======================
|
|
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
|