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

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

Проблема и решение

1. Суть проблемы

Во время разворачивания Python-3.8 из исходных кодов [3.1], поимел показанную в дампе 1.1 проблему установки пакетов, которые позволяют расширать возможности бинарного интерпретатора CPython

Основная проблема использования toolsetup является вроде бы в невинном предупреждении во время python3.8 setup.py install, показанным в дампе 1.1

Дамп 1.1

$ python3.8 setup.py install
...
/home/user/.sources/Python-3.8.13/build/python-setuptools/setuptools/command/easy_install.py:144: EasyInstallDeprecationWarning: easy_install command is deprecated. Use build and pip and other standards-based tools.
...

Так давайте по порядку — где находится суть загвоздки?

Для этого, сначала мне потребовалось развернуть Python-3.8 следующим образом, как показано в дампе 1.2

Дамп 1.2

~$ mkdir .sources && cd .sources 
~/.sources$ sudo apt update
…
~/.sources$ sudo apt build-dep python3.8
~/.sources$ sudo apt upgrade
~/.sources$ wget -c \
https://www.python.org/ftp/python/3.8.13/Python-3.8.13.tgz && \
tar xzf Python-3.8.13.tgz && \
cd Python-3.8.13
~/.sources/Python-3.8.13$ ./configure —prefix=$HOME/.local/share/python-3.8
~/.sources/Python-3.8.13$ make -j8
~/.sources/Python-3.8.13$ make install
…
Installing collected packages: setuptools, pip
  WARNING: The scripts pip3 and pip3.8 are installed in '/home/user/.local/share/python-3.8/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed pip-22.0.4 setuptools-56.0.0

При этом, как показано в дампе 1.2 обращаем внимание на вроде бы уже установленной версии setuptools-56.0.0, как показано в дампе 1.4

Дамп 1.3

$ python3.8 -m pip list
Package    Version
---------- -------
build      0.8.0
packaging  21.3
pep517     0.12.0
pip        22.0.4
pyparsing  3.0.9
setuptools 56.0.0
tomli      2.0.1

добавить путь $HOME/.sources/Python-3.8.13/.local/share/python-3.8/bin к PATH файла ~/.profile, как показано в дампе 1.4

Дамп 1.4

...

# set PATH so it includes user's private .local/share/python-3.8/bin if it exists
if [ -d "$HOME/.local/share/python-3.8/bin" ] ; then
   PATH="$HOME/.local/share/python-3.8/bin:$PATH"
fi
...

или выполнить просто экспорт переменной окружении PATH на время выполнения сеанса пользователя, как показано в дампе 1.5

Дамп 1.5


~$ export PATH=$HOME/.local/share/python-3.8/bin:$PATH

После чего нужно стянуть последнюю версию пакетов python-build и python-setuptools, как показано в дампе 1.6

Дамп 1.5

~/.sources/Python-3.8.13/build$ git clone https://github.com/pypa/build.git python-build && cd python-build
...
~/.sources/Python-3.8.13/build/python-build$ cd ..
~/.sources/Python-3.8.13/build$ git clone https://github.com/pypa/setuptools.git python-setuptools && cd python-setuptool
...

И была выполнена успешна команда облегченной установки, как показано в дампе 1.6

Дамп 1.6

python3.8 setup.py install
...
/home/user/.sources/Python-3.8.13/build/python-setuptools/setuptools/command/easy_install.py:144: EasyInstallDeprecationWarning: easy_install command is deprecated. Use build and pip and other standards-based tools.
...

из которого видно, что установка сопровождалась предупреждением easy_install command is deprecated..., что станет в будущем несомненно проблемой.

Потому что начиная с версии setuptools-42.0 скрипта easy_install запрещена, а формат дистрибьюции egg больше не поддерживается, вместо последнего стоит воспользоватся wheel (файлы с расширением .whl) или обычной дистрибьюцей (файлы с расширением .tar.gz). Соответственно, что они устанавливаются с помощью модуля pip, который требует чтобы эти пакеты были собраны в определенных форматах . Поэтому нужно понимать как и что использовать вместо python setup.py install, а именно:

Дамп 1.7

[build-system]
# Minimum requirements for the build system to execute.
requires = ["setuptools", "wheel"]  # PEP 508 specifications.

Кроме того, нужно затвердить, что проект вашего программного обеспечения в Python не всегда равно пакету, потому что последний — это голая дистрибьюция, которая прежде всего содержит модули и порождает скрипты запуска этих модулей, если они были заданы в проекте до начала сборки.

Также в конце коснусь вопроса почему была запрещена read_configuration из setuptools.config и что использовать вместо неё.

2. Решение

2.1 Использование формата wheel

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

Дамп 2.1.1


python -m pip install {proto://}path/to/location/zip-archieve-file.whl

Где

Дамп 2.1.2


{distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl

Где

2.2 Создание дистрибутива в формате Wheel

Производится с использованием setup.py командой, формат которой показан в дампе 2.2.1

Дамп 2.2.1

python-shellenv-1.6$ python setup.py bdist_wheel
running bdist_wheel
running build
running build_py
package init file 'src/__init__.py' not found (or not a regular file)
running egg_info
writing shellenv.egg-info/PKG-INFO
writing dependency_links to shellenv.egg-info/dependency_links.txt
writing entry points to shellenv.egg-info/entry_points.txt
writing requirements to shellenv.egg-info/requires.txt
writing top-level names to shellenv.egg-info/top_level.txt
adding license file 'LICENSE' (matched pattern 'LICEN[CS]E*')
reading manifest file 'shellenv.egg-info/SOURCES.txt'
writing manifest file 'shellenv.egg-info/SOURCES.txt'
installing to build/bdist.linux-x86_64/wheel
running install
running install_lib
warning: install_lib: 'build/lib' does not exist -- no Python modules to install

running install_egg_info
Copying shellenv.egg-info to build/bdist.linux-x86_64/wheel/shellenv-1.7-py3.8.egg-info
running install_scripts
adding license file "LICENSE" (matched pattern "LICEN[CS]E*")
creating build/bdist.linux-x86_64/wheel/shellenv-1.7.dist-info/WHEEL
creating 'dist/shellenv-1.7-py2.py3-none-any.whl' and adding 'build/bdist.linux-x86_64/wheel' to it
adding 'shellenv-1.7.dist-info/LICENSE'
adding 'shellenv-1.7.dist-info/METADATA'
adding 'shellenv-1.7.dist-info/WHEEL'
adding 'shellenv-1.7.dist-info/entry_points.txt'
adding 'shellenv-1.7.dist-info/top_level.txt'
adding 'shellenv-1.7.dist-info/zip-safe'
adding 'shellenv-1.7.dist-info/RECORD'
removing build/bdist.linux-x86_64/wheel

При этом, как показано в дампе 2.2.2, в директории dist/ будет находится соответствующий формату собранный пакет Wheel файл с расширением .whl

Дамп 2.2.2

python-shellenv-1.6$ ls dist
shellenv-1.6-py2.py3-none-any.whl

python-shellenv-1.6$  python3 -m pip install dist/shellenv-1.7-py2.py3-none-any.whl
Processing ./dist/shellenv-1.7-py2.py3-none-any.whl
Requirement already satisfied: setuptools>=42 in /home/user/.local/share/python-3.8/lib/python3.8/site-packages (from shellenv==1.7) (56.0.0)
Requirement already satisfied: python-dotenv>=0.19 in /home/user/.local/share/python-3.8/lib/python3.8/site-packages (from shellenv==1.7) (0.20.0)
Installing collected packages: shellenv
  Attempting uninstall: shellenv
    Found existing installation: shellenv 1.6
    Uninstalling shellenv-1.6:
      Successfully uninstalled shellenv-1.6
Successfully installed shellenv-1.7

python-shellenv-1.6$  python3 -m pip list
Package       Version
------------- -------
...
python-dotenv 0.20.0
setuptools    56.0.0
shellenv      1.7
...
wheel         0.37.1

Эти атрибуты были рассмотрены мной более подробно в использовании setup.py

Поэтому быстро, атрибут bdist_wheel устанавливает универсальный формат wheel c помощью {"bdist_wheel": {"universal": True}} и используется вместе с комнадой python setup.py bdist_wheel

Атрибут zip_safe установлен к True, чтобы устанавливать пакет как zip-файл. В то время как более популярным является установка zip_safe к False, чтобы устанавливать все в отдельную директорию.

При выполнении команды python3 setup.py bdist_wheel может возникать ошибка, которая показана в дампе 2.2.3

Дамп 2.2.3

python-shellenv$ python3 setup.py bdist_wheel
usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
   or: setup.py --help [cmd1 cmd2 ...]
   or: setup.py --help-commands
   or: setup.py cmd --help

error: invalid command 'bdist_wheel'

Что решается установкой пакета wheel командой python3 -m pip install

2.3 Унифицированное решение для получение версии и содержимого пакета

Функция read_configuration из setuptools.config запрещена для использования, поэтому начиная с апреля 2020 года рекомендуется использовать pyproject.toml взамен setup.cfg . На самом деле, причиной этого стало желание избежать проблем связанных с использованием формата .ini-файлов в setup.cfg, которые вносят некоторые проблемы, связанные в первую очередь с лексическим разбором, а также возможность разночтения, в виду дублирования информации в setup.py [3.3]

Поэтому чтение версии берется из глобальной переменной модуля __version__, прописанной в файле __init__.py вместе с __copyright__, как показано в дампе 2.3.1

Дамп 2.3.1

...
__author__      = "Author: Andrew Rzhaskov"
__copyright__   = "Copyright: 2022, Russia Moscow"
__version__      = "1.7"  
...

Поэтому в setup.py нужно прописать пару функций, которые читают заключенное в двойных/одинарных скобках значение версии из __init__.py, как показано в дампе 2.3.2

Дамп 2.3.2

...
def read(filename, encoding='utf-8'):
    """read file contents"""
    full_path = os.path.join(os.path.dirname(__file__), filename)
    with io.open(full_path, encoding=encoding) as fh:
        contents = fh.read().strip()
    return contents

def get_version(rel_path):
    for line in read().splitlines():
        if line.startswith('__version__'):
            delim = '"' if '"' in line else "'"
            return line.split(delim)[1]
    else:
        raise RuntimeError("Unable to find version string.")
 ...

setup( 
          ...
          version=get_version('src/shellenv/__init__.py'),
          ...
          
          include_package_data = False,
          packages=find_packages(where='src', exclude=["shellenv-tools"]),
      package_dir={
        '': 'src',
      },
          ... 
)

В данном случае, явно прописывается на каком уровне файловой системы, директории src/ находится пакета 'shellenv' в дереве проекта python-shellenv, в который содержат дополнительный пакет именем shellenv-tools, как показано в дереве дампа 2.3.3

Дамп 2.3.3

.
├── buildout.cfg
├── LICENSE
├── pyproject.toml
├── README.md
├── setup.cfg
├── setup.py
└── src
   ├── shellenv-tools
   │  ├── __init__.py
   │  └── __main__.py
   └── shellenv
      ├── __init__.py
      ├── __main__.py
      ├── cmdlineargs.py
      ├── shellenv.py
      └── testrun.py

Которое имеет файлы __init__.py, но пока в настоящей версии, начиная с shellenv-1.7, раздаваемый файл пакета в формате wheel будет собираться только для shellenv

Поэтому в find_packages() используется дополнительный атрибут exclude=, чтобы исключить возникновение ошибки, как показано в дампе 2.3.4

Дамп 2.3.4

$ python3 setup.py bdist_wheel
running bdist_wheel
running build
running build_py
error: package directory 'shellenv-tools' does not exist

При этом include_package_data = False, так как данные отдельно не подключаются в данном проекте при сборки дистрибутива, включающего модуль shellenv [3.6]

Кроме того, можно еще попробовать использовать файл MANIFEST.in [3.8], который позволяет игнорировать один или несколько файлов, но также указать какие файлы нужно включать в проект, например, как показано в дампе 2.3.5

Дамп 2.3.4

include AUTHORS
include LICENSE
include README.md

exclude .git
exclude .travis.yml

recursive include doc  *
recursive exclude test *

global exclude __pycache__ *.pyc

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

3.1 Setuptools is removing easy_install, deprecation warning in 42.0.0 #493

3.2 PEP 491 – The Wheel Binary Package Format 1.9

3.3 StackOverflow.Com – Is `setup.cfg` deprecated?

3.4 Single-sourcing the package version

3.5 StackOverflow.Com – What is "where" argument for in setuptools.find_packages?

3.6 Setuptools – Data Files Support

3.7 Setuptools – Understanding the zip_safe flag

3.8 StackOverflow.Com – Is it possible to exclude certain files when building a wheel with setup.py?

3.9 PEP 491

3.10 PEP 517

3.11 PEP 518

Сайт разработан в соответствии с рекомендациями консорциума W3C для языка разметки HTML5.

Об авторе можно прочитать здесь.

Copyright © 2015-2019 Андрей Ржавсков