【问题标题】:Extract folder from python package resource从 python 包资源中提取文件夹
【发布时间】:2019-09-27 20:47:59
【问题描述】:

在我尝试分发的本地版本的包中,我有以下代码:

shutil.copytree(WWW_LOCATION, dir_path)

WWW_LOCATION 是我的 python 模块的子文件夹,其中包含一些静态文件和文件夹:

dv
  \dv
     mytool.py
     \www_folder
       \somefolders_and_files
  setup.py
  MANIFEST.in
  README.md
  LICENSE
  setup.cfg

在我的代码中,执行后,我需要将整个文件夹与一些动态生成的文件一起复制到用户指定的位置。这在本地工作得很好,但我读到通过 pypi 分发时,我必须小心,因为文件可能会被压缩。

This answer 解释了如何访问资源中的内容(=在 python 中读取它们),但是,一次只能访问一个文件。将文件夹内容复制到指定位置的安全方法是什么?

【问题讨论】:

    标签: python file package


    【解决方案1】:

    “更简单”的解决方案是在你的包设置中设置zip_safe=False(setup.py 或setup.cfg),以避免你的包被安装为一个压缩的鸡蛋。由于大多数安装都是使用 pip 完成的,它从不创建压缩的 egg 安装,所以现在运行到压缩包安装的情况越来越少了。

    然后您只需要担心有人将包手动压缩到压缩文件中以添加到sys.path,您可以选择不支持的用例。那是另一种形式的压缩包。 Eggs 是一个可安装项目的压缩文件(由pkg_resources 支持)并将它们存储在sys.path 上列出的目录中。 pkg_resources只能支持后者,不能支持前者。

    如果您确实想支持压缩鸡蛋,那么对于您的具体情况,使用pkg_resources API for resource extraction 会更容易,因为虽然它可能“更慢”,但它也支持完整的目录树。来自resource_filename() 文档:

    如果命名资源是一个目录,那么该目录中的所有资源(包括子目录)也会被提取。

    我会这样使用它:

    try:
        www_location = pkg_resources.resource_filename("dv", "www_folder")
        shutil.copytree(www_location, dir_path)
    finally:
        pkg_resources.cleanup_resources()
    

    在直接添加到sys.path 的压缩文件中找到的包内的资源无法通过pkg_resources 访问。为此,您需要更新的 importlib.resources module(或 backport),但此 API 不支持任意目录结构。 importlib.resources.path() function documenation 声明:

    package 是符合Package 要求的名称或模块对象。 resource 是要在包中打开的资源的名称;它可能不包含路径分隔符,也可能没有子资源(即它不能是目录)。

    (我的粗体强调)。

    虽然您可以使用 importlib.resources.contents() 在包中查找目录,但您实际上无法访问这些目录的内容,除非它们本身就是 Python 包(因此其中有一个 __init__.py 文件)。当使用importlib.resources.path() 时,这些功能的传统非压缩包的实现 仍然可以让您访问目录,但当包包含在.zip 中时,您不能这样做存档。

    importlib.resources 是一种更好的、面向未来的支持途径。为了支持这一点,您可以将www_folder 资源树压缩到您的源和轮子分发中,然后使用with importlib.resources.path("dv", "www_folder.zip") as www_location: www_zip = zipfile.open(www_location) 并将该压缩文件对象中的内容提取到目标位置。

    【讨论】:

    • 感谢您提供的大量帖子 - 我决定使用 zip_safe=False,因为在这种情况下,资源文件只有 60kb,实际上没有必要压缩它们。
    猜你喜欢
    • 1970-01-01
    • 2016-08-06
    • 1970-01-01
    • 1970-01-01
    • 2014-10-24
    • 1970-01-01
    • 2018-11-12
    • 2019-03-24
    • 1970-01-01
    相关资源
    最近更新 更多