从 python egg 访问文件

Access a file from a python egg

您好,我正在使用 python 包装。我有 3 个 non-code 个文件,即 ['synonyms.csv', 'acronyms.csv', 'words.txt']

问题是当我从代码中创建一个 egg,然后 运行 它,

我的代码给出错误:

Could not find the file at X:. Projects\Python\Wordproject\venv\lib\site-packages\Wordproject-1.0-py3.6.egg\Wordproject\Repository\DataBank\synonyms.csv

如果路径是鸡蛋,则无法从路径中获取文件或读取文件。有什么办法吗?这些文件必须在 egg.

egg 文件只是重命名为 .zip 文件。

您可以使用zipfile库打开egg并提取或读取您需要的文件。

import zipfile

zip = zipfile.ZipFile('/path/to/file.egg', 'r')

# open file from within the egg
f = zip.open('synonyms.csv', 'r')
txt = f.read()

您可以在这里尝试做两种不同的事情:

  • 将数据文件视为包的一部分,就像 Python 模块一样,并在运行时访问它们,就像您的包是普通目录树一样,即使它不是。
  • pip install时获取安装在其他地方的数据文件,到您可以正常访问的位置。

两者在the section on data files in the PyPA/setuptools docs. I think you want the first one here, which is covered in the subsection on Accessing Data Files at Runtime中都有解释:

Typically, existing programs manipulate a package’s __file__ attribute in order to find the location of data files. However, this manipulation isn’t compatible with PEP 302-based import hooks, including importing from zip files and Python Eggs. It is strongly recommended that, if you are using data files, you should use the ResourceManager API of pkg_resources to access them. The pkg_resources module is distributed as part of setuptools, so if you’re using setuptools to distribute your package, there is no reason not to use its resource management API. See also Accessing Package Resources for a quick example of converting code that uses __file__ to use pkg_resources instead.

跟随 link,您会发现一些看起来像一些笨拙的旧 PEAK 文档的内容,但这只是因为它们确实是笨拙的旧 PEAK 文档。有一个 version buried inside the setuptools docs,一旦您设法找到它,您可能会发现它更易于阅读和导航。

正如它所说,您 可以 try 使用 get_data (这将在 egg/zip 内工作)然后回退到访问一个文件(当来自源 运行 时可以工作),但你最好使用 pkg_resources 中的包装器。基本上,如果您的代码是这样做的:

path = os.path.join(__file__, 'Wordproject/WordProject/Repository/DataBank/', datathingy)
with open(path) as f:
    for line in f:
        do_stuff(line)

…你会把它改成这样:

path = 'Wordproject/WordProject/Repository/DataBank/' + datathingy
f = pkg_resources.resource_stream(__name__, path)
for line in f:
    do_stuff(line.decode())

请注意 resource_stream 文件始终以二进制模式打开。因此,如果你想将它们作为文本阅读,你需要在它们周围包裹一个 TextIOWrapper,或者解码每一行。

基于documentation,我们可以通过多种方式读取文件内容。

方案一:直接将文件内容读入内存

没有在本地提取文件。

import zipfile, tempfile
tfile = tempfile.NamedTemporaryFile()
with zipfile.ZipFile('/path/to/egg.egg') as myzip:
    with myzip.open('relative/path/to/file.txt') as myfile:
        tfile.write(myfile.read())

# .. do something with temporary file

tfile.close()

现在 tfile 是您的本地临时文件句柄。它的名称是 tfile.name 并且所有文件操作(例如 open(tfile) 等)都照常进行。 tfile.close() 必须在最后调用以关闭句柄。

文件内容可以被 myfile.read() 本身读取,但是一旦退出上下文,我们就会丢失 myfile 句柄。因此,如果需要为其他操作传递文件内容,则会将其复制到临时文件中。

方案二:在本地提取egg成员

zipfile 提供了一个 API 用于提取特定成员

import zipfile
x = zipfile.ZipFile('/path/to/egg.egg')
x.extractall(path='temp/dest/folder', members=['path/to/file.txt'])

解决方案 3:提取整个鸡蛋

另一种解决方案是将egg解压到临时文件夹中,然后读取文件。 Egg 可以在命令行中提取如下

python -m zipfile -e path/to/my.egg ./temp_destination

如果您使用的是 Python 3.7 或更高版本,我建议您使用 importlib_resources。从他们的文档 https://importlib-resources.readthedocs.io/en/latest/using.html 中,这里有一个将 YAML 文件放入模块的示例:

from importlib_resources import files, as_file

yaml_path = files('my-module').joinpath('openapi.yml')
with as_file(yaml_path) as yaml:
    conn_app.add_api(yaml)

如果通过 pip3 install . 将模块安装在目录中,并且 如果通过 python3 setup.py install[=] 作为 egg (zip) 文件安装,则此方法有效14=]