在 python 脚本中使用 conda install

Using conda install within a python script

根据此 answer 您可以从 Python 脚本中导入 pip 并使用它来安装模块。 conda install 可以做到这一点吗?

conda 文档仅显示命令行中的示例,但我正在寻找可以从 Python 脚本中执行的代码。

是的,我可以从脚本中执行 shell 命令,但我试图避免这种情况,因为它基本上假设无法导入 conda 并调用其函数。

试试这个:

!conda install xyzpackage

请记住这必须在 Python 脚本而不是 OS 提示中完成。

否则您可以尝试以下操作:

import sys
from conda.cli import main

    sys.exit(main())

    try:
        import conda
        from conda.cli import main
        sys.argv = ['conda'] + list(args)
        main()

您可以使用 conda.cli.main。例如,这会安装 numpy:

import conda.cli

conda.cli.main('conda', 'install',  '-y', 'numpy')

使用 -y 参数来避免交互问题:

-y, --yes Do not ask for confirmation.

我在查看最新的 Conda Python API 并注意到实际上只有 2 个 public 模块具有“非常 long-term 稳定性”:

  1. conda.cli.python_api
  2. conda.api

对于你的问题,我会使用第一个:

注意:下面的run_command()总是添加一个-y/--yes选项(即它不会要求确认)

import conda.cli.python_api as Conda
import sys

###################################################################################################
# The below is roughly equivalent to:
#   conda install -y 'args-go-here' 'no-whitespace-splitting-occurs' 'square-brackets-optional'

(stdout_str, stderr_str, return_code_int) = Conda.run_command(
    Conda.Commands.INSTALL, # alternatively, you can just say "install"
                            # ...it's probably safer long-term to use the Commands class though
                            # Commands include:
                            #  CLEAN,CONFIG,CREATE,INFO,INSTALL,HELP,LIST,REMOVE,SEARCH,UPDATE,RUN
    [ 'args-go-here', 'no-whitespace-splitting-occurs', 'square-brackets-optional' ],
    use_exception_handler=True,  # Defaults to False, use that if you want to handle your own exceptions
    stdout=sys.stdout, # Defaults to being returned as a str (stdout_str)
    stderr=sys.stderr, # Also defaults to being returned as str (stderr_str)
    search_path=Conda.SEARCH_PATH  # this is the default; adding only for illustrative purposes
)
###################################################################################################


使用上面的好处是它解决了使用 conda.cli.main():

时出现的问题(在上面的评论中提到)

...conda tried to interpret the comand line arguments instead of the arguments of conda.cli.main(), so using conda.cli.main() like this might not work for some things.


上面评论中的另一个问题是:

How [to install a package] when the channel is not the default?

import conda.cli.python_api as Conda
import sys

###################################################################################################
# Either:
#   conda install -y -c <CHANNEL> <PACKAGE>
# Or (>= conda 4.6)
#   conda install -y <CHANNEL>::<PACKAGE>

(stdout_str, stderr_str, return_code_int) = Conda.run_command(
    Conda.Commands.INSTALL,
    '-c', '<CHANNEL>',
    '<PACKAGE>'
    use_exception_handler=True, stdout=sys.stdout, stderr=sys.stderr
)
###################################################################################################

使用 Python 脚本中的 conda 一段时间后,我认为使用 subprocess 模块调用 conda 整体效果最好。在 Python 3.7+ 中,你可以这样做:

import json
from subprocess import run


def conda_list(environment):
    proc = run(["conda", "list", "--json", "--name", environment],
               text=True, capture_output=True)
    return json.loads(proc.stdout)


def conda_install(environment, *package):
    proc = run(["conda", "install", "--quiet", "--name", environment] + packages,
               text=True, capture_output=True)
    return json.loads(proc.stdout)

正如我在评论中指出的那样,conda.cli.main() 不适合外部使用。它直接解析 sys.argv,因此如果您尝试在您自己的脚本中使用它和您自己的命令行参数,它们也会被提供给 conda.cli.main()

@YenForYang 的回答建议 conda.cli.python_api 更好,因为这是一个公开记录的 API 用于调用 conda 命令。但是,我发现它仍然有粗糙的边缘。 conda 在执行命令时建立内部状态(例如缓存)。通常使用和测试 conda 的方式是作为命令行程序。在那种情况下,这个内部状态在 conda 命令结束时被丢弃。使用 conda.cli.python_api,您可以在单个进程中执行多个 conda 命令。在这种情况下,内部状态会继续存在,有时会导致意外结果(例如,缓存在执行命令时变得过时)。当然,conda直接处理这个内部状态应该是可以的。我的观点只是,以这种方式使用 conda 并不是开发人员的主要关注点。如果您想要最可靠的方法,请使用 conda 开发人员打算使用它的方式——作为它自己的过程。

conda 是一个相当慢的命令,所以我不认为人们应该担心调用子进程的性能影响。正如我在另一条评论中指出的那样,pip 是与 conda 类似的工具,并在 its documentation that it should be called as a subprocess, not imported into Python.

中明确说明

我尝试并为我工作的更简单的事情是:

import os

try:
    import graphviz
except:
    print ("graphviz not found, Installing graphviz ")
    os.system("conda install -c anaconda graphviz")
    import graphviz

并确保您 运行 您的脚本是管理员。

我发现 conda.cli.python_apiconda.api 是有限的,从某种意义上说,它们都没有执行这样的命令的选项:

conda export env > requirements.txt

所以我使用带有标志 shell=True 的子进程来完成工作。

subprocess.run(f"conda env export --name {env} > {file_path_from_history}",shell=True)

其中 env 是要保存到 requirements.txt 的环境的名称。