【问题标题】:Including Package Data Python from Top-level when Package is in Subdirectory当包位于子目录中时,从顶层包含包数据 Python
【发布时间】:2020-10-14 11:17:43
【问题描述】:

我正在尝试打包一系列配置文件以及一些源代码。我有一个这样的目录结构(由于团队的性质,我无法更改)

.
├── configs
│   ├── machines
│   ├── scope
├── esm_tools
│   ├── __init__.py
├── README.rst
├── setup.cfg
├── setup.py

61 directories, 45 files (Truncated)

据我了解 (https://docs.python.org/3/distutils/setupscript.html#installing-package-data),我可以在 setup 调用中添加一些部分:


setup(
    # ... other stuff
    include_package_data=True,
    name="esm_tools",
    packages=["configs", "esm_tools"],
    package_dir={"configs": "configs", "esm_tools": "esm_tools"},
    package_data={'configs': ['*']},
    version="4.1.5",
    zip_safe=False,
)

但是,我无法通过以下方式访问包数据:

In [1]: import pkg_resources                                                                                                                                                                                                                                                                       

In [2]: pkg_resources.resource_listdir("esm_tools", "config")                                                                                                                                                                                                                                      
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
<ipython-input-2-f0f255c14df6> in <module>
----> 1 pkg_resources.resource_listdir("esm_tools", "config")

/global/AWIsoft/miniconda/4.7.12/lib/python3.7/site-packages/pkg_resources/__init__.py in resource_listdir(self, package_or_requirement, resource_name)
   1161         """List the contents of the named resource directory"""
   1162         return get_provider(package_or_requirement).resource_listdir(
-> 1163             resource_name
   1164         )
   1165 

/global/AWIsoft/miniconda/4.7.12/lib/python3.7/site-packages/pkg_resources/__init__.py in resource_listdir(self, resource_name)
   1439 
   1440     def resource_listdir(self, resource_name):
-> 1441         return self._listdir(self._fn(self.module_path, resource_name))
   1442 
   1443     def metadata_listdir(self, name):

/global/AWIsoft/miniconda/4.7.12/lib/python3.7/site-packages/pkg_resources/__init__.py in _listdir(self, path)
   1608 
   1609     def _listdir(self, path):
-> 1610         return os.listdir(path)
   1611 
   1612     def get_resource_stream(self, manager, resource_name):

FileNotFoundError: [Errno 2] No such file or directory: '/home/ollie/pgierz/dev/esm_tools/esm_tools/esm_tools/config'

任何帮助将不胜感激,我不确定我做错了什么......

【问题讨论】:

  • 所以安装后configs/machines应该可以在esm_tools/config/machines下访问?
  • 你能展示一下pkg_resources/__init__.py里面的内容吗?从您的回溯中,很明显您的路径是错误的:'/home/ollie/pgierz/dev/esm_tools/esm_tools/esm_tools/config'esm_tools 路径中的 3 次都不对。所以看看get_provider 函数做了什么会很有帮助。
  • @pgierz 如果您想在已安装的包中将 configs 重新映射到 esm_tools/config,可以这样做,但 AFAIK 不适用于可编辑安装。否则,您当前的设置包括 configs 作为一个单独的包(即使它是一个命名空间),所以 pkg_resources.resource_listdir('configs') 应该可以工作。您正在调用pkg_resources.resource_listdir("esm_tools", "config"),这实际上是“在esm_tools 下查找目录config”,而当前的设置是无法获得的。
  • 这是可能的,但同样,可编辑安装不支持该 AFAIK,因此您必须为本地开发构建解决方法。我会尽快添加答案。

标签: python setuptools python-packaging


【解决方案1】:

根据您的电话pkg_resources.resource_listdir("esm_tools", "config"),我假设您想在已安装的包中将configs 重新映射为esm_tools.config

site-packages
├── esm_tools
│   ├── __init__.py
│   ├── config
│   │   ├── machines
│   │   ├── scope

这意味着你必须做以下事情:

  1. 告诉setuptools 包含一个子包esm_tools.config(即使它在源代码库中并不真正存在并且在技术上是一个命名空间,我们将通过进一步的配置来构建它)
  2. 告诉setuptools 新的esm_tools.config 包的源代码在哪里(这也是告诉setuptools 在dist 中包含什么的必要措施。包本身不会提供任何Python 源代码,因为没有 Python 文件位于 configs)。
  3. 告诉setuptools 包含来自正确路径的esm_tools.config 的包数据。

例子:

setup(
    ...,
    packages=['esm_tools', 'esm_tools.config'],           # 1
    package_dir={'esm_tools.config': 'configs'},          # 2
    package_data={'esm_tools.config': ['../configs/*']},  # 3
)

请注意,这不适用于可编辑安装(无论是通过pip install --editable . 还是python setup.py develop),因此您将不得不使用符号链接或.pth 文件或其他东西构建或多或少难看的本地解决方法。车轮分布(通过python setup.py bdist_wheelpip wheel 构建)将开箱即用,对于源分布,您必须通过MANIFEST.in 包含configs 目录,因为package_data 不会在@ 读取987654342@时间:

# MANIFEST.in
...
graft configs

【讨论】:

  • 很好的答案!想知道include_package_data=True是否仍然需要(取决于是否有问题中未提及的其他包数据文件)。
  • @sinoroc 谢谢!事实上,include_package_data=Truezip_safe=False 都与答案中的示例代码无关,我只是从问题中复制了代码并编辑了内容。
  • 对其他人的重要提示:注意configconfigs。我有一个错字,有短暂的困惑。
  • 这是同一行的两倍。我看不出你指的是什么。
猜你喜欢
  • 2015-08-27
  • 1970-01-01
  • 2018-06-02
  • 1970-01-01
  • 1970-01-01
  • 2010-11-09
  • 2014-09-29
  • 2011-04-24
  • 2016-03-13
相关资源
最近更新 更多