× К оглавлению На главную Об авторе

Дата и время публикации:    

Назначение и использование

1. Назначение

1.1 Что такое формат egg в Python

Логическая структура, которая отвечает реализацию определенной версии проекта Python, включающей в себя собственно код, ресурсы и метаданные. Существует несколько форматов, которые могут быть использованы для фактического представления Python и могут быть развиты самостоятельно.

Несмотря на большую полигамию, существуют два основных формата, реализующие накатывания отдельных дистрибутивов на базе проекта Python, которые с иронией стали называть яйца Python (Python egg), из которых получается знатная яичница в виде собранного и готового к дистрибьюции пакета Python:

При этом, так как собираюсь рассказывать о buildout, реализуемый Python-модулем zc.buildout, углубляться в тонкости использования форматов Python egg не буду, потому что эти форматы выбраны в нем основными [3.2].

1.2 Python-модуль zc.buildout

Реализует автоматическую сборку и тестирование собираемого программного обеспечения на всех этапах от разработки до момента выпуска версии программного продукта. При этом buidout основывается на принципах автоматизации процесса и неизменности воспроизведения [3.3]. Последняя подразумевает неизменность результата на повторных циклах сборки и тестирования для одной и той же конфигурации buidout в том же самом окружении.

2. Использование

2.1 Настройка и установка buildout

Как всегда, произвел зеркалирование репозитария Git в своем локальном хранилище [3.5] проекта свободно-распространяемого исходного кода zc.buildout [3.4], как показано в дампе 2.1.1

Дамп 2.1.1

$ git clone https://github.com/buildout/buildout.git python-buildout
Клонирование в «python-buildout.git»…
remote: Enumerating objects: 13610, done.
remote: Counting objects: 100% (438/438), done.
remote: Compressing objects: 100% (241/241), done.
remote: Total 13610 (delta 217), reused 310 (delta 141), pack-reused 13172
Получение объектов: 100% (13610/13610), 4.28 MiB | 7.56 MiB/s, готово.
Определение изменений: 100% (6697/6697), готово.
...
$ sudo -u git git init --bare /home/git/repos/python-buildout.git 
...
git remote set-url origin git://localhost/python-buildout.git
...
$ git push --mirror
Перечисление объектов: 13610, готово.
Подсчет объектов: 100% (13610/13610), готово.
При сжатии изменений используется до 8 потоков
Сжатие объектов: 100% (5500/5500), готово.
Запись объектов: 100% (13610/13610), 4.28 MiB | 230.47 MiB/s, готово.
Total 13610 (delta 6697), reused 13610 (delta 6697), pack-reused 0
remote: Resolving deltas: 100% (6697/6697), done.
To git://localhost/python-buildout.git
* [new branch]      master -> master
...

Затем, выполнил и разместил пакет в индексном репозитарии Python — все операции показаны в дампе 2.1.2

Дамп 2.1.2

$ python3 -m build
…
Successfully built zc.buildout-3.0.0rc3.dev0.tar.gz and zc.buildout-3.0.0rc3.dev0-py2.py3-none-any.whl
$ sudo -u git mkdir /home/git/pypisrv/zc.buildout
…
$ sudo install -m 0644 -o git -g git dist/zc.buildout-*-none-any.whl /home/git/pypisrv/zc.buildout
$ sudo install -m 0644 -o git -g git dist/zc.buildout-*.tar.gz /home/git/pypisrv/zc.buildout
…
$ pip install --upgrade -U zc.buildout --extra-index-url http://localhost:8080/simple 
…
Installing collected packages: setuptools, zc.buildout
  Attempting uninstall: setuptools
    Found existing installation: setuptools 60.10.0.post20220318
    Uninstalling setuptools-60.10.0.post20220318:
      Successfully uninstalled setuptools-60.10.0.post20220318
Successfully installed setuptools-51.3.3 zc.buildout-2.13.6

При этом, рекомендую воспользоваться опцией --upgrade, которая позволяет устанавливать (обновлять) ранее установленные версии buildout. Так же возможно, в моем случае это было так, производит автоматическое разрешение версий зависимостей (других пакетов) к требуемым, как показано в дампе 2.1.2

2.2 Настройка и установка виртуального окружения CPython

Далее, рекомендуется настроить виртуальное окружение с использованием virtualenv [3.6]. Для чего, проводим такую же процедуру сохранения и публикацию проекта модуля virtualenv в хранилищах, как показано в дампе 2.2.1

Дамп 2.2.1

$ git clone https://github.com/pypa/virtualenv.git python-virtualenv
…
$ sudo -u git git init --bare /home/git/repos/python-virtualenv.git
…
$ git remote set-url origin git://localhost/python-virtualenv.git
$ git push --mirror 
…
$ python3 -m build
…
Successfully built virtualenv-20.13.4.dev4+g63c94af.tar.gz and virtualenv-20.13.4.dev4+g63c94af-py2.py3-none-any.whl
…
$ sudo install -m 0755 -o git -g git -d /home/git/pypisrv/virtualenv
$ sudo install -m 0644 -o git -g git dist/virtualenv-*-none-any.whl /home/git/pypisrv/virtualenv
$ sudo install -m 0644 -o git -g git dist/virtualenv-*.tar.gz /home/git/pypisrv/virtualenv
$ pip install --upgrade -U virtualenv --extra-index-url http://localhost:8080/simple 
…
Requirement already satisfied: six<2,>=1.9.0 in /usr/lib/python3/dist-packages (from virtualenv) (1.16.0)
Installing collected packages: distlib, platformdirs, filelock, virtualenv
Successfully installed distlib-0.3.4 filelock-3.6.0 platformdirs-2.5.1 virtualenv-20.13.4

После чего, можно приступить к настройки виртуального окружения, потому что начиная с версии 2.0 установленный zc.buildout больше не поддерживает изоляцию окружения сборки [3.7]. Поэтому один раз создаем виртуальное окружение, как показано в дампе 2.2.2

Дамп 2.2.2

$ mkdir -p ~/Projects/python-venv/ && cd ~/Projects/python-venv/
$ pip freeze > requirements.txt 
$ pip freeze -q -r requirements.txt | sed '/freeze/,$ d' > requirements-froze.txt
$ mv requirements-froze.txt requirements.txt

При этом будте готовы поломать голову и не терять время, чтобы устранить битые зависимости из requirements.txt, например — отсутствующий Brlapi, если задумаете использовать pip freeze для этого. Поэтому рекомендую следующий рецепт, чтобы создать локальное окружение CPython, изолированное от глобального, как показано в дампе 2.2.3

Дамп 2.2.3

$ virtualenv -p python3 venv
created virtual environment CPython3.9.2.final.0-64 in 485ms
  creator CPython3Posix(dest=/home/user/Projects/python-venv/venv, clear=False, no_vcs_ignore=False, global=False)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/home/user/.local/share/virtualenv)
    added seed packages: pip==22.0.4, setuptools==60.10.0, wheel==0.37.1
  activators BashActivator,CshellActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator
...
$ . venv/bin/activate
(venv) $ pip install --upgrade -U zc-buildout --extra-index-url http://localhost:8080/simple

При этом нужно помнить, что часто приводимая в некоторых источниках опция --no-site-packages в версии virtualenv-20 и выше была удалена и больше не используется [3.11]. Так же, как вариант, только что созданное окружение может быть создано и использовано, как показано в дампе 2.2.4

Дамп 2.2.4

$ virtualenv -p python3 venv-shellenv
$ cd venv-shellenv
$ bin/pip install --upgrade -U zc-buildout --extra-index-url http://localhost:8080/simple
$ mkdir src && cd src && git clone http://localhost/python-shellenv.git -b v1.4

Недостатком использования локального виртуального окружения СPython является в постоянном контроле за тем , что какими инструментальными средствами из глобального или только что созданного виртуального окружения. Даже несмотря на то, что была выполнена команда `source bin/activate`, а командная строка начинается с имени корневой директории, где на ходится это окружение, как показано в дампе 2.2.5

Дамп 2.2.5

user@myhost:~/Projects/python-venv/venv-shellenv$ source bin/activate
(venv-shellenv) user@home2:~/Projects/python-venv/venv-shellenv$

2.3 Методанные запуска и инициализации Buildout

Реализуются с помощью команды `buildout bootstrap` и требует наличие файла buildout.cfg, который можно сгнерировать с помощью команды buildout init и как показано в дампе 2.3.1

Дамп 2.3.1

(venv-shellenv) ~/.../src/python-shellenv/$ ../../bin/buildout init
Creating '/home/user/Projects/python-venv/venv-shellenv/src/python-shellenv/buildout.cfg'.
Creating directory '~/.../src/python-shellenv/eggs'.
Creating directory '~/.../src/python-shellenv/bin'.
Creating directory '~/.../src/python-shellenv/parts'.
Creating directory '~/.../src/python-shellenv/develop-eggs'.
Generated script '~/.../src/python-shellenv/bin/buildout'.

В результате в корне будут сформированы дополнительные файлы и директории/, которые показаны в дампе 2.3.2 в качестве неотслеживаемых и добавленные мной в файл .gitignore

Дамп 2.3.2

(venv-shellenv) ~/.../src/python-shellenv/$ git status
...
Неотслеживаемые файлы:
  (используйте «git add <файл>…», чтобы добавить в то, что будет включено в коммит)
	bin/
	buildout.cfg
	develop-eggs/
       parts/
       eggs/

Кроме файла buildout.cfg , который имеет секцию [buildout] и пустой список частей, именуемый "parts" и содержащий отдельные часть, которые будем добавлять по ходу пьесы [3.13]. Файл получаемый после выполнения команды buildout init показан в дампе 2.3.3

Дамп 2.3.2

~/.../src/python-shellenv/$ cat      
$ cat buildout.cfg
[buildout]
parts =     
...

Каждая часть в списке "parts" ассоциируется с рецептом (recipe), который делает свою часть работы по выкатыванию яйца (egg), например

Так, в моем случае, использование zc.recipe.egg и git-recipe позволит удовлетворять зависимости, которые указаны в файле pyproject.toml опции "requires=" секции, где кроме отвечающих за сборку проекта модулей еще указана зависимость от модуля python-dotenv, поэтому, если нужно прописать загрузку и установку этого модуля в отдельных частях, как показано в дамп 2.3.3

Дамп 2.3.3

[buildout]
parts =
      git-dotenv
      dotenv

[git-dotenv]
recipe = git-recipe
repository = git://localhost/python-dotenv.git
ref = origin/master
download-directory = ${buildout:directory}/parts/

[dotenv]
recipe = zc.recipe.egg
eggs = python-dotenv               
...

В результате, должно получится что-то подобное, как показано в дампе 2.3.4

Дамп 2.3.4

(venv-shellenv) ~/.../src/python-shellenv/$ ../../bin/buildout -c buildout.cfg
Getting distribution for 'git-recipe'.
Got git-recipe 0.2.7.
Getting distribution for 'zc.recipe.egg>=2.0.6'.
Got zc.recipe.egg 2.0.7.
Uninstalling git-dotenv.
Installing git-dotenv.
Updating dotenv.
Getting distribution for 'python-dotenv'.
Got python-dotenv 0.19.2.

2.4 Директории используемые или автоматически создаваемые buildout

Директория bin/

Содержит различные выполняемые файлы, включая команду buildout и скрипты управления экземплярами, например, пакета 'python-dotenv';

Директория eggs/

Содержит файлы и директории в формате eggs, которые будут загружены buildout, что будет неявно активировано скриптом управления экземпляром в директории bin/;

Директория downloads/

Содержит код и данные, управляемые buildout. В моем случае, это закаченный из локального репозитария пакета 'python-dotenv'

Директория var/

Содержит дополнительно импортируемые экземпляры модулей, журналирование действий, например, по запуску и управления баз данных, сервисом и служб [3.17]

При этом,

${buildout:directory} — корневая (рабочая) директория, в корне которой запускается buildout и расширяемая до абсолютного пути, как показано в дампе 2.3.4

${bin-buildout:directory} — директория bin/ и расширяемая до полного пути относительно корневая (рабочая) директория buildout

Таким образом, после выполнения buildout модуль python-shellenv приобритет вид и вышеперечисленные директории, как показано в дампе 2.4.1

Дамп 2.4.1

$ exa --tree --ignore-glob="*~|__pycache__|dist|*.egg-info" -L1 --sort=type
.
├── bin/
├── develop-eggs/
├── eggs/
├── parts/
├── src/
├── LICENSE
├── README.md
├── buildout.cfg
├── pyproject.toml
└── setup.cfg

2.5 Совместное использование с модулем setuptools

Для сборки пакета 'python-build' с использованием локального virtualenv и построение копии в формате python egg c помощью buildout, мне понадобилось добавить setup.py на ряду с buildout.cfg [3.18] в корень проекта. Поэтому мне пришлось добавить в проект python-shellenv файл setup.py, почему?

Потому что после того, как мной были добавлены опции 'develop=' и 'egg=' в секцию [buildout], как показано в листинге 2.5.1, запуск buildout в моем локальном окружении был завершен с ошибкой, что setup.py не был найден.

Листинг 2.5.1

[buildout]
parts =
      git-dotenv
      dotenv
      python
develop = .
eggs = shellenv

[git-dotenv]
recipe = git-recipe
repository = git://localhost/python-dotenv.git
ref = origin/master
# download-directory = ${buildout:directory}/parts/

[dotenv]
recipe = zc.recipe.egg
eggs = python-dotenv               

[python]
recipe = zc.recipe.egg
interpreter = python
eggs = ${buildout:eggs}

Файл setup.py не был найден отображается ошибкой, как показано в дампе 2.5.2

Дамп 2.5.2

(venv-shellenv) ~/.../src/python-shellenv/$ ../../bin/buildout
Develop: '${HOME}/.../venv-shellenv/src/python-shellenv/.'
Traceback (most recent call last):
  File "/tmp/tmphg8bxny1", line 13, in 
    with open('${HOME}/.../venv-shellenv/src/python-shellenv/./setup.py') as f:
FileNotFoundError: [Errno 2] No such file or directory: '${HOME}/.../venv-shellenv/src/python-shellenv/./setup.py'
...

Поэтому мной был написан дублирующий setup.cfg скрипт setup.py, фрагмент которого приведен в листинге 2.5.3

Листинг 2.5.3

from setuptools.config import read_configuration
...
setup(
        name = "shellenv",
        version=get_package_version(),
        url = 'https://github.com/rjaan/python-shellenv.git',
        license = 'PSF',
        description = "print SHELL's enviroment variables on standard output",
        author = 'Andrey Rzhavskov',
        packages = find_packages(),
        package_dir = {'': 'src'},
        install_requires = [ 'setuptools>=42', 'python-dotenv>=0.19' ],
        python_requires  = '>=3.8',
        long_description=read('README.md'),
        classifiers=[
            "Programming Language :: Python :: 3",
            "OSI Approved::Python Software Foundation License",
            "Operating System :: OS Independent"
            # Get strings from
            # http://pypi.python.org/pypi?%3Aaction=list_classifiers
            ],
        zip_safe=True,
        options={"bdist_wheel": {"universal": True}},
        platforms=["any"],
)

Результат выполнения buildout показан в дампе 2.5.4

Дамп 2.5.4

../../bin/buildout -c buildout.cfg
Creating directory '/home/user/Projects/python-venv/venv-shellenv/src/python-shellenv/eggs'.
Creating directory '/home/user/Projects/python-venv/venv-shellenv/src/python-shellenv/bin'.
Creating directory '/home/user/Projects/python-venv/venv-shellenv/src/python-shellenv/parts'.
Creating directory '/home/user/Projects/python-venv/venv-shellenv/src/python-shellenv/develop-eggs'.
Develop: '/home/user/Projects/python-venv/venv-shellenv/src/python-shellenv/.'
Getting distribution for 'git-recipe'.
Got git-recipe 0.2.7.
Getting distribution for 'zc.recipe.egg>=2.0.6'.
Got zc.recipe.egg 2.0.7.
Uninstalling python.
Uninstalling dotenv.
Uninstalling git-dotenv.
Installing git-dotenv.
Installing dotenv.
Generated script '/home/user/Projects/python-venv/venv-shellenv/src/python-shellenv/bin/dotenv'.
Installing python.
Generated interpreter '/home/user/Projects/python-venv/venv-shellenv/src/python-shellenv/bin/python'.

3. Библиография

3.1 Buildout 1.2.1 documentation — Buildout Tutorial

3.2 Buildout's Getting started — egg

3.3 Buildout's Getting started

3.4 Buildout's source code

3.5 Git to deploy own git server

3.6 virtualenv's source code

3.7 Buildout & virtualenv

3.8 How to create python development environment virtualenv using setup

3.10 virtualenv n site packages pip 1842

3.11 virtualenv-virtualenvwrapper virtualenv error unrecognized arguments no sit

3.12 What is setup.py

3.13 Plane — Understanding buildout.cfg the-zope2-section

3.14 Python's package zc.recipe.macro

3.15 Python's package git-recipe

3.17 Plone — Creating a buildout for your project

3.18 whats a minimal buildout cfg file for a python package

3.19 Setuptools

3.20 dep_license — README.md