当安装包使用 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 问题和我要遵循的解决方案,我想我可能终于有了一些值得回馈这个我已经使用了这么久的网站的东西。
我的设置
- OS: macOS 卡特琳娜
- Shell:bash(是的,我在 Catalina 更新后将其改回并抑制了唠叨的 'zsh is now default' 消息)
- IDE: PyCharm 19.1 专业版
- 蟒蛇:4.4.7
- Python: 3.7
上下文 -
我开发了几个交互数据科学包,并作为一般做法在本地以可编辑模式安装它们:
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
错误。
到目前为止已经尝试过
- 已验证并尝试通过
which python
终端命令设置使用哪个 python。我可以看到默认值是 /Users/my_user_name/anaconda3/bin/python
,如果我在我的项目中从命令提示符执行此操作,我会看到 /Users/my_user_name/anaconda3/envs/my_env/bin/python
,反映了预期的环境版本。
- 检查
/Users/my_user_name/anaconda3/envs/my_env/bin/my_entry_name
中的实际入口点文件以查看 shebang 行如何指示 python 版本,即 #!/Users/my_user_name/anaconda3/envs/my_env/bin/python
- 尝试将这个 shebang 添加到我的 .command 文件的顶部
- 重新安装了我的包很多次,认为入口点可能没有以某种方式正确注册。
- 经常使用 bash 和 zsh,认为通过 Catalina 更新过渡到 zsh,然后再回到 bash 可能会导致问题。
- 试图通过从虚拟环境返回来恢复功能,但无法使 PyCharm 非虚拟解释器设置再次工作。
- 查看 $PATH 内容是否有问题。
- 阅读了很多关于虚拟环境的教程(我发现的都停留在非常基础的地方)
- 追寻有关虚拟环境相关设置工具错误的话题
- 这些努力的许多组合。
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?
问题- 从非虚拟环境转移到 conda 虚拟环境会导致无法识别控制台脚本入口点。
背景 - 我最近试图让我的 Python 项目相信使用虚拟环境。我决定在更新到 macOS Catalina 后执行此操作导致我所有的 PyCharm 项目显示无效的解释器错误。我想 "What could go wrong throwing one big mess on top of another?" 两天后我终于可以再次 运行 编写脚本了——这是我遇到过的最糟糕的砖墙。我无法在任何地方找到解决方案,所以我正在写我的第一个 SO 问题和我要遵循的解决方案,我想我可能终于有了一些值得回馈这个我已经使用了这么久的网站的东西。
我的设置
- OS: macOS 卡特琳娜
- Shell:bash(是的,我在 Catalina 更新后将其改回并抑制了唠叨的 'zsh is now default' 消息)
- IDE: PyCharm 19.1 专业版
- 蟒蛇:4.4.7
- Python: 3.7
上下文 - 我开发了几个交互数据科学包,并作为一般做法在本地以可编辑模式安装它们:
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
错误。
到目前为止已经尝试过
- 已验证并尝试通过
which python
终端命令设置使用哪个 python。我可以看到默认值是/Users/my_user_name/anaconda3/bin/python
,如果我在我的项目中从命令提示符执行此操作,我会看到/Users/my_user_name/anaconda3/envs/my_env/bin/python
,反映了预期的环境版本。 - 检查
/Users/my_user_name/anaconda3/envs/my_env/bin/my_entry_name
中的实际入口点文件以查看 shebang 行如何指示 python 版本,即#!/Users/my_user_name/anaconda3/envs/my_env/bin/python
- 尝试将这个 shebang 添加到我的 .command 文件的顶部
- 重新安装了我的包很多次,认为入口点可能没有以某种方式正确注册。
- 经常使用 bash 和 zsh,认为通过 Catalina 更新过渡到 zsh,然后再回到 bash 可能会导致问题。
- 试图通过从虚拟环境返回来恢复功能,但无法使 PyCharm 非虚拟解释器设置再次工作。
- 查看 $PATH 内容是否有问题。
- 阅读了很多关于虚拟环境的教程(我发现的都停留在非常基础的地方)
- 追寻有关虚拟环境相关设置工具错误的话题
- 这些努力的许多组合。
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?