【问题标题】:Using conda install within a python script在 python 脚本中使用 conda install
【发布时间】:2017-06-05 15:50:42
【问题描述】:

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

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

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

【问题讨论】:

  • 您为什么不尝试并报告回来? :)
  • 回报什么?
  • 你总是可以使用子进程
  • 是的,我也可以只使用 bash 脚本,但我想避免在 Python 中执行 shell 命令,因为这看起来很不自然。可以从 Python 脚本中导入 pip 并安装包,看起来我也可以导入 conda。只是看不到如何在 Python 脚本中使用 conda。
  • 虽然在 Python 中可以使用import pip,也就是explicitly discouraged in pip's documentation。对于使用 pip 和 conda 推荐的面向公众的 API,我没有看到任何骇人听闻的事情——这些 API 基于调用带有参数和选项标志的新进程。 conda 现在有一个模仿命令行的 Python API(参见@YenForYang 的回答)。首次发布此问题时,此 API 不存在。

标签: python installation anaconda conda


【解决方案1】:

在 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 中明确声明。

【讨论】:

  • 我想使用您的解决方案,但我遇到了抱怨conda init 未运行的问题。我认为它实际上会读取您的 bashrc (或其他)的来源并阻止您继续。如果命令行上有办法禁用此功能(未记录 AFAIK),那么这是您列出的原因的最佳方法。
  • 在运行与condasubprocess 交互的Python 脚本之前,我通常在环境中运行conda activate base。我不确定你所说的环境东西是什么意思。我使用这些脚本与 conda 环境进行交互。
  • 我正在使用一个远程调用框架(invoke/fabric),它使事情变得复杂,所以我不能只事先运行conda activate。关于“环境的东西”:我也在尝试自动创建、销毁和激活不属于 conda.cli.python_api 的环境
  • 这确实让它变得更难了。当我需要 conda 环境时,我通常将我的 Python 脚本包装在使用 conda activate 的 bash 脚本中。 conda activate 所做的只是设置环境变量,因此您可以查看它的作用并手动设置它们。另一种方法是将所有 conda 调用包装在 conda run 中,但它仍然是 alpha 级别的功能。对于conda run,请尝试尽可能使用新版本的 conda 以获得更好的支持(one important improvement 尚未发布 conda)。
  • 不知道conda run,但我一定会留意的。手动设置变量可能会作为一个快速补丁,但对于自动化的东西来说听起来真的很脆弱。
【解决方案2】:

试试这个:

!conda install xyzpackage

请记住,这必须在 Python 脚本而不是操作系统提示中完成。

或者你可以尝试以下方法:

import sys
from conda.cli import main

    sys.exit(main())

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

【讨论】:

  • 这看起来有点骇人听闻,因为它正在执行一个 shell 命令。我想导入 conda 并调用它的等效安装函数。
  • 查看上面的链接,它提供了关于 conda 和 python 模块的信息。 Conda 是一个环境和实用程序,可在操作系统中使用,而不是在 python 模块中。你有什么特别的 anaconda 包吗?
  • 请看@mike-muller 的回答,事实上,您can 从Python 脚本中访问conda。
  • 这是一个 hack,但它有效。以有限的剂量使用它,并了解其后果!
【解决方案3】:

我发现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 的环境的名称。

【讨论】:

  • 我想以编程方式将环境导出到 requirements.txt 文件。但是 'file_path_from_history' 的正确值应该是什么?当我运行您的命令时,我收到“NameError: name 'file_path_from_history' is not defined”消息。
【解决方案4】:

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

import os

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

并确保以管理员身份运行脚本。

【讨论】:

  • 你不应该依赖管理员权限来处理 conda 的任何内容(除非它是通过你的操作系统包管理器分发的,我不知道它是通过你的操作系统包管理器分发的)。也违背了问题的要求。
【解决方案5】:

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

  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()时出现的问题(在上面的cmets中提到):

...conda 试图解释命令行参数而不是 conda.cli.main() 的参数,因此像这样使用 conda.cli.main() 可能不适用于某些事情。


上面cmets中的另一个问题是:

频道不是默认频道时如何【安装包】?

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
)
###################################################################################################

【讨论】:

  • 这应该是公认的答案。最初接受的答案依赖于不保证稳定性的内部 API。另外,我认为完整的答案应该提到使用 subprocess 模块调用 conda。使用 --json 选项从 subprocess 模块调用 conda 并解析结果是完全有效的,并且可能更加稳定。它也不需要在 conda 环境中安装conda。出于性能原因避免使用subprocess 可能是过早的优化。
  • 什么是频道?
【解决方案6】:

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

import conda.cli

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

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

-y, --yes 不要求确认。

【讨论】:

  • 谢谢!这成功了,这正是我想要的。我在 conda 脚本本身中看到了这一点,但无法破译如何使用它。我传递的是一个列表而不是一组命令。
  • 我发现当我尝试使用具有命令行参数的脚本执行此操作时,conda 试图解释命令行参数而不是conda.cli.main() 的参数,所以像这样使用conda.cli.main()可能不适用于某些事情。
  • 频道不是默认的怎么办?
  • @ws_e_c421 如果您正在寻找该问题的解决方案(仍然),请参阅下面的答案。
  • @pceccon 只需添加参数'-c', '&lt;CHANNEL&gt;'。请参阅下面的答案以获取示例。
猜你喜欢
  • 2017-09-23
  • 2012-01-18
  • 1970-01-01
  • 1970-01-01
  • 2012-10-07
  • 2019-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多