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

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

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

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

Скрипт сценария setup.py содержит сценарий выполнения setuptools, который позволяет не только производить сборку, но и установку пакета в формате weel [3.1]. Поэтому, если файл pyproject.toml отсутствует или не определена фоновая служба сборки (build-backend), таже утилита PIP, не говоря уже об buildout, будет искать сценарий setup.py [3.2].

При этом,

2. Использование файла Setup.py

Как уже было сказано выше, setup.py является давно устоявшимся форматом представления дерева исходного кода, который часто используется с setuptools, пример которого показана в листинг 2.1

Листинг 2.1

import io
import os
import re
from setuptools import setup, find_packages
from setuptools.config import read_configuration

def read_config( vkey ): 
    """
    Read given configuration file from root directoty and returns options from 
    it as a dict. 
    """
…
def read(filename, encoding='utf-8'):
    """read file contents"""
…
def get_package_version():
    """get version from top-level package init"""
…
setup(
        name = "shellenv",
        version=get_package_version(),
        url = 'https://github.com/rjaan/python-shellenv.git',
        license = 'PSF',
        description = "You able to operate SHELL's enviroment variables",
        author = 'Andrew Rzhavskov',
        packages = find_packages('shellenv'),
        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"],
)

В листинге 2.1 , приведен фрагмент файла setup.py, обспечивающий процесс сборки и установки модуля python-shellenv, осуществляемый методом setuptools:setup,который принимает для этого [,достяжения этих целей,] методанные в виде списка атрибутов, перечисляемых ниже [3.5], и базируется на основе модуля distutils [3.4].

Атрибут name

Содержит текстовую строку имени пакета.

Атрибут version

Содержит текстовую строку версии пакета, которая извлекается функций get_package_version() из файла setup.cfg или __init__.py, текст как показано в листинге 2.2

Листинг 2.2

...
def get_package_version():
    """get version from top-level package init"""
    version_file = read('src/shellenv/__init__.py')
    version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]",
                              version_file, re.M)
    if version_match:
        return version_match.group(1)

    """if you didn't able to read nothing from top-level package init,
       you should try to get the version from top-level package file setup.cfg 
    """
    version=read_config( 'version' )
    if version == None :
       raise RuntimeError('Unable to find version string.')        
    
    return version
...    

Функция get_package_version(), показанная в листинге 2.2, сначала пытается извлеч текстовую строку с версией пакета из файла __init__.py с использованием функции read_config(), текст которой показан в листинге 2.3

Листинг 2.3

...
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
...

Затем, get_package_version() пытается извлечь версию пакета из опции 'version' файла setup.cfg уже c помощью функции read_config(), текст которой показана в листинге 2.4

Листинг 2.4

def read_config( vkey ): 
    """
    Read given configuration file from root directoty and returns options from 
    it as a dict. 
    """
    conf_dict = read_configuration(os.path.dirname(os.path.abspath(__file__))+'/'+'setup.cfg' )

    return conf_dict.get('metadata')[vkey]

Атрибут url

Содержит текстовую строку с адресом URL на домашнюю страницу с исходным кодом, в данном случае на Git репозитрарий python-shellenv.git во внешнем хранилище на GitHub

Атрибут license

Содержит текстовую строку лицензии под условиями которой распространяется данный пакет. В моем случае, такой является лицензия PSF (Python Software Foundation License).

Лицензия Python Software Foundation License

В данном случае, согласно тексту лецензии, данная лицензия не имеет обязательного заголовка [3.6]. Поэтому предлагаю воспользоваться лицензией от удостоверяющего пакетного центра Python (The Python Packaging Authority), текст которой приведен в листинге 2.5

Листинг 2.5

opyright (c) 2022 Andrew Rzhavskov

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

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

Атрибут description

Содержит текстовую строку с кратким описанием и/или назначением пакета Python

Атрибут author

Содержит текстовую строку c указанием авторства пакета Python

Атрибут packages

Содержит список строковых значений, возвращаемые методом find_packages модуля setooptools find_packages, в единственном аргументе, которой передано имя пакета. Хотя, это можно было не делать, так как в данном случае поддержка сборки и установки нескольких пакетов не используется.

Атрибут package_dir

Содержит словарь с отражаемых имен к реальным названию директорий, где искать содержимое пакета.

Атрибут install_requires

Содержит список текстовых строк с условиями зависимостей от каких версий других пакетов, которые будут установлены из индекса пакетов Python, если они не были установлены ранее.

Атрибут python_requires

Содержит список текстовых строк с условиями зависимостей c какими версиями Python будет совместим пакет

При этом, условия удовлетворения зависимостей устанавливаются согласно PEP-440 [3.10]

Атрибут long_description

Содержит текстовый контекст файла README.md/README.rst, имеющие форматированный текст, в заданной кодировки. Например, в моем случае, ей является широко используемая utf-8, что видно из применяемой получения данного контекста функции read(), показанной в листинге 2.3

Атрибут classifiers

Содержит список из классификаторов, которые категоризируют проект. Полный список приведен в https://pypi.org/classifiers/, а детальные инструкции как провести категоризацию или вернее классификацию проекта, приведены в PEP-301 [3.12].

В моем случае, как показано в листинге 2.1, мной проект python-shellev был отнесен как платформенно независимый, использующий Python версии 3 и распространяемый под лицензией PSF, о которой рассказывал выше в соответствие с классификаторами: "Programming Language :: Python :: 3", "OSI Approved::Python Software Foundation License", "Operating System :: OS Independent".

Атрибут zip_safe

Для максимальной производительности пакеты Python лучше всего устанавливать в формате zip. Однако, не все пакеты могут быть приведены к сжатому виду, формату zip, потому что они могут потребовать доступ либо к файлам исходного кода или данных операционной системы. Поэтому, какой будет выбран вариант установки проекта Python в формате zip-файла, или директории — зависит от того, как был определен флаг zip_file

Так, если флаг zip_file = True, то пакет будет восприниматься в формате файла ZIP, в обратном случае, он будет рассматриваться в качестве директории [3.13]

Атрибут zip_safe

Содержит словарь с опциями по умолчанию передаваемые скриптом setup. В данном случае, как показано в листинге 2.1, опции передаются расширению bdist_wheel, который обеспечивает сборку пакета в формате wheel

Атрибут Platforms

Содержит текстовую строку c указанием используемой платформы. В моем случае, как показано в листинге 2.1, any – платформа независимая.

Атрибут Entry_points

Содержит словарь, с ключевыми словами которого определяется какие точки входа существуют в данном Python-модуле (проекте) [3.16]. Это позволяет обеспечить более дружественный интерфейс вызова в виде одного или нескольких скриптов-оберток Python-модуля чем через команду pip -m <module>

Применяется entry_points согласно следующему правилу, приведенному в листинге 2.6 для проекта python-shellenv [3.17], на выходе сборке которого получается модуль shellenv и скрипт pypi-shellenv

Листинг 2.6

...
from setuptools import setup

entry_points={
            "console_scripts": ["py-shellenv=shellenv.__main__:main"],
},
...

Из которого вырисовывается общее правило:

"console_scripts": ["<name>=<module>.<submodule>:<exec-function>"],;

При этом, в имени <submodule> может быть опущено расширение .py

В заключении

В локальном виртуальном окружении venv-shellenv производим сборку и установку нового модуля, в результате которой получим установленный скрипт-обертку py-shellenv, как показано в дампе 2.7

Дамп 2.7

(venv-shellenv) ~/.../venv-shellenv/src/python-shellenv/$ ../../bin/pip install .
Processing /home/user/Projects/python-venv/venv-shellenv/src/python-shellenv
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
...
Successfully built shellenv
Installing collected packages: shellenv
Successfully installed shellenv-1.5
(venv-shellenv) ~/.../venv-shellenv/src/python-shellenv/$ which py-shellenv
~/.../venv-shellenv/bin/py-shellenv  

Git: add main() in file __main__.py to create wrapper script when package's building and remove unnecessary мodule level "dunders" __author__ and  __copyright__ from __main__.py   

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

3.1 PIP Documention — setup.py (legacy)

3.2 PEP 517 — A build-system independent format for source trees

3.3 Getting Started With setuptools and setup.py

3.4 Setuptool's source code in _init__.py line 73

3.5 Distutils — API Reference

3.6 Python-2.0 licenses

3.7 Setuptools — Package Discovery and Namespace Package

3.8 PyPA — install_requires vs requirements files

3.9 PyPA — Packaging and distributing projects — attribute python-requires

3.10 PEP-440

3.11 PyPA — Packaging and distributing projects — README.rst / README.md

3.12 PEP-301 — Distutils Trove Classification

3.13 The PEAK Developers' Center — Setting the zip_safe flag

3.15 pip wheel

3.16 What Are Python Wheels and Why Should You Care?

3.17 GitHub — Module python-shellenv