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

时间:2013-03-17 21:07:25

标签: python virtualenv

我有一个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'])]

当我想以python setup.py install的root身份安装软件时,这很好用,但当然在virtualenv中失败,因为不允许用户写入/etc和{{1} }。

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

2 个答案:

答案 0 :(得分:10)

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

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

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

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

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

然而,当从virtualenv前缀与其编译前缀运行时,Python确实有一个轻微的运行时差异: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-python,则将不会设置real_prefix,但用户仍具有对其的写入权限Python lib目录,可能写入/etc/usr/share/man

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

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

答案 1 :(得分:0)

仅将问题缩小到其标题:

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

已经7岁多了,被接受的答案对我不起作用(在Ubuntu 18.04上为python 3.6.9)。

当我在虚拟环境中时,它无法检测到我处于激活状态。更具体地说,getattr(sys, "real_prefix", None)返回了"/usr",并且(错误地)得出结论,我不是在虚拟环境中运行。

问题本身建议的替代解决方案效果很好(1)。 尽管上面有异议,但在非常见情况下它可能并不可靠。

保存到文件is-in-venv并使其可执行,可以从外壳程序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) 为了使潜在的未来用户受益,正在为2020年的python3寻找书面标题的可行解决方案。