Включая файл python из корня проекта в сборку setup.py

Я пытаюсь включить файл python в каталог build/lib, созданный при запуске

python setup.py install

В частности, я хотел бы включить простой файл конфигурации ('definitions.py'), который определяет переменную ROOT_DIR, которая затем используется подпакетами. Файл Definition.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/')

Идея проистекает из этого ответа stackru: /questions/18953761/python-poluchit-put-k-kornevoj-strukture-proekta/18953780#18953780.
Однако этот файл "Definition.py" никогда не появляется в каталоге сборки при запуске "setup.py install".

Вот структура каталогов проекта:

проект
|
Setup── setup.py
|
Definition── definitions.py
|
Package── package1
|   ├── __init__.py
| Config── config.py
|   └── ...
|
Package── package2
|   ├── __init__.py
|   └── ...
└── ...

Мои многочисленные попытки не увенчались успехом (например, попытки, предложенные в /questions/5337544/kak-vklyuchit-staticheskie-fajlyi-v-setuptools-paket-python/5337581#5337581). Насколько я могу судить, это связано с тем, что defines.py находится на верхнем уровне структуры моего проекта (в котором отсутствует файл __init__.py).

Я пытался:

1)... используя переменную package-data в setuptools.setup()

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

но определение.py не отображается в сборке
(Я думаю, потому что defines.py отсутствует в "пакете", в котором есть __init__.py?).

2)... используя файл MANIFEST.in, но это также не работает
(Я думаю, потому что MANIFEST не работает с файлами.py?)

Мой вопрос:
Есть ли способ включить определения.py в каталог сборки?
Или есть ли лучший способ обеспечить доступ к абсолютным путям, созданным из каталога верхнего уровня для нескольких подпакетов?

1 ответ

Решение

Если вы ищете способ доступа к файлу данных, отличному от 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 в комментариях, теперь есть бэкпорт для importlib.resources (который доступен только в Python 3.7 и далее) - 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')

и т.п.

Другие вопросы по тегам