Создание python-пакетов (aka setup scripts)
Одна из действительно полезных вещей в python — это система скриптов установки. Любой, серьезно увлекающийся python-программированием разработчик рано или поздно сталкивается с ней. Но из-за гибкости инструментария скриптов установки, их документация весьма раздута. На текущий момент имеется набор утилит (setuptools, distutils, distribute) выполняющих одинаковые задачи.
В данной статье я на конкретных примерах покажу как создать и настроить простой python-пакет.
Наш проект будет иметь следующую функциональность:
- Метод возвращающий строку: «Hello World!»;
- Команда helloworld печатающая эту строку в стандартный вывод.
Создаем структуру проекта
Для начала создадим директорию для пакета. Ее минимальный набор файлов состоит из: файла дистрибьюции ( setup.py ) описывающего метаданные и python кода проекта (в нашем случае модуля helloworld).
Также, xорошим тоном считается создание в корне директории файла с описанием проекта: README.txt .
Получаем следующую структуру:
helloworld-project ├── helloworld │ ├── __init__.py │ └── core.py ├── setup.py └── README.txt
Наша корневая директория helloworld-project будет содержать мета-данные пакета и вспомогательные файлы (тесты, лицензию, документацию и т.д.), а поддиректория helloworld непосредственно сам модуль helloworld .
Теперь отредактируем файл: helloworld/core.py и добавим логику нашего приложения (получение и вывод строки «Hello World!»):
def get_message(): return "Hello World!" def print_message(): print get_message()
Редактируем мета-информацию (setup.py)
Заполним файл описания README.rst :
Description =========== An example Hello World project.
Теперь отредактируем файл setup.py :
from setuptools import setup, find_packages from os.path import join, dirname setup( name='helloworld', version='1.0', packages=find_packages(), long_description=open(join(dirname(__file__), 'README.txt')).read(), )
Убедитесь, что в вашей системе доступны setuptools, в противном случае установите python-пакет distribute
Этих операций достаточно, чтобы собрать пакет дистрибьюции. Выполните команду сборки:
$ python setup.py sdist
В случае успеха вы получите файл: dist/helloworld-1.0.tar.gz . Это полноценный, архивированный python-пакет и вы можете распространять его среди прочих разработчиков.
Виртуальное окружение
Virtualenv — пакет применяемый для создания изолированного python-окружения. Используем его для тестирования нашего проекта.
Создадим окружение env:
$ virtualenv env
Команда создаст директорию env внутри нашего проекта и установит туда python, pip и distribute. Произведем в него установку нашего проекта.
$ ./env/bin/python setup.py install running install running bdist_egg running egg_info [. ] Processing dependencies for helloworld==1.0 Finished processing dependencies for helloworld==1.0
И протестируем его работоспособность:
$ ./env/bin/python >>> import helloworld.core as hw >>> hw.get_message() 'Hello World!' >>> hw.print_message() Hello World!
Все работает. Осталось добавить поддержку команды helloworld в консоли.
Создание команд
Для создания команды helloworld изменим файл setup.py :
setup( . entry_points= 'console_scripts': ['helloworld = helloworld.core:print_message'] > )
В параметре entry_points мы задаем словарь с «точками вызова» нашего приложения. Ключ console_scripts задает список создаваемых исполняемых скриптов (в Windows это будут exe-файлы). В данном случае мы указали создание исполняемого скрипта helloworld при вызове которого будет запускаться метод print_message из модуля helloworld.core.
Переустановим модуль в наше окружение и проверим работу созданного скрипта (для этого прийдется активировать наше окружение):
$ ./env/bin/python setup.py install $ source ./env/bin/activate (env) $ helloworld Hello World! (env)
Похоже все работает.
Работа с версиями
Номер версии важная часть любого проекта. От него зависит обновление пакетов и разрешение зависимостей. В примере выше мы указали номер версии 1.0 в файле setup.py . Более правильное решение перенести его в файл helloworld/__init__.py чтобы сделать доступным в python-коде. По существующим соглашения для хранения номера версии в модуле, используется переменная __version__.
__version__ = '1.0'
Изменим файл setup.py , чтобы нам не приходилось редактировать номер версии в двух местах:
. import helloworld setup( name='helloworld', version=helloworld.__version__, .
Существует множество систем наименования версий в python обычно рекомендуется использовать PEP386. Можно представить, что обозначение версии состоит из номера мажорного, минорного релизов (номера багфикса при необходимости), разделенных точками. В последней части версии разрешается использовать буквы латинского алфавита. Примеры из официальной документации:
0.4 0.4.0 (these two are equivalent) 0.4.1 0.5a1 0.5b3 0.5 0.9.6 1.0 1.0.4a3 1.0.4b1 1.0.4
Управление зависимостями
Добавим функциональности нашему проекту. Создадим команду serve которая будет запускать вебсервер отдающий страницу со строкой «Hello world!» генерируемой нашим модулем. Для этого воспользуемся пакетом Flask.
Добавляем файл helloworld/web.py :
from flask import Flask, render_template from helloworld.core import get_message app = Flask(__name__) @app.route("/") def hello(): return render_template('index.html', message=get_message()) def run_server(): app.run()
И файл helloworld/templates/index.html :
body>>body>
И опишем команду serve в файле setup.py :
. entry_points= 'console_scripts': [ 'helloworld = helloworld.core:print_message', 'serve = helloworld.web:run_server', ] >, .
Теперь в нашем проекте появилась зависимость от пакета Flask. Без его установки наше приложение не будет правильно работать. За описание зависимостей в файле setup.py отвечает параметр install_requires:
. install_requires=[ 'Flask==0.8' ]
Проверим установку зависимостей обновив наш пакет и работу команды serve:
$ ./env/bin/python setup.py develop . Processing dependencies for helloworld==0.1 Searching for Flask==0.8 . $ serve * Running on http://127.0.0.1:5000/
Открыв браузер по адресу http://127.0.0.1:5000 вы должны увидеть нашу страницу.
Управление файлами проекта (MANIFEST.in)
На текущий момент при сборке нашего пакета distutils включает в него только python-файлы. Необходимо включить в него файл helloworld/templates/index.html без которого проект работать не будет.
Чтобы сделать это мы должны сообщить distutils какие еще файлы надо включать в наш проект. Один из способов — это создание файла MANIFEST.in :
recursive-include helloworld/templates *.html
Данная команда указывает distutils на включение в проект всех html файлов в директории helloworld/templates .
Также придется обновить setup.py :
. setup( . include_package_data=True, . )
Теперь шаблоны будут включены в наш проект.
Создание и запуск тестов
Хорошей практикой считается создание тестов для вашего проекта. Добавим простейшую реализацию, файл tests.py :
from unittest import TestCase from helloworld.core import get_message class HelloworldTestCase(TestCase): def test_helloworld(self): self.assertEqual(get_message(), 'Hello World!')
И обновим setup.py :
. setup( . test_suite='tests', . )
Теперь мы можем произвести предварительное тестирование нашего проекта:
$ python setup.py test running test running egg_info writing requirements to helloworld.egg-info/requires.txt writing helloworld.egg-info/PKG-INFO writing top-level names to helloworld.egg-info/top_level.txt writing dependency_links to helloworld.egg-info/dependency_links.txt writing entry points to helloworld.egg-info/entry_points.txt reading manifest file 'helloworld.egg-info/SOURCES.txt' reading manifest template 'MANIFEST.in' writing manifest file 'helloworld.egg-info/SOURCES.txt' running build_ext test_helloworld (tests.HelloworldTestCase) . ok ---------------------------------------------------------------------- Ran 1 test in 0.000s OK
Обратите внимание, что для запуска тестов даже не нужно создание виртуального окружения. Необходимые зависимости будут скачаны в директорию проекта в виде egg пакетов.
Публикация пакета на pypi.python.org
Прежде чем вы сможете опубликовать свой проект вам необходимо зарегистрироваться на PyPi. Запишите ваши реквизиты в файле ~/.pypirc :
[distutils] index-servers = pypi [pypi] username: password:
Все ваш проект готов к публикации. Достаточно ввести соответствующую команду:
$ python setup.py register sdist upload
Вы не сможете опубликовать пакет helloworld , тк данное имя проекта уже занято.
Учимся создавать пакеты Python
Почему важно уметь создавать пакеты Python?
• Пакеты легко устанавливаются (pip install demo).
• Пакеты упрощают разработку (Команда pip install -e устанавливает ваш пакет и следит за тем, чтобы он сам обновлялся в ходе всего процесса разработки).
• Пакеты легко запускать и тестировать (from demo.main import say_hello, а затем тестируем функцию).
• Пакеты легко версионировать, при этом вы не рискуете нарушить работу кода, зависящего от этого пакета (pip install demo==1.0.3).
В чем отличия между библиотекой, пакетом и модулем:
• Модуль: это .py-файл, в котором содержатся функции, образующие некоторое единство
• Пакет: это коллекция модулей, которую можно распространять
• Библиотека: это пакет, не учитывающий контекста
Заключать код Python в пакеты достаточно просто. Для этого вам понадобится всего один скрипт setup.py, позволяющий упаковать код сразу в нескольких форматах для распространения.
1. Подготовка к упаковке
Давайте воспользуемся такой структурой каталогов, которая описана в этом посте, и создадим здесь виртуальное окружение:
➜ tree -a -L 2 . ├── .venv │ └── . ├── Pipfile ├── Pipfile.lock ├── src │ └── demo │ └── main.py └── tests └── demo └── . 9 directories, 3 files
Создаем файл setup.py в корневом каталоге. В этом файле мы будем описывать, каким именно образом хотим упаковать наш код. Для начала напишем следующее:
"""Скрипт Setup.py для проекта по упаковке.""" from setuptools import setup, find_packages import json import os def read_pipenv_dependencies(fname): """Получаем из Pipfile.lock зависимости по умолчанию.""" filepath = os.path.join(os.path.dirname(__file__), fname) with open(filepath) as lockfile: lockjson = json.load(lockfile) return [dependency for dependency in lockjson.get('default')] if __name__ == '__main__': setup( name='demo', version=os.getenv('PACKAGE_VERSION', '0.0.dev0'), package_dir=, packages=find_packages('src', include=[ 'demo*' ]), description='A demo package.', install_requires=[ *read_pipenv_dependencies('Pipfile.lock'), ] )
Теперь можно вызвать этот скрипт, который позволяет упаковать ваш код несколькими способами:
python setup.py develop # ничего не генерировать, просто установить локально python setup.py bdist_egg # сгенерировать дистрибутив «яйцо», не включать зависимости python setup.py bdist_wheel # сгенерировать версионированное «колесо», включить зависимости python setup.py sdist --formats=zip,gztar,bztar,ztar,tar # исходный код
Давайте запустим первый вариант из списка. Если все пройдет успешно, то вы сможете импортировать ваш код следующим образом:
from demo.main import say_hello
Примечание:
Если выдается сообщение “No module named demo…», то нужно добавить пустой файл __init__.py во все каталоги, из которых вы хотите импортировать. В нашем примере сюда включается только каталог demo. Подробнее об этих файлах __init__.py можно почитать здесь.
Теперь, когда мы в состоянии установить проект, давайте внимательнее рассмотрим аргументы, передаваемые функции setuptools.setup:
1. name: имя вашей функции
2. version: результатом каждого изменения, вносимого в код, должна быть новая версия пакета; в противном случае возможна ситуация, в которой разработчики устанавливают прежнюю версию пакета, которая вдруг станет функционировать не так как раньше и сломает код.
3. packages: список путей ко всем вашим файлам python
4. install_requires: список имен и версий пакетов (точно как в файле requirements.txt)
Как видите, я написал простую функцию read_pipenv_dependencies для считывания из Pipfile.lock зависимостей, не попадающих в разработку (non-dev). В данном случае я не хочу задавать зависимости вручную. Также я воспользуюсь os.getenv для считывания переменной окружения и определения версии пакета – пожалуй, это хорошие сюжеты для новых постов.
2. Документация
Точно как при считывании Pipfile.lock для указания зависимостей, я могу прочитать и файл README.md, чтобы отобразить полезную документацию как long_description. Подробнее о том, как это делается, рассказано в packaging.python.org.
Кроме того, можно создать полноценную веб-страницу с документацией при помощи readthedocs и sphinx. Создаем каталог для вашей документации:
mkdir docs
pipenv install -d sphinx
Командой quickstart генерируем каталог с исходниками для вашей документации:
sphinx-quickstart
Теперь можно приступать к наполнению файла docs/index.rst самой документацией. Подробнее о том, как автоматизировать этот процесс, рассказано на сайте sphinx-doc.org.
3. Линтинг и тестирование
В рамках процесса упаковки целесообразно применить статический анализ кода, линтинг и тестирование.
pipenv install -d mypy autopep8 \ flake8 pytest bandit pydocstyle
В данном случае предпочтительно выполнить команду, которая выполнила бы стиль кода, прогнала несколько тестов и проверок, прежде, чем код можно будет зафиксировать и скинуть в удаленный репозиторий. Это делается для того, чтобы спровоцировать отказ конвейера сборки, если тесты не пройдут.
4. Makefile
По мере того, как мы быстро вводим все новые команды, нужные для упаковки нашего конкретного проекта, распространенные команды полезно записывать. В большинстве инструментов для автоматизации сборки (например, в Gradle или npm) эта возможность предоставляется по умолчанию.
Make – это инструмент, организующий компиляцию кода. Традиционно используется в c-ориентированных проектах. Но с его помощью можно выполнять и любые другие команды.
По умолчанию при использовании make выполняется первая команда из списка. Таким образом, в следующем примере будет выполнена make help, а на экран будет выведено содержимое Makefile.
Если сделать make test, то сначала будет выполнена make dev, поскольку в файле Makefile она указана как зависимость:
help: @echo "Tasks in \033[1;32mdemo\033[0m:" @cat Makefile lint: mypy src --ignore-missing-imports flake8 src --ignore=$(shell cat .flakeignore) dev: pip install -e . test: dev pytest --doctest-modules --junitxml=junit/test-results.xml bandit -r src -f xml -o junit/security.xml || true build: clean pip install wheel python setup.py bdist_wheel clean: @rm -rf .pytest_cache/ .mypy_cache/ junit/ build/ dist/ @find . -not -path './.venv*' -path '*/__pycache__*' -delete @find . -not -path './.venv*' -path '*/*.egg-info*' -delete
Теперь, как видите, новым разработчикам достаточно легко внести свой вклад в проект. Распространенные команды у них как на ладони и, например, сразу видно, как собрать колесо: make build.
5. Установка колеса
Если запустить make build, программа использует файл setup.py, чтобы создать дистрибутив колеса. Файл .whl находится в каталоге dist/, в имени файла должно присутствовать 0.0.dev0. Теперь можно указать переменную окружения, чтобы изменить версию колеса:
export PACKAGE_VERSION='1.0.0' make build ls dist
Имея колесо, можно создать где-нибудь на ПК новый каталог, скопировать в него колесо, а затем установить его при помощи:
mkdir test-whl && cd test-whl pipenv shell pip install *.whl
Вывод списка установленных файлов:
pip list
6. Включить конфигурационные файлы
Добавить данные в пакет можно и другим способом, включив в скрипт setup.py следующие строки:
Примечание:
Dозможно, не будет работать на распределенных системах (например, в Databricks).
if __name__ == '__main__': setup( data_files=[ ('data', ['data/my-config.json']) ] )
После этого можно будет прочитать файл при помощи следующей функции:
def get_cfg_file(filename: str, foldername: str) -> dict: """получить конфигурационный файл при помощи свойства 'data_files' из скрипта setup.py. """ if not isinstance(foldername, str): raise ValueError('Foldername must be string.') if foldername[0] == '/': raise ValueError('Foldername must not start with \'/\'') if not isinstance(filename, str): raise ValueError('Filename must be string.') # Сначала попытается считать файл из того места, в котором он установлен # Это касается только установок .whl # В противном случае файл будет считываться напрямую try: filepath = os.path.join(sys.prefix, foldername, filename) with open(filepath) as f: return json.load(f) except FileNotFoundError: filepath = os.path.join(foldername, filename) with open(filepath) as f: return json.load(f)
Если снова создать колесо и установить его в виртуальной среде в новом каталоге, не копируя файл данных, то можно будет обратиться к данным, выполнив вышеприведенную функцию.
7. DevOps
В рамках процесса упаковки мы хотим интегрировать изменения, внесенные многими участниками и автоматизировать интеграцию, так как для успешного релиза новой версии требуется выполнять множество повторяющихся процессов.
Здесь рассмотрим для примера Azure DevOps, где на git tags, а также в ветке master будет инициироваться процесс, представленный ниже.
Посмотрите код, и ниже мы обсудим его различные стадии и задачи:
resources: - repo: self trigger: - master - refs/tags/v* variables: python.version: "3.7" project: demo feed: demo major_minor: $[format('.', pipeline.startTime)] counter_unique_key: $[format('.demo', variables.major_minor)] patch: $[counter(variables.counter_unique_key, 0)] fallback_tag: $(major_minor).dev$(patch) stages: - stage: Test jobs: - job: Test displayName: Test steps: - task: UsePythonVersion@0 displayName: "Use Python $(python.version)" inputs: versionSpec: "$(python.version)" - script: pip install pipenv && pipenv install -d --system --deploy --ignore-pipfile displayName: "Install dependencies" - script: pip install typed_ast && make lint displayName: Lint - script: pip install pathlib2 && make test displayName: Test - task: PublishTestResults@2 displayName: "Publish Test Results junit/*" condition: always() inputs: testResultsFiles: "junit/*" testRunTitle: "Python $(python.version)" - stage: Build dependsOn: Test jobs: - job: Build displayName: Build steps: - task: UsePythonVersion@0 displayName: "Use Python $(python.version)" inputs: versionSpec: "$(python.version)" - script: "pip install wheel twine" displayName: "Wheel and Twine" - script: | # Получить версию по тегу git (v1.0.0) -> (1.0.0) git_tag=`git describe --abbrev=0 --tags | cut -d'v' -f 2` echo "##vso[task.setvariable variable=git_tag]$git_tag" displayName: Set GIT_TAG variable if tag is pushed condition: contains(variables['Build.SourceBranch'], 'refs/tags/v') - script: | # Получить переменные, совместно используемые разными заданиями GIT_TAG=$(git_tag) FALLBACK_TAG=$(fallback_tag) echo GIT TAG: $GIT_TAG, FALLBACK_TAG: $FALLBACK_TAG # Экспортировать переменную, так, чтобы python мог ее принять export PACKAGE_VERSION=$> echo Version used in setup.py: $PACKAGE_VERSION # Использовать PACKAGE_VERSION в setup() python setup.py bdist_wheel displayName: Build - task: CopyFiles@2 displayName: Copy dist files inputs: sourceFolder: dist/ contents: demo*.whl targetFolder: $(Build.ArtifactStagingDirectory) flattenFolders: true - task: PublishBuildArtifacts@1 displayName: PublishArtifact inputs: pathtoPublish: $(Build.ArtifactStagingDirectory) ArtifactName: demo.whl - task: TwineAuthenticate@1 inputs: artifactFeed: $(project)/$(feed) - script: | twine upload -r $(feed) --config-file $(PYPIRC_PATH) dist/* displayName: PublishFeed
На этапе Test мы устанавливаем проект в контейнер конвейера, не создавая виртуального окружения. Затем выполняем команды make lint и make test, точно как вы сделали бы это на вашей машине.
На этапе Build попытаемся извлечь версию пакета, ориентируясь на тег git, а еще соберем резервную версию пакета. Выполним команду python setup.py bdist_wheel для сборки колеса, учитывая, что у нас уже установлена переменная окружения, соответствующая версии пакета. Наконец, мы публикуем артефакт в числе других артефактов Azure DevOps и (по желанию) можем выложить в ленту.
Чтобы опубликовать пакет в ленте, вам потребуется файл .pypirc, а затем вы можете скопировать содержимое ленты, созданной в Azure DevOps. Выглядеть файл будет примерно так:
[distutils] Index-servers = stefanschenk [stefanschenk] Repository = https://pkgs.dev.azure.com/stefanschenk/_packaging/stefanschenk/pypi/upload
О том, как устанавливать пакеты из частной ленты, рассказано здесь.
- python
- программирование
- web-разработка
setup.py
Сценарий установки является центром всей деятельности по созданию, распространению и установке модулей с использованием Distutils. Его цель — правильная установка программного обеспечения.
Если все, что вам нужно, это распространить модуль с именем foo, содержащийся в файле foo.py, то ваш скрипт установки может быть таким простым:
from distutils.core import setup setup(name='foo', version='1.0', py_modules=['foo'], )
Чтобы создать исходный дистрибутив для этого модуля, вы должны создать скрипт установки setup.py, содержащий приведенный выше код, и запустить эту команду из терминала:
python setup.py sdist
sdist создаст архивный файл (например, tarball в Unix, ZIP-файл в Windows), содержащий ваш скрипт установки setup.py и ваш модуль foo.py. Архивный файл будет называться foo-1.0.tar.gz (или .zip) и будет распакован в каталог foo-1.0.
Если конечный пользователь желает установить ваш модуль foo, все, что ему нужно сделать, это загрузить foo-1.0.tar.gz (или .zip), распаковать его и — из каталога foo-1.0 — запустить
python setup.py install
Добавление сценариев командной строки в ваш пакет Python
Скрипты командной строки внутри пакетов Python являются общими. Вы можете организовать свой пакет таким образом, чтобы, когда пользователь установит пакет, скрипт был доступен по его пути.
Если вы имели greetings пакета , который имел в командной строке скрипт hello_world.py .
greetings/ greetings/ __init__.py hello_world.py
Вы можете запустить этот скрипт, запустив:
python greetings/greetings/hello_world.py
Однако, если вы хотите запустить его так:
hello_world.py
Вы можете достичь этого путем добавления scripts к вашей setup() в setup.py , как это:
from setuptools import setup setup( name='greetings', scripts=['hello_world.py'] )
При установке пакета приветствия теперь hello_world.py будет добавлен к вашему пути.
Другой возможностью было бы добавить точку входа:
entry_points=
Таким образом, вы просто должны запустить его так:
greetings
Использование метаданных контроля версий в setup.py
setuptools_scm является официально благословенным пакетом , который можно использовать Git или Mercurial метаданные , чтобы определить номер версии пакета, и найти пакеты Python и данные пакета , чтобы включить в него.
from setuptools import setup, find_packages setup( setup_requires=['setuptools_scm'], use_scm_version=True, packages=find_packages(), include_package_data=True, )
Этот пример использует обе функции; только использовать метаданные SCM для версии, замените вызов find_packages() с ручным списком пакетов, или использовать только пакет искатель, удалить use_scm_version=True .
Добавление параметров установки
Как видно из предыдущих примеров, основное использование этого скрипта:
python setup.py install
Но есть еще больше возможностей, таких как установка пакета и возможность изменить код и протестировать его без необходимости переустановки. Это делается с помощью:
python setup.py develop
Если вы хотите , чтобы выполнять определенные действия , как составление документации сфинкса или строительство FORtran кода, вы можете создать свой собственный вариант , как это:
cmdclasses = dict() class BuildSphinx(Command): """Build Sphinx documentation.""" description = 'Build Sphinx documentation' user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): import sphinx sphinx.build_main(['setup.py', '-b', 'html', './doc', './doc/_build/html']) sphinx.build_main(['setup.py', '-b', 'man', './doc', './doc/_build/man']) cmdclasses['build_sphinx'] = BuildSphinx setup( . cmdclass=cmdclasses, )
initialize_options и finalize_options будут выполняться до и после run функции , как их имена предполагает его.
После этого вы сможете назвать свой вариант:
python setup.py build_sphinx
К подготовке и публикации первого пакета Python готовы!
Python стал одним из самых широко используемых языков программирования. Главным образом объясняется это тем, что мы, его обычные пользователи, можем поделиться своим кодом, обеспечивая другим возможность беспрепятственно им пользоваться. А сделать это можно общепринятым способом, упаковав весь код и загрузив его в каталог программного обеспечения Python (Python Package Index или PyPI), с помощью которого пользователи легко и просто установят ваш пакет, используя инструмент pip.
Если у вас был опыт публикации пакета Python, то вы уже знаете, насколько всё просто. Однако новичкам этот процесс ошибочно представляется геркулесовым трудом. В данной статье будут рассмотрены все этапы подготовки пакета и его последующей публикации.
Очевидно, что на первом этапе ваша задача — завершить проект. Однако все понимают, что пакеты никогда не бывают идеальными. Поэтому не будем ждать окончания проекта, а заранее узнаем, как опубликовать пакет.
Для работы с текущим руководством представим, что директория со всеми файлами Python, включая нужный нам python_file_0.py, называется test_package. Именно этот пакет мы и намерены опубликовать. Следуя принципу простоты, файл python_file_0.py содержит лишь следующий код, который будет использован по мере нашей готовности импортировать пакет после его публикации:
1. Подготовка файлов
Перед тем, как углубиться в детали публикации, сначала структурируем директорию с помощью необходимых вспомогательных файлов. Ниже представлена файловая структура пакета:
the_root_dir/ |— README.md |— setup.py |— test_package | |— __init__.py | |— python_file_0.py | |— python_file_1.py | |— python_file_2.py
- В корневой директории на одном уровне с test_package создайте файл README.md. Он будет содержать необходимую пользователям информацию о пакете, например сведения об установке и инструкции по применению.
- На этом же уровне находится файл setup.py. Он будет включать информацию, необходимую для подготовки пакета к публикации. Вскоре мы рассмотрим содержимое этого файла.
- В директории test_package создайте файл __init__.py именно с таким именем. Он трансформирует обычную директорию в пакет Python. Для этого простого пакета просто поместим код в python_file_0.py и экспортируем from test_package.python_file_0 import hello_world.
Файл README
Теоретически для этого файла можно использовать простой текст, но отдав предпочтение файлу Markdown, вы получите разные возможности форматирования и таким образом сделаете его более интересным для чтения. Ниже показан пример простого файла README.md:
Это тестовый пакет, представляющий собой часть обучающего руководства Meduim.
**Текст жирным шрифтом**
*Текст, выделенный курсивом*