当安装包使用 conda 虚拟环境时,如何使 Python 控制台脚本入口点工作?

How do you make Python console script entry points work when installed package uses a conda virtual environment?

问题- 从非虚拟环境转移到 conda 虚拟环境会导致无法识别控制台脚本入口点。

背景 - 我最近试图让我的 Python 项目相信使用虚拟环境。我决定在更新到 macOS Catalina 后执行此操作导致我所有的 PyCharm 项目显示无效的解释器错误。我想 "What could go wrong throwing one big mess on top of another?" 两天后我终于可以再次 运行 编写脚本了——这是我遇到过的最糟糕的砖墙。我无法在任何地方找到解决方案,所以我正在写我的第一个 SO 问题和我要遵循的解决方案,我想我可能终于有了一些值得回馈这个我已经使用了这么久的网站的东西。

我的设置

上下文 - 我开发了几个交互数据科学包,并作为一般做法在本地以可编辑模式安装它们:

My_Machine:my_package my_user_name$ pip install -e .

我使用 setup.py 文件和 setuptools 创建 python 包,使用 PyCharm 构建。在 setup.py 文件中,我这样定义控制台脚本入口点:

setup.py:

# -*- coding: utf-8 -*-

from setuptools import setup, find_packages

setup(...
      name='my_project',
      entry_points={'console_scripts':['my_entry_name=my_package.scripts.my_python_script:main'
                                      ]},
     ...
)

在转移到 conda 虚拟环境之前,多年来我一直在 运行通过这样的批处理文件完美地编写脚本:

my_batch_file.command:

#!/bin/bash
cd "$(dirname "[=13=]")"  # set the working directory as the command file locations

my_entry_name <script arguments>

但是,在切换到 conda 虚拟环境后,运行 宁命令文件产生 my_entry_name: command not found 错误。

到目前为止已经尝试过

None 有效 - 同样的 my_entry_name: command not found 错误。这两天特别郁闷

经过两天的努力,我找到了一个解决方案,我将在下面post,但是我非常想听听评论、替代方案,以及直截了当的“你是个白痴”教育。

看来需要两个要素:

  • 指示 python 的版本以用作与虚拟环境关联的版本(因为我尝试不成功)。
  • 正在激活虚拟环境。

我将我的 .command 文件更改为此,在指定 python 版本和相关文本输出之前和之后添加了几个不必要的验证检查:

my_batch.command:

#!/usr/bin/env bash

echo "VERIFY: Python version BEFORE activating virtual environment:"
which python

echo "Activating conda virtual environment..."
source activate my_env_name

echo "Setting python version to use in this environment..."
#!/Users/my_username/anaconda3/envs/my_env_name/bin/python

echo "VERIFY: Python version AFTER activating virtual environment:"
which python

cd "$(dirname "[=10=]")"  # set the working directory as the command file locations

echo "RUN THE SCRIPT:"
my_entry_name <script arguments>

我遗漏的关键行是 source activate my_env_name。我确认删除它会导致失败,并且每次都必须包含它,而不仅仅是一次,因此包含在我的 .command 文件中。

我也不清楚有多条 shebang 行是否可以,但这工作正常。

我很高兴又能正常工作了,但我不得不承认我很沮丧,因为该体系结构不仅仅让我的入口点工作,期间,没有这种笨拙。拥有入口点的原因是允许脚本的使用者轻松调用它,而不必关心脚本的位置和安装方式等细节。虚拟环境的使用似乎消除了这些入口点的便利。我完全赞成使用虚拟环境的好处,但是有什么方法可以让我的蛋糕也吃到吗?理想情况下,调用入口点将激活虚拟环境并知道要使用哪个版本的 python。有没有更好的方法来做到这一点?

您不必激活 Python 虚拟环境,一次都不需要。 假设您在 /venv 有一个虚拟环境,那么您可以随时随地调用 /venv/bin/python/venv/bin/my_entry_name,而无需激活虚拟环境,它应该可以正常工作。如果它不起作用,则说明您的设置有问题,必须修复。

当您使用 setuptools console_scripts 入口点 Python 解释器在虚拟环境中的完整路径环境在 shebang 中是硬编码的,因此这不可能不起作用。


更新

糟糕,我没有注册你正在使用 conda 虚拟环境。我不知道这些是如何工作的,也许我的观点仍然成立,但可能不成立。

进一步输入和试验后修改的答案。我找到了两个选项,它们都需要知道定义入口点的实际文件在哪里。对于 conda 虚拟环境,它将在此处:

/anaconda3/envs/my_env_name/bin/entry_point_name

调用此文件不需要指定python版本,也不需要激活环境。我找到了两种方法:

选项 1 - 感谢@sinoroc,他首先指出如果正确调用入口点,则无需激活虚拟环境。对于 conda 虚拟环境,这将是:

my_batch_file.command

#!/bin/bash
cd "$(dirname "[=11=]")"  # set the working directory as the command file locations

~/anaconda3/envs/my_env_name/bin/entry_point_name <my script args>

对于其他类型的虚拟环境,您只需调整路径详细信息即可到达入口点文件。

选项 2 - 如果将入口点文件的副本放在主 Anaconda bin 中:

/anaconda3/bin/my_entry_name

你不需要指定路径,让你调用入口点就像他们应该工作一样,恕我直言 - 即屏蔽脚本用户的语言和安装细节:

my_batch_file.command

#!/bin/bash
cd "$(dirname "[=13=]")"  # set the working directory as the command file locations

entry_point_name <my script args>

由于这个手动复制步骤并不优雅,我已经发布了一个关于如何更好地做到这一点的问题:How do you make an entry point to a script in a virtual environment available system-wide?