mamba-org/mamba

QUERY: some confusion migrating to mamba2

Opened this issue · 4 comments

Here is some code from asv which used MambaSolver (vendored from mamba.api), with representative values for some of the variables:

solver = MambaSolver(['conda-forge', 'nodefaults'], None, self.context)
...
transaction = solver.solve(['python=3.12', 'wheel', 'pip', 'asv_runner'])
transaction.execute(libmambapy.PrefixData(self._path))

Reading https://mamba.readthedocs.io/en/latest/usage/solver.html, I've got an idea of some changes to be made, like replacing MambaSolver with libmambapy.solver.libsolv.Solver, and creating a db = libmambapy.solver.libsolv.Database and a request = Request(...) to pass to the solver. Questions:

  • where does the execute(libmambapy.PrefixData(...)) step come in now? Should that be part of db or request?
  • What is the translation from ['conda-forge', 'nodefaults'] to a libmambapy.specs.ChannelResolveParams object? Do we need to specify URLs now?

cc @Hind-M

the mamba1 code: https://github.com/airspeed-velocity/asv/blob/main/asv/plugins/mamba.py

where does the execute(libmambapy.PrefixData(...)) step come in now? Should that be part of db or request?

In 1.x, Transaction was used through the python bindings, but that's not the case anymore (even if I think it still could be possible as bindings are still provided but with a different API).
(See https://mamba.readthedocs.io/en/latest/developer_zone/changes-2.0.html#libmambapy-python-bindings to have an idea of what's available and recommended).

In 2.x, after defining database and request, the solving is now done this way:

solver = libmambapy.solver.libsolv.Solver()
outcome = solver.solve(db, request)

You can then check that the solution (outcome) is valid before doing what you want with the specs::PackageInfo and the corresponding action to perform on it (install, remove, etc...)
See https://mamba.readthedocs.io/en/latest/usage/solver.html#examine-the-solution.

What is the translation from ['conda-forge', 'nodefaults'] to a libmambapy.specs.ChannelResolveParams object? Do we need to specify URLs now?

Regarding the channels, you can follow the example in this section to fully specify a channel (using ChannelResolveParams) or as the note suggests in the mentioned section - and considering an already existing configuration (for example .condarc), use ChannelContext.make_conda_compatible, and then ChannelContext.make_channel from a string (in this case, conda-forge or nodefaults).

I don't think that you need to set all parameters in ChannelResolveParams though (but at least channel_alias is recommended to avoid issues).

thanks!

In 2.x, after defining database and request, the solving is now done this way:

Right, but my question was more about the PrefixData part - where does that come in now?

and considering an already existing configuration (for example .condarc), use ChannelContext.make_conda_compatible, and then ChannelContext.make_channel from a string (in this case, conda-forge or nodefaults).

Cool, that sounds like what I'm looking for.

The PrefixData can be created with PrefixData.create(prefix_path, channel_context) but it is kind of hidden now. It is used in the Transaction execute but that's not the way to go.
Rather defining a custom function (here my_upgrade in Upgrade case) and operate on PackageInfo like the doc example suggests:

solver = libmambapy.solver.libsolv.Solver()
outcome = solver.solve(db, request)

Solution = libmambapy.solver.Solution

if isinstance(outcome, Solution):
    for action in outcome.actions:
        if isinstance(action, Solution.Upgrade):
            my_upgrade(from_pkg=action.remove, to_pkg=action.install)
        if isinstance(action, Solution.Reinstall):
            ...
        ...

The PrefixData can be created with PrefixData.create(prefix_path, channel_context) but it is kind of hidden now. It is used in the Transaction execute but that's not the way to go.
Rather defining a custom function (here my_upgrade in Upgrade case) and operate on PackageInfo like the doc example suggests:

So IIUC, previously transaction.execute would handle upgrading/reinstalling etc. itself, but now the user has to write their own functions which do this? If so, are there example functions that somebody has written already (which I can modify to include the prefix path part)?