从egg包内部访问Python egg中的文件

10

这个问题是尝试获得如何执行该操作的精确指令。之前有过几次尝试,但似乎都不是完整的解决方案:

将文件移动到包内的解决方案

作为zip文件读取的解决方案

通过get_distribution访问元信息的解决方案

手头的任务是读取程序正在运行的egg的信息。我理解有几种方法:

  1. 硬编码蛋的位置并将其视为zip档案-这将起作用,但不够灵活,因为如果文件移动到另一个位置,则需要编辑和重新编译

  2. 使用ResourceManager().resource_filename(__name__, filename)-这似乎在事实上受到限制,因为我无法访问位于蛋内而不在包内的文件。如filename中的"../../EGG-INFO/PKG-INFO"等标记不起作用,会产生KeyError。因此也不好用。

  3. 使用dist = pkg_resources.get_distribution("dist_name"),然后使用dist对象获取信息,但我无法从文档中理解应该如何指定我的分发名称?它找不到它。

所以,我正在寻找正确的关于使用pkg_resources.get_distribution的解决方案,同时终于有一个完整的解决方案来读取蛋内的任何文件。

谢谢!

2个回答

8
Setuptools/distribute/pkg_resources旨在成为Python标准distutils的透明覆盖层,后者相当有限,并且不允许很好地分发代码。 蛋只是一种将一堆Python文件、数据文件和元数据组合在一起的方式,有点类似于Java JARs——但即使没有egg(这是标准分发中不存在的概念),Python包也可以从源代码安装。 所以这里有两种情况:要么你是一个程序员,试图使用库中的某个文件,在这种情况下,为了读取分发中的任何文件,你不需要其完整路径——你只需要一个打开的文件对象及其内容,对吗?因此,你应该这样做:
from pkg_resources import resource_stream, Requirement
resource_stream(Requirement.parse("restez==0.3.2"), "restez/httpconn.py")

这将返回您从软件包分发中请求的文件的打开、可读文件。如果是压缩的egg文件,则会自动解压。

请注意,您应该在(restez)内指定软件包名称,因为分发名称可能与软件包名称不同(例如,分发Twisted然后使用扭曲的软件包名称)。要求解析使用此语法:http://setuptools.readthedocs.io/en/latest/pkg_resources.html#requirements-parsing

这应该足够了——一旦您知道如何从egg文件中获取文件,您就不需要知道egg文件的路径。

如果您确实想要完整路径并且确定您的egg文件未压缩,请使用resource_filename而不是resource_stream。

否则,如果您正在构建一个“打包工具”并且需要访问您的软件包的内容,无论是egg文件还是其他任何内容,您都必须手动完成,就像pkg_resources一样(pkg_resources源代码)。没有一个精确的API用于“查询egg内容”,因为没有这样的用例。如果您是一个程序员,只需像我建议的那样使用pkg_resources即可。如果您正在构建一个打包工具,您应该知道在哪里放置您的手,并且就这样。


如何组成类似“restez==0.3.2”这样的名称?如果我有一个名为my_program_0.9.egg的文件,我应该说“my_program==0.9”吗?如果文件名中没有版本号怎么办? - Eugene Sajine
@EugeneSajine http://packages.python.org/distribute/pkg_resources.html#requirements-parsing。版本号不在文件名中,而是在分发元数据中 - 这是您在setup.py中指定的内容。 - Alan Franzoni
你是在说这种方式可以让感兴趣的文件不必在包内吗?因为我问题中的p2提供了紧密的方法,但却有这个限制。抱歉,我现在无法自行检查。 - Eugene Sajine
@EugeneSajine resource_stream(Requirement.parse("restez==0.3.2"), "README.txt") 但这取决于打包方式,可能无法与非egg文件一起使用。 - Alan Franzoni
1
很好的解释。但是,如果您正在使用需要完整路径到资源的依赖库,则其并不真正起作用。在这种情况下,您唯一能做的就是使用resource_filename,但如果该egg文件被压缩,则该方法无法使用。 - Emiliano
显示剩余3条评论

3

zipimporter(zipimporter对象)被用来加载一个模块,可以通过访问模块上的__loader__属性来访问它,因此访问egg文件中的文件应该就像这样简单:

__loader__.get_data('path/within/the/egg')

这里的用法对我来说不太清楚,能否请您详细解释一下,并且提供一个更完整的例子?另外,似乎Alan提到的“egg”并不一定是一个zip文件,这是一个很好的观点。 - Eugene Sajine
是的,这确实与一般情况下访问蛋文件无关,而是与压缩的蛋文件有关,它们实际上只是可以放入Python路径中的zip文件。这与setuptools/pkg_resources无关,后者只是提供了一种不同的处理蛋文件的方式,但并非必需品。 - mata

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