4

When using conda install, is it possible to install different packages from different channels in one line? For example could one do something like this?

conda install -c <channel_1> <package_1> -c <channel_2> <package_2> ...?

Johannes Wiesner
  • 1,006
  • 12
  • 33
  • 1
    It would be a nice-to-have, in order to automatize the installation of a list of conda packages saved in a .csv file, where for each package I have the information about the channel. I could then parse the .csv file and create one line of code that automatically installs all the package from the right channels. – Johannes Wiesner Jan 06 '22 at 15:54
  • 1
    @9769953 "*run conda install ... multiple times*" - the solver is very likely to end up re-sourcing previously installed packages to other channels under such a strategy. Also, the most computationally intensive part of Conda is solving, and this would wastefully re-solve subsets of the environment despite the whole specification being known at the outset. – merv Jan 06 '22 at 18:52

2 Answers2

12

The --channel argument

The --channel, -c flag tells Conda where to search for packages, but does not necessarily constrain where a specific package should be sourced. Moreover, the order that channels are specified applies to the whole solving process, and has no contextual relationship with adjacent package specifications. For example, the following commands are all completely identical after parsing:

conda install -c A -c B pkg1 pkg2
conda install -c A pkg1 -c B pkg2
conda install -c A pkg2 -c B pkg1
conda install pkg1 pkg2 -c A -c B

and all of these will prioritize channel A over B (under channel_priority: strict or flexible).

It should be emphasized that this does not guarantee either of these channels will be used, only considered. I think it helps to have a prosaic translation of the above command:

With channels A and B prioritized, ensure that packages pkg1 and pkg2 are installed in the current environment.

Specifying channels per package

However, the MatchSpec grammar is rather expressive and fully supports specifying the channel from which to source a given package. For example, if we want pkg1 from channel A and pkg2 from channel B, this would be expressed as:

conda install A::pkg1 B::pkg2

which translates to the imperative:

Ensure that pkg1 from channel A and pkg2 from channel B are installed in the current environment.

Note that we don't even need to include the channel via a --channel argument, because the package specification itself indicates the channel. One only needs to include the --channel, -c argument if they want to source additional packages (e.g., dependencies of pkg1) from the additional channel.

merv
  • 67,214
  • 13
  • 180
  • 245
2

FWIW, you can pick this up for free if you specify everything in a YAML file with the right syntax and update from that. See here/here for more.

I natively tried putting the same syntax into a one-liner and it seems to do what you're after:

$ conda install "conda-forge::black" "main::click" -c conda-forge -c main
Collecting package metadata (current_repodata.json): done
Solving environment: done

## Package Plan ##

  environment location: /Users/mwt/miniconda3

  added / updated specs:
    - conda-forge::black
    - main::click


The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    click-8.0.3                |     pyhd3eb1b0_0          73 KB  main
    mypy_extensions-0.4.3      |   py37hf985489_4          10 KB  conda-forge
    typed-ast-1.5.1            |   py37h271585c_0         207 KB  conda-forge
    ------------------------------------------------------------
                                           Total:         290 KB

The following NEW packages will be INSTALLED:

  black              conda-forge/noarch::black-21.12b0-pyhd8ed1ab_0
  click              main/noarch::click-8.0.3-pyhd3eb1b0_0
  dataclasses        conda-forge/noarch::dataclasses-0.8-pyhc8e2a94_3
  mypy_extensions    conda-forge/osx-64::mypy_extensions-0.4.3-py37hf985489_4
  pathspec           conda-forge/noarch::pathspec-0.9.0-pyhd8ed1ab_0
  platformdirs       conda-forge/noarch::platformdirs-2.3.0-pyhd8ed1ab_0
  tomli              conda-forge/noarch::tomli-1.2.2-pyhd8ed1ab_0
  typed-ast          conda-forge/osx-64::typed-ast-1.5.1-py37h271585c_0
  typing_extensions  conda-forge/noarch::typing_extensions-4.0.1-pyha770c72_0

The following packages will be UPDATED:

  certifi            pkgs/main::certifi-2021.10.8-py37hecd~ --> conda-forge::certifi-2021.10.8-py37hf985489_1

The following packages will be SUPERSEDED by a higher-priority channel:

  ca-certificates    pkgs/main::ca-certificates-2021.10.26~ --> conda-forge::ca-certificates-2021.10.8-h033912b_0
  conda              pkgs/main::conda-4.11.0-py37hecd8cb5_0 --> conda-forge::conda-4.11.0-py37hf985489_0
  openssl              pkgs/main::openssl-1.1.1l-h9ed2024_0 --> conda-forge::openssl-1.1.1l-h0d85af4_0


Proceed ([y]/n)?
Matt Thompson
  • 641
  • 3
  • 14
  • Very nice! Could you give an example of how the line would look like if one wants to install multiple packages from one channel? I guess something like `conda install "conda-forge::black" "conda-forge::white" "main::click" "main::me"-c conda-forge -c main`? – Johannes Wiesner Jan 06 '22 at 17:54
  • 2
    If you wanted to install many packages from one channel but one/few from another, I think it would be easier to modify the channel priority, i.e. `conda install black isort flake8 numpy matplotlib "main::other_package" -c conda-forge -c main`. This might require setting strict channel priority. My $0.02 here for anything this complex would be to try to use a YAML file, though, since that more explicitly tracks the state. – Matt Thompson Jan 06 '22 at 18:05
  • 2
    Despite adding my own answer, I fully endorse the broader suggestion here, i.e., consider using a YAML. It's a much more deliberate and systematic way to work with environments, and you can keep them version controlled. – merv Jan 06 '22 at 18:42