使用 `setup.py` + `pip` 对 `data_files` 的跨平台支持

Cross-platform support for `data_files` with `setup.py` + `pip`

使用 setup.py(与 pip 兼容)传送 data_files 的跨平台方式是什么?

从官方文档来看,需要这样写:

setup(...,
    data_files=[('bitmaps', ['bm/b1.gif', 'bm/b2.gif']),
                ('config', ['cfg/data.cfg']),
                ('/etc/init.d', ['init-script'])]
    )

'bitmaps'等是这些文件应该去的子目录(相对于sys.prefix)。

但是,这对于标准子目录将取决于系统的跨平台安装来说不是最佳选择。 此外,在开发人员模式下安装包不会将文件放置在安装后它们稍后所在的位置,这使得 finding/using 资源的这个过程最终难以调试/烦人。

我已经研究过 appdirs,但似乎很难在安装过程中使其正常工作,例如如果将用户目录用于数据,这实际上与我的开发环境相关联。

我问这个问题的原因是因为我有一个实现简单 GUI 的小 Python 包,我想随附一个图标。

郑重声明,我可以用 setuptools 处理 setup.py

更新 查看 from @hoefling

data_files 选项指定要为您的包上传的文件。

来自docs

No directory information from files is used to determine the final location of the installed file; only the name of the file is used.

如果要构建跨平台目录路径,请使用 os 模块

import os

path = os.path.join('root', 'directory')

如果您想在有人尝试构建您的包时确定平台,请使用 sys 模块

import sys

current_platform = sys.platform.lower()
is_windows = current_platform.startswith('win')
is_ubuntu =  'ubuntu' in current_platform
is_mac = 'darwin' in current_platform


if is_windows:
     ... # windows specific dayta

elif is_ubuntu:
     ....

else:
    raise Exception('Platform not supported')

正如评论中所建议的那样,对于捆绑资源文件,我宁愿使用 package_data 并将文件放在某个包目录下。示例:

project
├── pkg1
│   ├── __init__.py
│   └── icons
│       └── image.png
└── pkg2
    └── __init__.py

setup.py脚本中打包:

from setuptools import setup


setup(
    ...
    package_data={'pkg1': ['icons/image.png']},
)

在代码中访问资源文件的更新:

Python 3.7 引入了 importlib.resources,它取代了旧的 pkg_resources 功能,并提供利用 pathlib:

的现代资源机制
filepath = importlib_resources.path('pkg1', 'icons/image.png')

对于 Python 3.6 及更早版本,有一个名为 importlib_resources 的向后移植。因此,与版本无关的示例是:

import sys

if sys.version_info >= (3, 7):
    from importlib import resources as importlib_resources
else:
    import importlib_resources

filepath = importlib_resources.path('pkg1', 'icons/image.png')

尽可能使用 importlib_resources 而不是 pkg_resources

原回答,仅供历史参考

要在代码中引用资源文件,请使用pkg_resources:

import pkg_resources

filepath = pkg_resources.resource_filename('pkg1', 'icons/image.png')

因此,跨平台支持由 pkg_resources 处理。可用的资源访问函数参见ResourceManager API