从setup.py文件中检测Python包的安装路径

10
安装完成后,我想要创建软链接到安装过程中创建的某些配置和数据文件。如何确定从软件包的setup.py中安装的新软件包文件的位置?我最初硬编码了路径“/usr/local/lib/python2.7/dist-packages”,但在尝试使用虚拟环境(由virtualenv创建)时,它会出现错误。我尝试使用distutils.sysconfig.get_python_lib(),在虚拟环境中可以工作,但在实际系统上安装时,它返回“/usr/lib/python2.7/dist-packages”(注意缺少“local”目录)。我还尝试使用site.getsitepackages():在基本环境中运行Python shell:
import site
site.getusersitepackages()
'/home/sarah/.local/lib/python2.7/site-packages'
site.getsitepackages()
['/usr/local/lib/python2.7/dist-packages','/usr/lib/python2.7/dist-packages']
在名为“testenv”的虚拟环境中运行Python shell:
import site
site.getsitepackages()
Traceback(most recent call last):
File“”,第1行,在()之前
AttributeError:'module' object has no attribute 'getsitepackages'

我在Ubuntu上运行“Python 2.7.3(默认值,Aug 1 2012, 05:14:39)”,并使用“[GCC 4.6.3] on linux2”。我可能可以通过尝试/除块拼凑一些东西,但似乎应该有一些由distutils/setuptools设置/返回的变量。(只要它有效,我对使用哪个分支不偏不倚。)

谢谢。


一种方法是使用 import <yourpackage> 并从 <yourpackage>.__file__ 中剥离包名。虽然我相信还有更好的方法。 - ev-br
我可能会尝试这个解决方法,但我希望有一种不像临时应急措施的东西。另外,setuptools.setup()返回一个对象,但似乎没有属性描述它所做的事情。build/、dist/和*.egg-info/目录是其他适合存储此信息的地方……但它们并没有包含该信息。 - Sarah Messer
在 distutils 的源代码中研究时发现了一些有趣的内容:distutils.command.install.INSTALL_SCHEMES、distutils.command.install.install.user_options 和 distutils.command.install.install.sub_commands 看起来具有相关信息/功能,但我还不知道如何利用它们...特别是从 setup.py 中。 - Sarah Messer
2个回答

1
我还没有找到“正确”的方法来做到这一点,但我已经发现了几个看起来几乎正确的技巧。其中一种方法只适用于安装;另一种方法仅在包已安装时才适用。
对于安装,我使用setuptools.setup()返回的对象:
from setuptools import setup
s = setup([...])
installation_path = s.command_obj['install'].install_lib

(这仅在安装过程中起作用,因为您需要一个有效的Distribution对象才能存在这些属性。据我所知,获得这样的对象的唯一方法是运行setup()。)

在卸载时,我使用包的file属性,如@Zhenya上面建议的那样。唯一的问题是,当我运行./setup.py uninstall来摆脱package时,我通常会有目录./package/./build./dist./package.egg-info/。(“卸载”选项被我的代码捕获,而不调用setup()。它运行一个手动创建的脚本来删除包文件。)这些可能会将Python解释器重定向到某个其他地方,而不是我试图摆脱的全局可访问存储库。以下是我的hack处理方法:

import imp
import sys
from subprocess import Popen
from os import getcwd
Popen('rm -r build dist *.egg-info', shell=True).wait()
oldpath = sys.path
rundir = getcwd()
sys.path.remove(rundir)
mod = imp.find_module(PACKAGE)
p = imp.load_module(PACKAGE, mod[0], mod[1], mod[2])
sys.path = oldpath
installation_path = p.__file__

这在安装期间不起作用,因为我认为Python只有在启动时才会列出模块,因此find_module()无法找到刚安装的软件包,除非您退出Python并重新进入。我已经在裸机环境和虚拟环境(来自virtualenv 1.9.1)中测试了安装和卸载。我正在运行Ubuntu 12.04 LTS,Python 2.7.3,setuptools 0.6c11(在裸机环境中)和setuptools 0.7.4(在虚拟环境中)。

我猜这个不再起作用了。在Python 3中,我得到了以下错误信息:Traceback (most recent call last): File "<string>", line 1, in <module> File "/tmp/pip-req-build-a1c6n4hb/setup.py", line 14, in <module> s = setup([...]) TypeError: setup() takes 0 positional arguments but 1 was given - Ben Farmer
这个可能在Python 3中不起作用,但你得到的错误消息表明你省略了setup()所需的必要输入。(我在我的答案中没提到它们,因为它们是与环境相关的)查看Python 3 setup()的详细信息,请访问https://setuptools.readthedocs.io/en/latest/setuptools.html#configuring-setup-using-setup-cfg-files - Sarah Messer
啊,抱歉,我有点傻。不过,我有两个问题:1.在运行setup()之前,我需要知道安装路径,因为我必须在setup中告诉一些额外的构建代码有关这个路径,这样它就可以设置rpath并将文件复制到正确的位置。2.我尝试通过创建一个“虚拟”的setup()对象来规避这个问题,该对象什么都不做,但是我仍然会收到错误消息:KeyError:“install”。所以也许在Python 3中无法解决。 - Ben Farmer
为此,我会尝试手动查找setup()的代码(和文档),寻找系统如何确定适当路径的方法... 根据我的经验,路径似乎是基于系统参数、setup.py调用的详细信息(如用户权限)以及Python版本来确定的,并且与安装的软件包几乎没有关系。由于您控制着调用setup.py的脚本,因此您可以尝试进行测试安装并假设它始终是相同的路径。 - Sarah Messer

0
这可能不是你问题的答案,但如果你需要访问已安装包的源代码或该包中的任何其他文件,最好的方法是以开发模式安装此包(通过下载源代码,将其放在任何你想要的位置,然后在包源代码的基本目录中运行python setup.py develop)。这样你就知道包的位置了。

这是一个我以前没有见过的有趣功能(谢谢!),但似乎它并不能帮助我在其他地方链接到代码。 - Sarah Messer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接