在 setup.py 构建中包含来自项目根目录的 python 文件

including python file from project root in setup.py build

我试图在 运行

时创建的 build/lib 目录中包含一个 python 文件
python setup.py install

特别是,我想包含一个简单的配置文件 ('definitions.py'),它定义了一个 ROOT_DIR 变量,然后由子包使用。 'definitions.py' 文件包含:

import os
ROOT_DIR  = os.path.dirname(os.path.abspath(__file__))

我的目标是让每个子包中的配置文件 ('config.py') 调用 ROOT_DIR 来构建自己的绝对路径:

from definitions import ROOT_DIR
PACKAGE_DIR = os.path.join(ROOT_DIR, 'package1/')

这个想法来自这个 Whosebug 答案:。
但是,当 运行 'setup.py install' 时,这个 'definitions.py' 文件永远不会出现在构建目录中。

项目目录结构如下:

project
|
├── setup.py
|
├── definitions.py
|
├── package1
|   ├── __init__.py
|   ├── config.py
|   └── ...
|
├── package2
|   ├── __init__.py
|   └── ...
└── ...

我的多次尝试都失败了(尝试,例如 中提供的建议)。据我所知,这是因为 definitions.py 位于我的项目结构的顶层(缺少 __init__.py 文件)。

我试过了:

1) ...在 setuptools.setup() 中使用 'package-data' 变量

package_data={'package': ['./definitions.py']}

但 definitions.py 没有出现在构建
中(我认为是因为 definitions.py 不在具有 __init__.py?)。

2) ...使用 MANIFEST.in 文件,但这也不起作用
(我认为是因为 MANIFEST 不适用于 .py 文件?)

我的问题:
有没有办法在构建目录中包含 definitions.py?
或者,有没有更好的方法可以访问从顶级目录构建的多个子包的绝对路径?

如果您正在寻找一种方法来访问已安装模块中的非 python 数据文件,就像您链接的问题一样(顶级包中的配置文件应该可以访问在子包中),使用 pkg_resources 机制而不是发明自定义路径解析。示例项目结构:

project
├── setup.py
└── root
    ├── __init__.py
    ├── config.txt
    ├── sub1
    │   └── __init__.py
    └── sub2
        └── __init__.py

setup.py:

from setuptools import setup

setup(
    name='myproj',
    ...,
    packages=['root', 'root.sub1', 'root.sub2'],  # or setuptools.find_packages()
    package_data={'root': ['config.txt']}
)

更新:

正如 wim in the comments, there's now a backport for importlib.resources (which is only available in Python 3.7 and onwards) - importlib_resources 所指出的,它提供了一种利用 pathlib:

的现代资源机器
# access the filepath
importlib_resources.path('root', 'config.txt')

# access the contents as string
importlib_resources.read_text('root', 'config.txt')

# access the contents as file-like object
importlib_resources.open_binary('root', 'config.txt')

原回答

使用 pkg_resources,您可以从包的任何位置访问 root/config.txt,而无需执行任何路径解析:

import pkg_resources

# access the filepath:
filepath = pkg_resources.resource_filename('root', 'config.txt')

# access the contents as string:
contents = pkg_resources.resource_string('root', 'config.txt')

# access the contents as file-like object:
contents = pkg_resources.resource_stream('root', 'config.txt')

等等