Перейти к содержимому

Как создать свой пакет python

  • автор:

Создание пакетов Python

Каждый пакет требует setup.py файл , который описывает пакет.

Рассмотрим следующую структуру каталогов для простого пакета:

 +-- package_name | | | +-- __init__.py | +-- setup.py 

__init__.py содержит только строки def foo(): return 100 .

Следующий setup.py определит пакет:

 from setuptools import setup setup( name='package_name', # package name version='0.1', # version description='Package Description', # short description url='http://example.com', # package URL install_requires=[], # list of packages this package depends # on. packages=['package_name'], # List of module names that installing # this package will provide. ) 

virtualenv отлично подходит для тестирования установки пакета без изменения других ваших сред Python:

 $ virtualenv .virtualenv . $ source .virtualenv/bin/activate $ python setup.py install running install . Installed . /package_name-0.1-. egg . $ python >>> import package_name >>> package_name.foo() 100 

Загрузка в PyPI

После того, как ваш setup.py полностью функционален (см Введение ), очень легко загрузить пакет PyPI .

Установите файл .pypirc

В этом файле хранятся логины и пароли для аутентификации ваших учетных записей. Обычно он хранится в вашем домашнем каталоге.

 # .pypirc file [distutils] index-servers = pypi pypitest [pypi] repository=https://pypi.python.org/pypi username=your_username password=your_password [pypitest] repository=https://testpypi.python.org/pypi username=your_username password=your_password 

Это безопаснее использовать twine для загрузки пакетов, поэтому убедитесь , что установлено.

 $ pip install twine 

Зарегистрируйтесь и загрузите в testpypi (необязательно)

Примечание: PyPI не допускает перезапись загруженных пакетов , поэтому целесообразно сначала проверить развертывание на выделенном тестовом сервере, например testpypi. Этот вариант будет обсуждаться. Рассмотрим схему управления версиями для вашего пакета до загрузки , таких как календарь версий или семантического версий .

Либо войти или создать новую учетную запись на testpypi.Регистрация требуется только в первый раз, хотя регистрация более одного раза не наносит вреда.

 $ python setup.py register -r pypitest 

Находясь в корневом каталоге вашего пакета:

 $ twine upload dist/* -r pypitest 

Теперь ваш пакет должен быть доступен через вашу учетную запись.

тестирование

Создайте тестовую виртуальную среду. Попробуйте pip install пакет с любого testpypi или PyPI.

 # Using virtualenv $ mkdir testenv $ cd testenv $ virtualenv .virtualenv . $ source .virtualenv/bin/activate # Test from testpypi (.virtualenv) pip install --verbose --extra-index-url https://testpypi.python.org/pypi package_name . # Or test from PyPI (.virtualenv) $ pip install package_name . (.virtualenv) $ python Python 3.5.1 (default, Jan 27 2016, 19:16:39) [GCC 4.2.1 Compatible Apple LLVM 7.0.2 (clang-700.1.81)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import package_name >>> package_name.foo() 100 

В случае успеха ваш пакет будет наименее импортируемым. Вы также можете попробовать протестировать свой API перед окончательной загрузкой в ​​PyPI. Если вы провалили упаковку во время тестирования, не беспокойтесь. Вы все еще можете это исправить, повторно загрузить в testpypi и протестировать снова.

Зарегистрируйтесь и загрузите в PyPI

Убедитесь в том , twine установлен:

 $ pip install twine 

Либо войти или создать новую учетную запись на PyPI .

 $ python setup.py register -r pypi $ twine upload dist/* 

Это оно! Ваш пакет теперь живут .

Если вы обнаружите ошибку, просто загрузите новую версию вашего пакета.

Документация

Не забудьте включить хотя бы какую-то документацию для вашего пакета. PyPi принимает в качестве языка форматирования по умолчанию в ReStructuredText .

Прочти меня

Если пакет не имеет большую документации, включает в себя то , что может помочь другим пользователям в README.rst файла. Когда файл готов, нужен еще один, чтобы сказать PyPi, чтобы он показывался.

Создать setup.cfg файл и поместить эти две строки в нем:

 [metadata] description-file = README.rst 

Обратите внимание , что если вы попытаетесь поставить Markdown файл в пакет, PyPi будет читать его как чистый текстовый файл без какого — либо форматирования.

лицензирование

Это часто больше , чем могут поместить LICENSE.txt файл в пакете с одним из лицензий OpenSource , чтобы сообщить пользователям , если они могут использовать ваш пакет, например , в коммерческих проектах или если ваш код может использоваться с их лицензией.

В более понятным способом некоторые лицензии объясняются на TL; DR .

Делаем пакет исполняемым

Если пакет не только библиотека, но есть кусок кода , который может быть использован либо в качестве образца или отдельного приложения при установке вашего пакета, положил этот кусок кода в __main__.py файл.

Поместите __main__.py в package_name папке. Таким образом, вы сможете запустить его прямо из консоли:

 python -m package_name 

Если нет никакого __main__.py файла доступен, пакет не будет работать с этой командой, будет напечатана эта ошибка:

питон: Нет модуль с именем package_name.__main__; ‘имя_пакета’ — это пакет, который не может быть выполнен напрямую.

Создаём свой пакет Python

Создаём свой пакет Python

Повторное использование кода — очень полезная штука. Вы экономите время при написание одних и тех же кусков кода, и даже в одном проекте у вас сохраняется модульная структура приложения, что позволяет поддерживать в актуальном состоянии каждый модуль отдельно от других. И в python довольно легко создать структуру приложения так, чтобы было легко его оформить в пакет. Этот гайд поможет вам научиться создавать такие пакеты с нуля так, чтобы другие люди могли воспользоваться им в своих приложениях.

Структура пакета

Файл с расширением ‘.py’ — это модуль. Вы можете создать в нём классы, функции и переменные с таким же именем, как у файла. А если в папку положить несколько модулей и создать файл ‘__init__.py’, вы создадите тем самым пакет с именем как у папки. Вот примерная файловая иерархия обычного пакета:

Создаём свой пакет Python

Сборка пакета

Теперь когда мы знаем структуру пакета, поговорим про его сборку. Самое важное здесь — конфигурационный файл ‘setup.py’. Основной смысл в нём — хранение метаданных о пакете. Вот пример такого файла:

 from setuptools import setup, find_packages setup(name='funniest', version='0.1', description='The funniest joke in the world', long_description='Really, the funniest around.', classifiers=[ 'Development Status :: 3 - Alpha', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python :: 2.7', 'Topic :: Text Processing :: Linguistic', ], keywords='funniest joke comedy flying circus', url='http://github.com/storborg/funniest', author='Flying Circus', author_email='flyingcircus@example.com', license='MIT', packages=find_packages(), install_requires=[ 'markdown', ], include_package_data=True, zip_safe=False)

Более подробно об этом файле можно прочитать в документации.

Указываем зависимости

Для того, чтобы с пакетом можно было работать сразу после установки, вы должны указать в его конфигурации, от каких пакетов он зависит, чтобы они были сразу же установлены. Нужно просто вставить ‘install_requires=[…]’ в функцию setup. Можно также задать версию зависимости:

install_requires=[‘A==1.0’, ‘B>=1,

Эти зависимости — общедоступные пакеты, которые можно установить с помощью утилиты pip. Но если ваши зависимости не перечислены в каталоге pypi, укажите их так:

dependency_links=[‘http://github.com/user/repo/tarball/master#egg=package-1.0']
Дополнительные файлы

Иногда бывает необходимость вложить в пакет другие типы файлов. Для этого:

  1. Задайте ‘include_package_data=True’
  2. Создайте файл MANIFEST.in в папке с setup.py
  3. Добавьте путь до файла в MANIFEST как ‘include /path/to/test.json’, путь при этом относительный. Также можно использовать поисковый шаблон типа ‘*.json’.
Сборка

Теперь у нас всё готово, приступаем к сборке пакета. Это значит, что мы создадим дистрибутив исходного кода (напр., tar.gz) или бинарный файл (напр., wheel). Это очень просто.

python setup.py sdist bdist_wheel

В результате у нас в папке ‘./dist’ появятся оба формата. при этом имя дистрибутива будет присвоено исходя из имени пакета и его версии.

Распространение пакета

Поздравляю, вы создали замечательный пакет! Теперь необходимо выложить его для общего доступа. Мы загрузим его на Pypi, поэтому в будущем можно будет его установить командой ‘pip install’.

Для начала создайте учётную запись на сайте pypi.

twine upload dist/*

При этом файлы из папки ‘dist/’ выгрузятся в каталог pypi. Также вы можете явно указать только определённый файл для выгрузки. Twine это специальная утилита для работы с pypi. При первой загрузке пакета она зарегистрирует пакет в pypi.

Работа с пакетом

Теперь ваш пакет опубликован в pypi. Для его установки достаточно набрать ‘pip install my_package’, а затем в коде ‘import my_package’.

При локальной разработке пакета для его тестирования добавьте путь к нему в $PYTHONPATH. Но если вы не хотите трогать переменные окружения, установите его командой ‘pip install -e .’ из папки с пакетом.

Разработчик: java, kotlin, c#, javascript, dart, 1C, python, php.

Учимся создавать пакеты Python

image

Почему важно уметь создавать пакеты Python?
• Пакеты легко устанавливаются (pip install demo).
• Пакеты упрощают разработку (Команда pip install -e устанавливает ваш пакет и следит за тем, чтобы он сам обновлялся в ходе всего процесса разработки).
• Пакеты легко запускать и тестировать (from demo.main import say_hello, а затем тестируем функцию).
• Пакеты легко версионировать, при этом вы не рискуете нарушить работу кода, зависящего от этого пакета (pip install demo==1.0.3).

image

В чем отличия между библиотекой, пакетом и модулем:
• Модуль: это .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-разработка

Как создать и использовать свои пакеты в Python

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

Creating a Python package.

Алексей Кодов
Автор статьи
23 июня 2023 в 18:38

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

Создание пакета

Создание пакета в Python достаточно просто. Вам нужно сделать следующее:

  1. Создайте каталог для пакета. Название каталога будет являться именем пакета, поэтому выберите название, которое отражает его содержимое. Например, если вы создаете пакет для работы с изображениями, вы можете назвать его image_processing .
  2. Добавьте файл __init__.py в каталог. Этот файл является обязательным для корректного определения пакета Python. Файл может быть пустым или содержать инициализацию пакета.
  3. Добавьте модули и функции в пакет. В каталоге пакета создайте файлы .py с именами модулей и напишите в них код. Например, для пакета image_processing вы можете создать модуль filters.py с функциями для применения различных фильтров к изображениям.

Использование пакета

Чтобы использовать созданный вами пакет в другом Python-проекте, выполните следующие шаги:

  1. Импортируйте пакет. Используйте инструкцию import для импорта пакета в свой код. Например:
import image_processing
  1. Используйте функции и модули пакета. Теперь вы можете обращаться к функциям и модулям из вашего пакета. Например, чтобы использовать функцию apply_filter из модуля filters пакета image_processing , выполните следующую команду:
image_processing.filters.apply_filter(image, filter_type)

Python-разработчик: новая работа через 9 месяцев
Получится, даже если у вас нет опыта в IT

Пример создания и использования пакета

Давайте создадим простой пакет math_utils с модулем operations , который будет содержать функции для основных математических операций.

  1. Создайте каталог math_utils .
  2. Добавьте файл __init__.py в каталог math_utils .
  3. Создайте файл operations.py в каталоге math_utils и добавьте следующий код:
def add(a, b): return a + b def subtract(a, b): return a - b def multiply(a, b): return a * b def divide(a, b): if b == 0: raise ValueError("Division by zero is not allowed.") return a / b

Теперь ваш пакет math_utils готов к использованию. В другом проекте вы можете импортировать этот пакет и использовать его функции следующим образом:

import math_utils.operations result = math_utils.operations.add(3, 4) print(result) # Вывод: 7

Теперь вы знаете, как создавать и использовать свои собственные пакеты в Python. Это поможет вам лучше организовать свой код и повысить его переиспользуемость. Удачного кодирования! ��

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *