5

我有一个 Python 软件,其中包含一个配置文件和一个联机帮助页。要安装这些,我在我的setup.py(如http://docs.python.org/2/distutils/setupscript.html#installing-additional-files中所述)中有以下行:

data_files = [('/etc/foo', ['foo.conf']), ('/usr/share/man/man1', ['foo.1'])]

当我想以 root 身份安装软件时,这工作得很好python setup.py install,但在 virtualenv 中当然会失败,因为不允许用户写入/etc/usr/share/man.

解决这个问题的最佳做法是什么?在当前环境中检查VIRTUAL_ENV并且根本不安装这些文件?该软件会foo.conf在本地目录中查找,所以应该没问题。用户会错过手册页,但无论如何都没有明智的安装方法,因为man不会在 virtualenv 附近的任何地方寻找它。

4

2 回答 2

10

最终,您的问题似乎实际上是关于如何检测正在运行的 Python 是否在 virtualenv 中。要深入了解这一点,我们必须了解virtualenv实际工作原理。

当您activate在 virtualenv 中运行脚本时,它会做两件事:

  • 它更新PATH环境变量以包含bin来自 virtualenv 的目录,这样当你python从 virtualenv 运行二进制文件时,它就会运行。
  • 它设置一个变量VIRTUAL_ENV,以便激活脚本本身可以跟踪激活。

直接python从 virtualenv 运行是完全可以接受的,并且在运行时python根本不使用该VIRTUAL_ENV变量。相反,它确定包含正在运行的python二进制文件的目录并使用父目录作为其“前缀”。

sys您可以通过导入模块和咨询来确定系统的前缀sys.prefix但是,在未激活virtualenv 时依赖 this 的值是一个坏主意,因为这是 Python 的构建时设置,可以轻松自定义,并且肯定会因平台而异。

然而,当 Python从 virtualenv 前缀与其编译的前缀运行时,它确实有一点运行时差异:sys有一个额外的变量real_prefix,它返回编译到 Python 二进制文件中的前缀。因此,可以使用它来识别 Python 正在非默认位置运行,这很可能意味着它是从 virtualenv 运行的:

import sys

if getattr(sys, "real_prefix", None) is not None:
    print "Maybe in a virtualenv"
else:
    print "Probably not in a virtualenv"

然而,即使这也不是一门精确的科学。这一切真正告诉你的是,python 二进制文件不在编译时指定的位置。它不会告诉您当前用户是否有权写入/usr/share/man- 在某些(可能是边缘)情况下,这不会给您正确的答案:

  • 如果用户已经从他的主目录中的源代码编译了他自己的 Python 并且它的编译前缀/home/johnd/local-pythonreal_prefix不会被设置,但用户仍然可以写访问他的 Pythonlib目录,并且可能没有写访问/etc/usr/share/man

  • 同样,在某些系统上,管理员可能已授予/usr/lib/python2.7特定应用程序开发人员组的组写入权限,以便他们可以安装 Python 模块,但未授予他们对其他系统文件的写入权限。

所以我认为最终你能做的最好的就是启发式方法,最好避免在data_files你希望在 virtualenv 中使用的任何模块中使用绝对路径。折衷方案可能是将您的模块简单地拆分为两个发行版,一个代表可本地化的源文件,另一个代表系统范围的配置以使其运行。后者可以依赖前者,这样用户仍然可以轻松安装它,但使用者可以virtualenv选择直接使用另一个前者。

于 2013-03-18T04:49:54.983 回答
0

仅将问题缩小到其标题:

“如何在包安装期间测试 Python 是否从 virtualenv 运行”

超过 7 岁,接受的答案对我不起作用(python 3.6.9在 Ubuntu 18.04 上)。

它未能检测到我在虚拟环境中(已激活并正在使用)。更具体地说,getattr(sys, "real_prefix", None)返回"/usr"并(错误地)得出结论,我没有从虚拟环境中运行。

问题本身建议的替代解决方案效果很好(1)。它简单明了,尽管有人反对它在非常见情况下可能不可靠。

保存到文件is-in-venv并使其可执行,并且可以从 shell 调用它,if is-in-venv; then ...; else ...; fi

#!/usr/bin/env python3

import os
import sys

venvdir = os.getenv('VIRTUAL_ENV')

if venvdir and os.path.isdir(venvdir):
    print("python3 virtual-env detected: %s" % venvdir)
    sys.exit(0)
else:
    print("python3 not in a virtual env")
    sys.exit(1)

(1) 为了潜在的未来用户的利益,他们正在寻找针对 Python3 的书面标题的有效解决方案,大约 2020 年。

于 2020-07-30T03:35:06.350 回答