Включить файл с корневого уровня в setup.py

#python #setuptools

#python #setuptools

Вопрос:

Я пытаюсь создать пакет python, используя конвейер bamboo в нашей рабочей среде.

Чтобы запустить сборку, я должен включить файл build.info.txt , содержащий номер версии. Этот файл находится на верхнем уровне в репозитории, поэтому структура репозитория выглядит следующим образом

 build.info.txt
setup.py
MANIFEST.in
README.md
package/
   __init__.py
   file1.py
   file2.py
  

Файл build.info.txt имеет номер версии

 version=x.y.z
  

Я хотел бы использовать этот файл для запуска номера версии, поэтому в __init__.py I включен простой синтаксический анализатор

 from pathlib import Path
path = Path(__file__).absolute().parent / "build.info.txt"
__version__ = open(path).readline()[0].split("=")[-1]
  

Это отлично работает в локальном режиме. Однако, когда я создаю пакет и отправляю его на наш сервер pypi, я получаю следующую ошибку во время выполнения (т. Е. pip install package Работает):

 FileNotFoundError: [Errno 2] No such file or directory: '</PATH/TO/ENVIRONMENT>/python3.8/site-packages/build.info.txt'
  

Я изменил поведение setup.py (я использую setuptools ), включая:

 setup(**other_params, package_data={"": ["../build.info.txt"]}, include_package_data=True)
  

пока MANIFEST.in выглядит так

 include build.info.txt
  

Проблема в том, что build.info.txt using pip install находится на верхнем уровне:

 </PATH/TO/ENVIRONMENT>/python3.8/site-packages/build.info.txt
  

этот файл является общим для нескольких пакетов, в то время как я хотел бы иметь файл в

 </PATH/TO/ENVIRONMENT>/python3.8/site-packages/<PACKAGE>/build.info.txt
  

(затем мне нужно управлять анализатором __init__ , чтобы проанализировать нужный файл, но это просто)

Как я могу это сделать?

Спасибо

Ответ №1:

Моя рекомендация — использовать importlib.metadata для чтения версии проекта.

Была попытка формализовать и стандартизировать соглашение о настройке __version__ в PEP 396, но оно так и не получило полного признания. А также в настоящее время эта привычка исчезает, потому что необходимость в этом больше не так остра, благодаря importlib.metadata . Таким образом, вы можете __version__ полностью удалить и использовать сторонние фрагменты кода, которые хотят знать номер версии вашего приложения или библиотеки importlib.metadata.version('MyProject') , для его чтения.

Если вы настаиваете на том, чтобы иметь __version__ в своей библиотеке, вы можете изменить это и выполнить следующие действия в своем __init__.py :

 __version__ = importlib.metadata.version('MyProject')
  

Asides:

  • Если вы настаиваете на работе с файлом build-info.txt , вы можете создать символическую ссылку на него в пакете, например, как package/build-info.txt (ссылка на build-info.txt ), и __init__.py можете прочитать этот файл во время выполнения.

    • Или, как предложено в комментариях, символическая build-info.txt ссылка на package/build_info.py , и в __init__.py : from build_info import version as __version__ (это предполагает, что содержимое этого файла также является допустимым синтаксисом Python).
  • Вы не должны использовать __file__ для чтения ресурсов данных пакета, это ненадежно, используйте importlib.resources вместо этого (это сделает это гораздо более чистым способом и, при необходимости, позаботится об извлечении файлов в случае архивирования пакета и т. Д.).

  • Существуют инструменты, которые могут решить все эти проблемы с номером версии, setuptools-scm которые приходят на ум и могут соответствовать вашим потребностям.

Комментарии:

1. Другое предложение для «сторон» package/build-info.txt может быть переименовано package/version.py , поэтому строка в __init__.py становится такой же простой, как: from .version import version as __version__ . А затем setup.py автоматически сгенерировать этот файл, используя, например, информацию scm.

2. Чтобы завершить мой предыдущий комментарий, см., Например, numpy setup.py , особенно. функция write_version_py

3. @demi-lune Из того, что я понял из вопроса, имя и местоположение файла являются заданными. Я понял это, поскольку это соглашение из их «бамбуковой» конвейерной среды, и оно не может быть изменено. Возможно, я ошибаюсь (мой ответ также немного вводит в заблуждение, я это исправлю). — Но да, ./setup.py может читать ./build-info.txt и генерировать ./package/version.py , это может сработать.

4. @sinoroc, вы правы: имя и путь исправлены.