Python — отличный язык программирования, но упаковка — одна из его самых слабых точек. Это общеизвестный в сообществе факт. За последние годы установка, импорт, использование и создание пакетов значительно улучшилась, но она все еще не соответствует новым языкам, таким как Go и Rust, которые многому научились в борьбе с Python и другими зрелыми языками.
В этом уроке вы узнаете все, что вам нужно знать о написании, упаковке и распространении собственных пакетов.
Как написать библиотеку Python
Библиотека Python представляет собой согласованный набор модулей Python, который организован как пакет Python. В общем, это означает, что все модули живут под одним и тем же каталогом и этот каталог находится на пути поиска Python.
Давайте быстро напишем небольшой пакет Python 3 и проиллюстрируем все эти понятия.
Пакет Pathology
Python 3 имеет отличный объект Path, который является большим улучшением по сравнению с неудобным модулем Os.path Python 2. Но ему не хватает одной важной возможности — найти путь к текущему сценарию. Это очень важно, если вы хотите найти файлы доступа относительно текущего скрипта.
Во многих случаях сценарий может быть установлен в любом месте, поэтому вы не можете использовать абсолютные пути, а рабочий каталог может быть установлен на любое значение, поэтому вы не можете использовать относительный путь. Если вы хотите получить доступ к файлу в подкаталоге или родительском каталоге, вы должны иметь возможность определить текущий каталог сценариев.
Вот как вы это делаете в Python:
1 |
import pathlib |
2 |
|
3 |
script_dir = pathlib.Path(__file__).parent.resolve() |
Чтобы получить доступ к файлу с именем ‘file.txt’ в подкаталоге данных в каталоге текущего скрипта, вы можете использовать следующий код:print(open(str(script_dir/'data/file.txt').read())
С пакетом pathology у вас есть встроенный метод script_dir, и вы используете его следующим образом:
1 |
from pathology.Path import script_dir |
2 |
|
3 |
print(open(str(script_dir()/'data/file.txt').read()) |
4 |
Да, это глоток свежего воздуха. Пакет патологии очень прост. Он выводит свой собственный класс Path из Pathlib Path и добавляет статический script_dir(), который всегда возвращает путь вызывающего скрипта.
Вот реализация:
1 |
import pathlib |
2 |
import inspect |
3 |
|
4 |
class Path(type(pathlib.Path())): |
5 |
@staticmethod |
6 |
def script_dir(): |
7 |
print(inspect.stack()[1].filename) |
8 |
p = pathlib.Path(inspect.stack()[1].filename) |
9 |
return p.parent.resolve() |
Из-за кросс-платформенной реализации pathlib.Path вы можете получить непосредственно от него и должны быть получены из определенного подкласса (PosixPath или WindowsPath). Разрешение dir-файла сценария использует модуль проверки, чтобы найти вызывающего, а затем его атрибут имени файла.
Тестирование пакета патологии
Всякий раз, когда вы пишете нечто более сложное, вы должны его протестировать. Модуль патологии не является исключением. Вот тесты с использованием стандартной модульной тестовой платформы:
1 |
import os |
2 |
import shutil |
3 |
from unittest import TestCase |
4 |
from pathology.path import Path |
5 |
|
6 |
|
7 |
class PathTest(TestCase): |
8 |
def test_script_dir(self): |
9 |
expected = os.path.abspath(os.path.dirname(__file__)) |
10 |
actual = str(Path.script_dir()) |
11 |
self.assertEqual(expected, actual) |
12 |
|
13 |
def test_file_access(self): |
14 |
script_dir = os.path.abspath(os.path.dirname(__file__)) |
15 |
subdir = os.path.join(script_dir, 'test_data') |
16 |
if Path(subdir).is_dir(): |
17 |
shutil.rmtree(subdir) |
18 |
os.makedirs(subdir) |
19 |
file_path = str(Path(subdir)/'file.txt') |
20 |
content = '123' |
21 |
open(file_path, 'w').write(content) |
22 |
test_path = Path.script_dir()/subdir/'file.txt' |
23 |
actual = open(str(test_path)).read() |
24 |
|
25 |
self.assertEqual(content, actual) |
Путь Python
Пакеты Python должны быть установлены где-то на пути поиска Python, который должен быть импортирован модулями Python. Путь поиска Python представляет собой список каталогов и всегда доступен в sys.path
. Вот мой текущий sys.path:
1 |
>>> print('n'.join(sys.path)) |
2 |
|
3 |
/Users/gigi.sayfan/miniconda3/envs/py3/lib/python36.zip |
4 |
/Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6 |
5 |
/Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6/lib-dynload |
6 |
/Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6/site-packages |
7 |
/Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6/site-packages/setuptools-27.2.0-py3.6.egg |
Обратите внимание, что первая пустая строка вывода представляет текущий каталог, поэтому вы можете импортировать модули из текущего рабочего каталога, что бы это ни было. Вы можете напрямую добавлять или удалять каталоги в / из sys.path.
Вы также можете определить переменную среды PYTHONPATH, и есть несколько других способов ее контролировать. Стандартные site-packages
включены по умолчанию, и именно там устанавливаются пакеты, которые вы устанавливаете с помощью pip.
Как упаковать библиотеку Python
Теперь, когда у нас есть наш код и тесты, давайте упакуем все это в нужную библиотеку. Python обеспечивает простой способ через модуль настройки. Вы создаете файл setup.py в корневом каталоге вашего пакета. Затем, чтобы создать исходный дистрибутив, вы запустите: python setup.py sdist
Чтобы создать двоичный дистрибутив, называемый колесом, вы запускаете: python setup.py bdist_wheel
Вот файл setup.py пакета патологии:
1 |
from setuptools import setup, find_packages |
2 |
|
3 |
setup(name='pathology', |
4 |
version='0.1', |
5 |
url='https://github.com/the-gigi/pathology', |
6 |
license='MIT', |
7 |
author='Gigi Sayfan', |
8 |
author_email='the.gigi@gmail.com', |
9 |
description='Add static script_dir() method to Path', |
10 |
packages=find_packages(exclude=['tests']), |
11 |
long_description=open('README.md').read(), |
12 |
zip_safe=False) |
Он включает в себя множество метаданных в дополнение к элементу ‘packages’, который использует функцию find_packages()
, импортированную из se
tuptools, чтобы найти подпакеты.
Давайте построим дистрибутив источника:
1 |
$ python setup.py sdist |
2 |
running sdist |
3 |
running egg_info |
4 |
creating pathology.egg-info |
5 |
writing pathology.egg-info/PKG-INFO |
6 |
writing dependency_links to pathology.egg-info/dependency_links.txt |
7 |
writing top-level names to pathology.egg-info/top_level.txt |
8 |
writing manifest file 'pathology.egg-info/SOURCES.txt' |
9 |
reading manifest file 'pathology.egg-info/SOURCES.txt' |
10 |
writing manifest file 'pathology.egg-info/SOURCES.txt' |
11 |
warning: sdist: standard file not found: should have one of README, README.rst, README.txt |
12 |
|
13 |
running check |
14 |
creating pathology-0.1 |
15 |
creating pathology-0.1/pathology |
16 |
creating pathology-0.1/pathology.egg-info |
17 |
copying files to pathology-0.1... |
18 |
copying setup.py -> pathology-0.1 |
19 |
copying pathology/__init__.py -> pathology-0.1/pathology |
20 |
copying pathology/path.py -> pathology-0.1/pathology |
21 |
copying pathology.egg-info/PKG-INFO -> pathology-0.1/pathology.egg-info |
22 |
copying pathology.egg-info/SOURCES.txt -> pathology-0.1/pathology.egg-info |
23 |
copying pathology.egg-info/dependency_links.txt -> pathology-0.1/pathology.egg-info |
24 |
copying pathology.egg-info/not-zip-safe -> pathology-0.1/pathology.egg-info |
25 |
copying pathology.egg-info/top_level.txt -> pathology-0.1/pathology.egg-info |
26 |
Writing pathology-0.1/setup.cfg |
27 |
creating dist |
28 |
Creating tar archive |
29 |
removing 'pathology-0.1' (and everything under it) |
Предупреждение связано с тем, что я использовал нестандартный файл README.md. Это безопасно поэтому игнорируем. Результатом является файл tar-gzipped в каталоге dist:
1 |
$ ls -la dist |
2 |
total 8 |
3 |
drwxr-xr-x 3 gigi.sayfan gigi.sayfan 102 Apr 18 21:20 .
|
4 |
drwxr-xr-x 12 gigi.sayfan gigi.sayfan 408 Apr 18 21:20 .. |
5 |
-rw-r--r-- 1 gigi.sayfan gigi.sayfan 1223 Apr 18 21:20 pathology-0.1.tar.gz
|
И вот двоичное распределение:
1 |
$ python setup.py bdist_wheel |
2 |
running bdist_wheel |
3 |
running build |
4 |
running build_py |
5 |
creating build |
6 |
creating build/lib |
7 |
creating build/lib/pathology |
8 |
copying pathology/__init__.py -> build/lib/pathology |
9 |
copying pathology/path.py -> build/lib/pathology |
10 |
installing to build/bdist.macosx-10.7-x86_64/wheel |
11 |
running install |
12 |
running install_lib |
13 |
creating build/bdist.macosx-10.7-x86_64 |
14 |
creating build/bdist.macosx-10.7-x86_64/wheel |
15 |
creating build/bdist.macosx-10.7-x86_64/wheel/pathology |
16 |
copying build/lib/pathology/__init__.py -> build/bdist.macosx-10.7-x86_64/wheel/pathology |
17 |
copying build/lib/pathology/path.py -> build/bdist.macosx-10.7-x86_64/wheel/pathology |
18 |
running install_egg_info |
19 |
running egg_info |
20 |
writing pathology.egg-info/PKG-INFO |
21 |
writing dependency_links to pathology.egg-info/dependency_links.txt |
22 |
writing top-level names to pathology.egg-info/top_level.txt |
23 |
reading manifest file 'pathology.egg-info/SOURCES.txt' |
24 |
writing manifest file 'pathology.egg-info/SOURCES.txt' |
25 |
Copying pathology.egg-info to build/bdist.macosx-10.7-x86_64/wheel/pathology-0.1-py3.6.egg-info |
26 |
running install_scripts |
27 |
creating build/bdist.macosx-10.7-x86_64/wheel/pathology-0.1.dist-info/WHEEL |
Пакет патологии содержит только чистые модули Python, поэтому можно создать универсальный пакет. Если ваш пакет включает расширения C, вам нужно будет создать отдельное колесо для каждой платформы:
1 |
$ ls -la dist |
2 |
total 16 |
3 |
drwxr-xr-x 4 gigi.sayfan gigi.sayfan 136 Apr 18 21:24 .
|
4 |
drwxr-xr-x 13 gigi.sayfan gigi.sayfan 442 Apr 18 21:24 .. |
5 |
-rw-r--r-- 1 gigi.sayfan gigi.sayfan 2695 Apr 18 21:24 pathology-0.1-py3-none-any.whl
|
6 |
-rw-r--r-- 1 gigi.sayfan gigi.sayfan 1223 Apr 18 21:20 pathology-0.1.tar.gz
|
Для более глубокого погружения в тему упаковки библиотек Python ознакомьтесь, как писать свои собственные пакеты Python.
Как раздавать пакет Python
Python имеет центральный репозиторий пакетов, называемый PyPI (индекс пакетов Python). Когда вы устанавливаете пакет Python с помощью pip, он загружает пакет из PyPI (если вы не укажете другой репозиторий). Чтобы распространять наш пакет патологии, нам нужно загрузить его в PyPI и предоставить некоторые дополнительные метаданные, которые требуется PyPI. Шаги:
- Создайте учетную запись на PyPI (только один раз).
- Зарегистрируйте свой пакет.
- Загрузите свой пакет.
Создайте аккаунт
Вы можете создать учетную запись на веб-сайте PyPI. Затем создайте файл .pypirc в своем домашнем каталоге:
1 |
[distutils] |
2 |
index-servers=pypi |
3 |
|
4 |
[pypi] |
5 |
repository = https://pypi.python.org/pypi |
6 |
username = the_gigi |
В целях тестирования вы можете добавить «pypitest» индексный сервер в ваш .pypirc файл:
1 |
[distutils] |
2 |
index-servers= |
3 |
pypi
|
4 |
pypitest
|
5 |
|
6 |
[pypitest] |
7 |
repository = https://testpypi.python.org/pypi |
8 |
username = the_gigi |
9 |
|
10 |
[pypi] |
11 |
repository = https://pypi.python.org/pypi |
12 |
username = the_gigi |
Зарегистрируйте свой пакет
Если это первый выпуск вашего пакета, вам необходимо зарегистрировать его с помощью PyPI. Используйте команду register setup.py. Она попросит вас ввести пароль. Обратите внимание, что я указываю его на тестовый репозиторий:
1 |
$ python setup.py register -r pypitest |
2 |
running register |
3 |
running egg_info |
4 |
writing pathology.egg-info/PKG-INFO |
5 |
writing dependency_links to pathology.egg-info/dependency_links.txt |
6 |
writing top-level names to pathology.egg-info/top_level.txt |
7 |
reading manifest file 'pathology.egg-info/SOURCES.txt'
|
8 |
writing manifest file 'pathology.egg-info/SOURCES.txt'
|
9 |
running check |
10 |
Password: |
11 |
Registering pathology to https://testpypi.python.org/pypi |
12 |
Server response (200): OK |
Загрузите свой пакет
Теперь, когда пакет зарегистрирован, мы можем его загрузить. Я рекомендую использовать twine, который более безопасен. Установите его, как обычно, с помощью pip install twine
. Затем загрузите свой пакет с помощью twine и укажите свой пароль (отредактированный ниже):
1 |
$ twine upload -r pypitest -p <redacted> dist/* |
2 |
Uploading distributions to https://testpypi.python.org/pypi |
3 |
Uploading pathology-0.1-py3-none-any.whl |
4 |
[================================] 5679/5679 - 00:00:02 |
5 |
Uploading pathology-0.1.tar.gz |
6 |
[================================] 4185/4185 - 00:00:01 |
Для более глубокого погружения в тему распространения ваших пакетов ознакомьтесь с разделом «Пакеты Python».
Заключение
В этом уроке мы прошли полноценный процесс написания библиотеки Python, ее упаковки и распространения через PyPI. На этом этапе у вас должны быть все инструменты для написания и обмена вашими библиотеками с остальным миром.
Кроме того, не стесняйтесь посмотреть, что у нас есть для продажи и для изучения на рынке, и, пожалуйста, задавайте любые вопросы и предоставляйте свою ценную обратную связь, используя приведенный ниже канал.
Время на прочтение
10 мин
Количество просмотров 22K
Каждый разработчик ПО должен знать как создать библиотеку с нуля. В процессе работы Вы можете многому научиться. Только не забудьте запастись временем и терпением.
Может показаться, что создать библиотеку с открытым исходным кодом сложно, но Вам не нужно быть потрепанным жизнью ветераном своего дела, чтобы разобраться в коде. Также как Вам не нужна мудреная идея продукта. Но точно понадобятся настойчивость и время. Надеюсь, что данное руководство поможет Вам создать первый проект с минимальной затратой и первого, и второго.
В этой статье мы пошагово разберем процесс создания базовой библиотеки на Python. Не забудьте заменить в приведенном ниже коде my_package, my_file и т.п. нужными вам именами.
Шаг 1: Составьте план
Мы планируем создать простую библиотеку для использования в Python. Данная библиотека позволит пользователю легко конвертировать блокнот Jupyter в HTML-файл или Python-скрипт.
Первая итерация нашей библиотеки позволит вызвать функцию, которая выведет определенное сообщение.
Теперь, когда мы уже знаем, что хотим делать, нужно придумать название для библиотеки.
Шаг 2: Дайте имя библиотеке
Придумывать имена сложно. Они должны быть короткими, уникальными и запоминающимися. Также они должны быть написаны строчными буквами, без прочерков и прочих знаков препинания. Подчеркивание не рекомендуется. В процессе создания библиотеки убедитесь, что придуманное Вами имя доступно на GitHub, Google и PyPi.
Если Вы надеетесь и верите, что однажды Ваша библиотека получит 10000 звезд GitHub, то стоит проверить, доступно ли данное имя в социальных сетях. В данном примере я назову свою библиотеку notebookc, потому что это имя доступное, короткое и более-менее описывает суть моей задумки.
Шаг 3. Настройте среду
Убедитесь, что у вас установлены и настроены Python 3.7, GitHub и Homebrew. Если вам нужно что-то из этого, вот подробности:
Python
Скачайте Python 3.7 здесь и установите его.
GitHub
Если у вас нет учетной записи GitHub, перейдите по этой ссылке и оформите бесплатную подписку. Посмотрите, как установить и настроить Git здесь. Вам потребуется утилита командной строки. Перейдите по ссылкам, скачайте и установите все, что Вам понадобится, придумайте юзернейм и укажите электронную почту.
Homebrew
Homebrew — менеджер библиотек для Mac. Инструкции по установке найдете здесь.
Venv
Начиная с Python 3.6 рекомендуется использовать venv для создания виртуальной среды для разработки библиотек. Существует множество способов управления виртуальными средами с помощью Python и все они со временем изменяются. Можете ознакомиться с обсуждением здесь, но, как говорится, доверяй, но проверяй.
Начиная с версии Python 3.3 venv входит в систему по умолчанию. Обратите внимание, что venv устанавливает pip и setuptools начиная с Python 3.4.
Создайте виртуальную среду Python 3.7 с помощью следующей команды:
python3.7 -m venv my_env
Замените my_env вашим именем. Активируйте среду таким образом:
source my_env/bin/activate
Теперь вы должны наблюдать (my_env) (или имя, которое вы выбрали для вашей виртуальной среды) в крайнем левом углу терминала.
Когда закончите работу, деактивируйте виртуальную среду с помощью deactivate
.
Теперь давайте настроим GitHub.
Шаг 4: Создайте организацию в GitHub
GitHub — лидер на рынке реестров контроля версий. Еще две популярные опции — GitLab и Bitbucket. В данном гиде мы будем использовать именно GitHub.
Вам придется часто обращаться к Git и GitHub, поэтому если Вы не знакомы с системой, то можете обратиться к моей статье.
Создайте новую организацию в GitHub. Следуйте инструкциям. Я назвал свою организацию notebooktoall. Вы можете создать репозиторий под своей личной учетной записью, но одна из целей работы — научиться создавать проект с открытым исходным кодом для более широкого сообщества.
Шаг 5: Настройте GitHub Repo
Создайте новый репозиторий. Я назвал свой notebookc.
Добавьте .gitignore из выпадающего списка. Выберите Python для своего репозитория. Содержимое Вашего файла .gitignore будет соответствовать папкам и типам файлов, исключенным из вашего хранилища. Вы можете позже изменить .gitignore, чтобы исключить другие ненужные или конфиденциальные файлы.
Рекомендую выбрать лицензию в списке Выбрать лицензию. Она определяет, что могут делать пользователи Вашего репозитория. Одни лицензии позволяют больше других. Если Вы ничего не выбираете, то автоматически начинают действовать стандартные законы об авторских правах. Узнайте больше о лицензиях здесь.
Для этого проекта я выбрал третью версию Открытого лицензионного соглашения GNU, потому что она популярная, проверенная и “гарантирует пользователям свободу использования, изучения, обмена и изменения программного обеспечения” — источник.
Шаг 6: Клонируйте и добавьте директории
Выберите, куда Вы хотите клонировать Ваш репозиторий или выполните следующую функцию:
git clone https://github.com/notebooktoall/notebookc.git
Подставьте свою организацию и репозиторий.
Перейдите в папку проекта с помощью десктопного графического интерфейса или редактора кода. Или используйте командную строку с cd my-project
и после просмотрите файлы с ls —A
.
Ваши исходные папки и файлы должны выглядеть так:
.git
.gitignore
LICENSE
README.rst
Создайте вложенную папку для основных файлов проекта. Я советую назвать ее так же, как и вашу библиотеку. Убедитесь, что в имени нет пробелов.
Создайте файл с именем __init__.py в основной вложенной папке. Этот файл пока останется пустым. Он необходим для импорта файлов.
Создайте еще один файл с таким же именем, как у основной вложенной папки, и добавьте .py. Мой файл называется notebookc.py. Вы можете назвать этот Python-файл как захотите. Пользователи библиотеки при импорте модуля будут ссылаться на имя этого файла.
Содержимое моей директории notebookc выглядит следующим образом:
.git
.gitignore
LICENSE
README.rst
notebookc/__init__.py
notebookc/notebookc.py
Шаг 7: Скачайте и установите requirements_dev.txt
На верхнем уровне директории проекта создайте файл requirements_dev.txt. Часто этот файл называют requirements.txt. Назвав его requirements_dev.txt, Вы показываете, что эти библиотеки могут устанавливаться только разработчиками проекта.
В файле укажите, что должны быть установлены pip и wheel.
pip==19.0.3
wheel==0.33.1
Обратите внимание, что мы указываем точные версии библиотек с двойными знаками равенства и полными номерами версии.
Закрепите версии вашей библиотеку в requirements_dev.txt
Соавтор, который разветвляет репозиторий проекта и устанавливает закрепленные библиотеки require_dev.txt с помощью pip, будет иметь те же версии библиотеки, что и Вы. Вы знаете, что эта версия будет работать у них. Кроме того, Read The Docs будет использовать этот файл для установки библиотек при сборке документации.
В вашей активированной виртуальной среде установите библиотеку в файл needs_dev.txt с помощью следующей команды:
pip install -r requirements_dev.txt
Настоятельно рекомендую обновлять эти библиотеки по мере выхода новых версий. На данный момент установите любые последние версии, доступные на PyPi.
В следующей статье расскажу, как установить инструмент, облегчающий этот процесс. Подпишитесь, чтобы не пропустить.
Шаг 8: Поработайте с кодом
В целях демонстрации давайте создадим базовую функцию. Свою собственную крутую функцию сможете создать позже.
Вбейте следующее в Ваш основной файл (для меня это notebookc/notebookc/notebookc.py):
def convert(my_name):
"""
Print a line about converting a notebook.
Args:
my_name (str): person's name
Returns:
None
"""
print(f"I'll convert a notebook for you some day, {my_name}.")
Вот наша функция во всей красе.
Строки документа начинаются и заканчиваются тремя последовательными двойными кавычками. Они будут использованы в следующей статье для автоматического создания документации.
Сохраните изменения. Если хотите освежить память о работе с Git, то можете заглянуть в эту статью.
Шаг 9: Создайте setup.py
Файл setup.py — это скрипт сборки для вашей библиотеки. Функция setup из Setuptools создаст библиотеку для загрузки в PyPI. Setuptools содержит информацию о вашей библиотеке, номере версии и о том, какие другие библиотеки требуются для пользователей.
Вот мой пример файла setup.py:
from setuptools import setup, find_packages
with open("README.md", "r") as readme_file:
readme = readme_file.read()
requirements = ["ipython>=6", "nbformat>=4", "nbconvert>=5", "requests>=2"]
setup(
name="notebookc",
version="0.0.1",
author="Jeff Hale",
author_email="jeffmshale@gmail.com",
description="A package to convert your Jupyter Notebook",
long_description=readme,
long_description_content_type="text/markdown",
url="https://github.com/your_package/homepage/",
packages=find_packages(),
install_requires=requirements,
classifiers=[
"Programming Language :: Python :: 3.7",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
],
)
Обратите внимание, что long_description установлен на содержимое файла README.md. Список требований (requirements), указанный в setuptools.setup.install_requires, включает в себя все необходимые зависимости для работы вашей библиотеки.
В отличие от списка библиотек, требуемых для разработки в файле require_dev.txt, этот список должен быть максимально разрешающим. Узнайте почему здесь.
Ограничьте список install_requires только тем, что Вам надо — Вам не нужно, чтобы пользователи устанавливали лишние библиотеки. Обратите внимание, что необходимо только перечислить те библиотеки, которые не являются частью стандартной библиотеки Python. У Вашего пользователя и так будет установлен Python, если он будет использовать вашу библиотеку.
Наша библиотека не требует никаких внешних зависимостей, поэтому Вы можете исключить четыре библиотеки, перечисленных в примере выше.
Соавтор, который разветвляет репозиторий проекта и устанавливает закрепленные библиотеки с помощью pip, будет иметь те же версии, что и Вы. Это значит, что они должны работать.
Измените информацию setuptools так, чтобы она соответствовала информации вашей библиотеки. Существует множество других необязательных аргументов и классификаторов ключевых слов — см. перечень здесь. Более подробные руководства по setup.py можно найти здесь и здесь.
Сохраните свой код в локальном репозитории Git. Пора переходить к созданию библиотеки!
Шаг 10: Соберите первую версию
Twine — это набор утилит для безопасной публикации библиотек Python на PyPI. Добавьте библиотеку Twine в следующую пустую строку файла require_dev.txt таким образом:
twine==1.13.0
Затем закрепите Twine в Вашей виртуальной среде, переустановив библиотеки needs_dev.txt.
pip install -r requirements_dev.txt
Затем выполните следующую команду, чтобы создать файлы библиотеки:
python setup.py sdist bdist_wheel
Необходимо создать несколько скрытых папок: dist, build и — в моем случае — notebookc.egg-info. Давайте посмотрим на файлы в папке dist. Файл .whl — это файл Wheel — встроенный дистрибутив. Файл .tar.gz является исходным архивом.
На компьютере пользователя pip будет по мере возможности устанавливать библиотеки как wheels/колеса. Они устанавливаются быстрее. Когда pip не может этого сделать, он возвращается к исходному архиву.
Давайте подготовимся к загрузке нашего колеса и исходного архива.
Шаг 11: Создайте учётную запись TestPyPI
PyPI — каталог библиотек Python (Python Package Index). Это официальный менеджер библиотек Python. Если файлы не установлены локально, pip получает их оттуда.
TestPyPI — это работающая тестовая версия PyPI. Создайте здесь учетную запись TestPyPI и подтвердите адрес электронной почты. Обратите внимание, что у Вас должны быть отдельные пароли для загрузки на тестовый сайт и официальный сайт.
Шаг 12: Опубликуйте библиотеку в PyPI
Используйте Twine для безопасной публикации вашей библиотеки в TestPyPI. Введите следующую команду — никаких изменений не требуется.
twine upload --repository-url https://test.pypi.org/legacy/ dist/*
Вам будет предложено ввести имя пользователя и пароль. Не забывайте, что TestPyPI и PyPI имеют разные пароли!
При необходимости исправьте все ошибки, создайте новый номер версии в файле setup.py и удалите старые артефакты сборки: папки build, dist и egg. Перестройте задачу с помощью python setup.py sdist bdist_wheel
и повторно загрузите с помощью Twine. Наличие номеров версий в TestPyPI, которые ничего не значат, особой роли не играют — Вы единственный, кто будет использовать эти версии библиотек.
После того, как Вы успешно загрузили свою библиотеку, давайте удостоверимся, что Вы можете установить его и использовать.
Шаг 13: Проверьте и используйте установленную библиотеку
Создайте еще одну вкладку в командном интерпретаторе и запустите другую виртуальную среду.
python3.7 -m venv my_env
Активируйте ее.
source my_env/bin/activate
Если Вы уже загрузили свою библиотеку на официальный сайт PyPI, то сможете выполнить команду pip install your-package
. Мы можем извлечь библиотеку из TestPyPI и установить его с помощью измененной команды.
Вот официальные инструкции по установке вашей библиотеки из TestPyPI:
Вы можете заставить pip загружать библиотеки из TestPyPI вместо PyPI, указав это в index-url.
pip install --index-url https://test.pypi.org/simple/ my_package
Если хотите, чтобы pip также извлекал и другие библиотеки из PyPI, Вы можете добавить — extra-index-url для указания на PyPI. Это полезно, когда тестируемая библиотека имеет зависимости:
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple my_package
Если у вашей библиотеки есть зависимости, используйте вторую команду и подставьте имя вашей библиотеки.
Вы должны увидеть последнюю версию библиотеки, установленного в Вашей виртуальной среде.
Чтобы убедиться, что Вы можете использовать свою библиотеку, запустите сеанс IPython в терминале следующим образом:
python
Импортируйте свою функцию и вызовите ее со строковым аргументом. Вот как выглядит мой код:
from notebookc.notebookc import convert
convert(“Jeff”)
После я получаю следующий вывод:
I’ll convert a notebook for you some day, Jeff.
(Когда-нибудь я конвертирую для тебя блокнот, Джефф)
Я в Вас верю.
Шаг 14: Залейте код на PyPI
Залейте Ваш код на настоящий сайт PyPI, чтобы люди могли скачать его с помощью pip install my_package
.
Загрузить код можно так:
twine upload dist/*
Обратите внимание, что Вам нужно обновить номер версии в setup.py, если Вы хотите залить новую версию в PyPI.
Отлично, теперь давайте загрузим нашу работу на GitHub.
Шаг 15: Залейте библиотеку на GitHub
Убедитесь, что Ваш код сохранен.
Моя папка проекта notebookc выглядит так:
.git
.gitignore
LICENSE
README.md
requirements_dev.txt
setup.py
notebookc/__init__.py
notebookc/notebookc.py
Исключите любые виртуальные среды, которые Вы не хотите загружать. Файл Python .gitignore, который мы выбрали при создании репозитория, не должен допускать индексации артефактов сборки. Возможно, Вам придется удалить папки виртуальной среды.
Переместите вашу локальную ветку на GitHub с помощью git push origin my_branch
.
Шаг 16: Создайте и объедините PR
В браузере перейдите к GitHub. У Вас должна появиться опция сделать pull-запрос. Нажимайте на зеленые кнопки, чтобы создать, объединить PR и чтобы убрать удаленную ветку.
Вернувшись в терминал, удалите локальную ветку с git branch -d my_feature_branch
.
Шаг 17: Обновите рабочую версию на GitHub
Создайте новую версию библиотеки на GitHub, кликнув на релизы на главной странице репозитория. Введите необходимую информацию о релизе и сохраните.
На сегодня достаточно!
Мы научимся добавлять другие файлы и папки в будущих статьях.
А пока давайте повторим шаги, которые мы разобрали.
Итог: 17 шагов к рабочей библиотеке
- Составьте план.
- Дайте имя библиотеке.
- Настройте среду.
- Создайте организацию в GitHub.
- Настройте GitHub Repo.
- Клонируйте и добавьте директории.
- Скачайте и установите requirements_dev.txt.
- Поработайте с кодом.
- Создайте setup.py.
- Соберите первую версию.
- Создайте учётную запись TestPyPI.
- Опубликуйте библиотеку в PyPI.
- Проверьте и используйте установленную библиотеку.
- Залейте код на PyPI.
- Залейте библиотеку на GitHub.
- Создайте и объедините PR.
- Обновите рабочую версию на GitHub.
Узнайте подробности, как получить востребованную профессию с нуля или Level Up по навыкам и зарплате, пройдя платные онлайн-курсы SkillFactory:
- Курс по Machine Learning (12 недель)
- Курс «Профессия Data Scientist» (24 месяца)
- Курс «Профессия Data Analyst» (18 месяцев)
- Курс «Python для веб-разработки» (9 месяцев)
Читать еще
- Крутые Data Scientist не тратят время на статистику
- Как стать Data Scientist без онлайн-курсов
- Шпаргалка по сортировке для Data Science
- Data Science для гуманитариев: что такое «data»
- Data Scienсe на стероидах: знакомство с Decision Intelligence
Добавлено 30 июля 2020 в 22:33
Содержание главы
Погружение
Вы хотите выпустить скрипт, библиотеку, фреймворк или приложение на Python? Превосходно. Миру нужно больше кода на Python. Python 3 поставляется с системой создания пакетов Distutils. Distutils – это много всего: инструмент сборки (для вас), инструмент установки (для ваших пользователей), формат метаданных пакета (для поисковых систем) и многое другое. Он интегрирован с каталогом пакетов Python PyPI, центральным репозиторием библиотек Python с открытым исходным кодом.
Все эти аспекты Distutils сосредоточены вокруг сценария установки, который обычно называется setup.py. На самом деле, вы уже видели в этой книге несколько скриптов установки Distutils. Вы использовали Distutils для установки httplib2 в HTTP веб-сервисах и еще раз для установки chardet
в главе 15 «Учебный пример: портирование chardet
на Python 3».
В данной главе вы узнаете, как работают скрипты установки для chardet
и httplib2
, и пройдете через процесс релиза своего собственного программного обеспечения на Python.
# setup.py модуля chardet
from distutils.core import setup
setup(
name = "chardet",
packages = ["chardet"],
version = "1.0.2",
description = "Universal encoding detector",
author = "Mark Pilgrim",
author_email = "mark@diveintomark.org",
url = "http://chardet.feedparser.org/",
download_url = "http://chardet.feedparser.org/download/python3-chardet-1.0.1.tgz",
keywords = ["encoding", "i18n", "xml"],
classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Development Status :: 4 - Beta",
"Environment :: Other Environment",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
"Operating System :: OS Independent",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Text Processing :: Linguistic",
],
long_description = """
Universal character encoding detector
-------------------------------------
Detects
- ASCII, UTF-8, UTF-16 (2 variants), UTF-32 (4 variants)
- Big5, GB2312, EUC-TW, HZ-GB-2312, ISO-2022-CN (Traditional and Simplified Chinese)
- EUC-JP, SHIFT_JIS, ISO-2022-JP (Japanese)
- EUC-KR, ISO-2022-KR (Korean)
- KOI8-R, MacCyrillic, IBM855, IBM866, ISO-8859-5, windows-1251 (Cyrillic)
- ISO-8859-2, windows-1250 (Hungarian)
- ISO-8859-5, windows-1251 (Bulgarian)
- windows-1252 (English)
- ISO-8859-7, windows-1253 (Greek)
- ISO-8859-8, windows-1255 (Visual and Logical Hebrew)
- TIS-620 (Thai)
This version requires Python 3 or later; a Python 2 version is available separately.
"""
)
chardet
и httplib2
имеют открытый исходный код, но нет требований, под какой-либо конкретной лицензией вам выпускать собственные библиотеки на Python. Процесс, описанный в данной главе, будет работать для любого программного обеспечения на Python, независимо от лицензии.
16.2 Вещи, которые Distutils не может сделать за вас
Релиз вашего первого пакета Python – сложный процесс (релиз второго немного проще). Distutils пытается максимально автоматизировать его, но есть некоторые вещи, которые вы просто должны сделать сами.
- Выбрать лицензию. Это сложная тема, связанная с политикой и опасностями. Если вы хотите выпустить свое программное обеспечение с открытым исходным кодом, я скромно предлагаю пять советов:
- Не пишите свою собственную лицензию.
- Не пишите свою собственную лицензию.
- Не пишите свою собственную лицензию.
- Это не обязательно должен быть GPL, но она должна быть GPL-совместимой.
- Не пишите свою собственную лицензию.
- Классифицировать свое программное обеспечение, используя систему классификации PyPI. Я объясню, что это значит позже в этой главе.
- Написать файл «прочти меня» (read me). Не экономьте на этом. Как минимум, он должен дать вашим пользователям обзор того, что делает ваше программное обеспечение и как его установить.
16.3 Структура каталогов
Чтобы начать создавать пакет программного обеспечения на Python, вам нужно привести в порядок файлы и каталоги. Каталог httplib2
выглядит так:
httplib2/ (1) | +--README.txt (2) | +--setup.py (3) | +--httplib2/ (4) | +--__init__.py | +--iri2uri.py
- Создайте корневой каталог для хранения всего. Дайте ему то же имя, что и вашему модулю на Python.
- Для удобства пользователей Windows ваш файл «readme» должен иметь расширение .txt и использовать символ возврата каретки. То, что вы используете нестандартный текстовый редактор, который запускается из командной строки и включает в себя собственный язык макросов, не означает, что вам нужно усложнить жизнь своим пользователям (ваши пользователи используют Notepad; грустно но это так). Даже если вы работаете в Linux или Mac OS X, ваш модный текстовый редактор, несомненно, имеет возможность сохранять файлы, используя символы возврата каретки в стиле Windows.
- Ваш скрипт Distutils для установки должен называться setup.py, если у вас нет веских причин так не делать. У вас нет веских причин так не делать.
- Если ваше программное обеспечение на Python представляет собой один файл .py, вы должны поместить его в корневой каталог вместе с файлом «readme» и скриптом установки. Но
httplib2
– это не один файл .py; это многофайловый модуль. Но это нормально! Просто поместите каталогhttplib2
в корневой каталог, чтобы у вас был файл __init__.py в каталоге httplib2/ в корневом каталоге httplib2/. Это не проблема; на самом деле это упростит процесс упаковки.
Каталог chardet
выглядит немного иначе. Как и httplib2
, это многофайловый модуль, поэтому в корневом каталоге chardet/ находится каталог chardet/. В дополнение к файлу README.txt, chardet
содержит документацию в формате HTML в каталоге docs/. Каталог docs/ содержит несколько файлов .html и .css и подкаталог images/, который содержит несколько файлов .png и .gif (это будет важно позднее). Также, в соответствии с соглашением для (L)GPL-лицензированного программного обеспечения, у него есть отдельный файл с именем COPYING.txt, который содержит полный текст LGPL.
chardet/ | +--COPYING.txt | +--setup.py | +--README.txt | +--docs/ | | | +--index.html | | | +--usage.html | | | +--images/ ... | +--chardet/ | +--__init__.py | +--big5freq.py | +--...
16.4 Написание скрипта установки
Скрипт установки Distutils – это скрипт на Python. Теоретически, он может делать всё, что может делать Python. На практике он должен быть как можно меньше, и как можно более стандартным. Скрипты установки должны быть скучными. Чем более экзотичен процесс установки, тем более экзотичны будут ваши сообщения об ошибках.
Первая строка каждого скрипта установки Distutils всегда одинакова:
from distutils.core import setup
Это импортирует функцию setup()
, которая является основной точкой входа в Distutils. 95% всех скриптов установки Distutils состоят из одного вызова setup()
, и ничего более. (Я только что придумал эту статистику, но если ваш скрипт установки Distutils делает больше, чем просто вызывает функцию Distutils setup()
, у вас должна быть веская причина. У вас есть веская причина? Не думаю.)
Функция setup()
может принимать десятки параметров. Чтобы все вовлеченные участники понимали, о чем идет речь, для каждого параметра вы должны использовать именованные аргументы. Это не просто соглашение; это обязательное требование. Ваш скрипт установки завершится сбоем, если вы попытаетесь вызвать функцию setup()
с неименованными аргументами.
Следующие именованные аргументы обязательны:
name
, название пакета;version
, номер версии пакета;author
, ваше полное имя;author_email
, ваш адрес электронной почты;url
, домашняя страница вашего проекта. Если у вас нет отдельного веб-сайта для проекта, то это может быть ваша страница пакета на PyPI,.
Хотя это и не обязательно, я рекомендую также включить в скрипт установки следующее:
description
, однострочное описание проекта.long_description
, многострочное описание в формате reStructuredText. PyPI преобразует его в HTML и покажет его на странице вашего пакета.classifiers
, список специально отформатированных строк, описанных в следующем разделе.
Метаданные скрипта установки определены в PEP 314.
Теперь давайте посмотрим на скрипт установки chardet
. В нем есть все эти обязательные и рекомендуемые параметры, плюс один, который я еще не упомянул: packages
.
from distutils.core import setup
setup(
name = 'chardet',
packages = ['chardet'],
version = '1.0.2',
description = 'Universal encoding detector',
author='Mark Pilgrim',
...
)
Параметр packages
указывает на неудачное совпадение слов в процессе создания дистрибутива. Мы говорим о «пакете» как о том, что вы создаете (и, возможно, включаете его в Python “Package” Index). Но этот параметр packages
относится не к этому. Он относится к тому факту, что модуль chardet
является многофайловым модулем, иногда называемым… «пакетом». Параметр packages
указывает Distutils включить каталог chardet/, его файл __init__.py и все другие файлы .py, которые составляют модуль chardet
. Это очень важно; все эти счастливые разговоры о документации и метаданных не имеют значения, если вы забудете включить реальный код!
16.5 Классификация вашего пакета
Python Package Index (PyPI) содержит тысячи библиотек на Python. Правильные метаданные классификации упростят людям поиск ваших проектов. PyPI позволяет просматривать пакеты по классификатору. Вы даже можете выбрать несколько классификаторов, чтобы сузить область поиска. Классификаторы – это не невидимые метаданные, которые вы можете просто игнорировать!
Чтобы классифицировать ваше программное обеспечение, передайте параметр classifiers
функции setup()
Distutils. Параметр classifiers
представляет собой список строк. Эти строки не являются произвольными. Все строки классификатора должны браться из этого списка на PyPI.
Классификаторы необязательны. Вы можете написать скрипт установки Distutils без каких-либо классификаторов вообще. Но не делайте так. Вы должны всегда включать, по крайней мере, следующие классификаторы:
- Programming Language (язык программирования). В частности, вы должны включить и «Programming Language :: Python«, и «Programming Language :: Python :: 3«. Если вы не включите их, ваш пакет не будет отображаться в этом списке библиотек, совместимых с Python 3.
- License (лицензия). Это первое, на что я обращаю внимание при оценке сторонних библиотек. Не заставляйте меня охотиться за этой важной информацией. Не включайте более одного классификатора лицензии, если ваше программное обеспечение явно не доступно под несколькими лицензиями. (И не выпускайте программное обеспечение под несколькими лицензиями, если не обязаны это делать. И не заставляйте других людей делать это. Лицензирование – достаточная головная боль; не усугубляйте еще больше.)
- Operating System (операционная система). Если ваше программное обеспечение работает только в Windows (или Mac OS X, или Linux), я хочу узнать об этом раньше, а не позже. Если ваше программное обеспечение работает везде без какого-либо платформозависимого кода, используйте классификатор «Operating System :: OS Independent«. Несколько классификаторов Operating System необходимы только в том случае, если вашему программному обеспечению требуется конкретная поддержка для каждой платформы (это не распространено).
Я также рекомендую вам включить следующие классификаторы:
- Development Status (состояние разработки). Ваше программное обеспечение в версии бета? В версии альфа? Пре-альфа? Выбери один из вариантов. Будьте честны.
- Intended Audience (целевая аудитория). Кто будет загружать ваше программное обеспечение? Наиболее распространенными вариантами являются Developers (разработчики), End Users/Desktop (конечные пользователи / десктоп), Science/Research (наука/исследования) and System Administrators (системные администраторы).
- Framework (фреймворк). Если ваше программное обеспечение является плагином для более крупного фреймворка Python, такого как Django или Zope, включите соответствующий классификатор Framework. Если нет, пропустите его.
- Topic (тема). Есть большое количество тем на выбор; выберите всё, что подходит.
16.5.1 Примеры хороших классификаторов пакетов
В качестве примера, вот классификаторы для Django, готового к работе, кроссплатформенного, лицензированного под BSD фреймворка веб-приложений, который работает на вашем веб-сервере.
Development Status :: 5 - Production/Stable Environment :: Web Environment Framework :: Django Intended Audience :: Developers License :: OSI Approved :: BSD License Operating System :: OS Independent Programming Language :: Python Programming Language :: Python :: 3 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3 :: Only Topic :: Internet :: WWW/HTTP Topic :: Internet :: WWW/HTTP :: Dynamic Content Topic :: Internet :: WWW/HTTP :: WSGI Topic :: Software Development :: Libraries :: Application Frameworks Topic :: Software Development :: Libraries :: Python Modules
Вот классификаторы для chardet
, библиотеки определения кодировки символов, описанной в главе 15 «Учебный пример: портирование chardet
на Python 3». chardet
– в бета-версии, кроссплатформенная, совместимая с Python 3, лицензия LGPL, и предназначена для разработчиков, чтобы интегрировать в свои собственные продукты.
Programming Language :: Python Programming Language :: Python :: 3 License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) Operating System :: OS Independent Development Status :: 4 - Beta Environment :: Other Environment Intended Audience :: Developers Topic :: Text Processing :: Linguistic Topic :: Software Development :: Libraries :: Python Modules
А вот классификаторы для httplib2
, библиотеки, представленной в главе 14 «HTTP веб-сервисы». httplib2
– в бета-версии, кроссплатформенная, с лицензией MIT, предназначена для разработчиков на Python.
Programming Language :: Python Programming Language :: Python :: 3 License :: OSI Approved :: MIT License Operating System :: OS Independent Development Status :: 4 - Beta Environment :: Web Environment Intended Audience :: Developers Topic :: Internet :: WWW/HTTP Topic :: Software Development :: Libraries :: Python Modules
16.6 Указание дополнительных файлов с помощью манифеста
По умолчанию Distutils будет включать в ваш пакет следующие файлы:
- README.txt
- setup.py
- Файлы .py, необходимые для многофайловых модулей, перечисленных в параметре
packages
- Отдельные .py файлы, перечисленные в параметре
py_modules
Это охватывает все файлы в проекте httplib2
. Но для проекта chardet
мы также хотим включить файл лицензии COPYING.txt и весь каталог docs/, содержащий изображения и HTML файлы. Чтобы указать Distutils, чтобы он при сборке пакета chardet
включил эти дополнительные файлы и каталоги, вам понадобится файл манифеста.
Файл манифеста – это текстовый файл с именем MANIFEST.in. Поместите его в корневой каталог проекта, рядом с README.txt и setup.py. Файлы манифеста – это не скрипты Python; это текстовые файлы, которые содержат серию «команд» в формате, определенном Distutils. Команды манифеста позволяют включать или исключать определенные файлы и каталоги.
Это весь файл манифеста для проекта chardet
:
include COPYING.txt (1)
recursive-include docs *.html *.css *.png *.gif (2)
- Строка 1. Первая строка не требует пояснений: включить файл COPYING.txt из корневого каталога проекта.
- Строка 2. Вторая строка немного сложнее. Команда
recursive-include
принимает имя каталога и одно или несколько имен файлов. Имена файлов не ограничены конкретными файлами; они могут включать подстановочные знаки. Эта строка означает «Видите этот каталог docs/ в корневом каталоге проекта? Ищите там (рекурсивно) файлы .html, .css, .png и .gif. Я хочу, чтобы все они были в релизе моего пакета.»
Все команды манифеста сохраняют структуру каталогов, заданную вами в каталоге вашего проекта. Эта команда recursive-include
не собирается помещать кучу файлов .html и .png в корневой каталог выпускаемого пакета. Она сохранит существующую структуру каталога docs/, но включая в себя только те файлы в этом каталоге, которые соответствуют заданным подстановочным символам. (Я не упоминал об этом ранее, но документация chardet
на самом деле написана в формате XML и преобразована в HTML отдельным скриптом. Я не хочу включать файлы XML в релиз пакета, мне нужны только HTML и изображения.)
Повторим: вам нужно создавать файл манифеста, только если вы хотите включить файлы, которые Distutils не включает по умолчанию. Если вам нужен файл манифеста, он должен включать только те файлы и каталоги, которые Distutils не смог бы найти самостоятельно.
16.7 Проверка вашего скрипта установки на наличие ошибок
Есть много чего, что нужно отслеживать. Distutils поставляется со встроенной командой проверки, которая проверяет в вашем скрипте установки наличие всех необходимых метаданных. Например, если вы забудете включить параметр version
, Distutils напомнит вам.
c:Userspilgrimchardet> c:python31python.exe setup.py check
running check
warning: check: missing required meta-data: version
После того, как вы добавите параметр version
(и все остальные необходимые метаданные), результат команды check
будет выглядеть следующим образом:
c:Userspilgrimchardet> c:python31python.exe setup.py check
running check
16.8 Создание дистрибутива исходников
Distutils поддерживает сборку различных типов пакетов. Как минимум, вы должны создать «дистрибутив исходников», который содержит ваш исходный код, ваш скрипт установки Distutils, ваш файл «read me» и все дополнительные файлы, которые вы хотите включить. Чтобы создать дистрибутив исходников, передайте в ваш скрипт установки Distutils команду sdist
.
c:Userspilgrimchardet> c:python31python.exe setup.py sdist
running sdist
running check
reading manifest template 'MANIFEST.in'
writing manifest file 'MANIFEST'
creating chardet-1.0.2
creating chardet-1.0.2chardet
creating chardet-1.0.2docs
creating chardet-1.0.2docsimages
copying files to chardet-1.0.2...
copying COPYING -> chardet-1.0.2
copying README.txt -> chardet-1.0.2
copying setup.py -> chardet-1.0.2
copying chardet__init__.py -> chardet-1.0.2chardet
copying chardetbig5freq.py -> chardet-1.0.2chardet
...
copying chardetuniversaldetector.py -> chardet-1.0.2chardet
copying chardetutf8prober.py -> chardet-1.0.2chardet
copying docsfaq.html -> chardet-1.0.2docs
copying docshistory.html -> chardet-1.0.2docs
copying docshow-it-works.html -> chardet-1.0.2docs
copying docsindex.html -> chardet-1.0.2docs
copying docslicense.html -> chardet-1.0.2docs
copying docssupported-encodings.html -> chardet-1.0.2docs
copying docsusage.html -> chardet-1.0.2docs
copying docsimagescaution.png -> chardet-1.0.2docsimages
copying docsimagesimportant.png -> chardet-1.0.2docsimages
copying docsimagesnote.png -> chardet-1.0.2docsimages
copying docsimagespermalink.gif -> chardet-1.0.2docsimages
copying docsimagestip.png -> chardet-1.0.2docsimages
copying docsimageswarning.png -> chardet-1.0.2docsimages
creating dist
creating 'distchardet-1.0.2.zip' and adding 'chardet-1.0.2' to it
adding 'chardet-1.0.2COPYING'
adding 'chardet-1.0.2PKG-INFO'
adding 'chardet-1.0.2README.txt'
adding 'chardet-1.0.2setup.py'
adding 'chardet-1.0.2chardetbig5freq.py'
adding 'chardet-1.0.2chardetbig5prober.py'
...
adding 'chardet-1.0.2chardetuniversaldetector.py'
adding 'chardet-1.0.2chardetutf8prober.py'
adding 'chardet-1.0.2chardet__init__.py'
adding 'chardet-1.0.2docsfaq.html'
adding 'chardet-1.0.2docshistory.html'
adding 'chardet-1.0.2docshow-it-works.html'
adding 'chardet-1.0.2docsindex.html'
adding 'chardet-1.0.2docslicense.html'
adding 'chardet-1.0.2docssupported-encodings.html'
adding 'chardet-1.0.2docsusage.html'
adding 'chardet-1.0.2docsimagescaution.png'
adding 'chardet-1.0.2docsimagesimportant.png'
adding 'chardet-1.0.2docsimagesnote.png'
adding 'chardet-1.0.2docsimagespermalink.gif'
adding 'chardet-1.0.2docsimagestip.png'
adding 'chardet-1.0.2docsimageswarning.png'
removing 'chardet-1.0.2' (and everything under it)
Несколько замечаний:
- Distutils заметил файл манифеста (MANIFEST.in).
- Distutils успешно проанализировал файл манифеста и добавил нужные нам файлы: COPYING.txt, а также HTML файлы и изображения в каталоге docs/.
- Если вы загляните в каталог вашего проекта, вы увидите, что Distutils создал каталог dist/. В этом каталоге dist/ находится .zip-файл, который вы можете распространять.
c:Userspilgrimchardet> dir dist
Volume in drive C has no label.
Volume Serial Number is DED5-B4F8
Directory of c:Userspilgrimchardetdist
07/30/2009 06:29 PM <DIR> .
07/30/2009 06:29 PM <DIR> ..
07/30/2009 06:29 PM 206,440 chardet-1.0.2.zip
1 File(s) 206,440 bytes
2 Dir(s) 61,424,635,904 bytes free
16.9 Создание графического установщика
По-моему, каждая библиотека Python заслуживает наличие графического установщика для пользователей Windows. Его легко обеспечить (даже если вы сами не работаете под Windows), а пользователи Windows это ценят.
Distutils может создать для вас графический установщик Windows, если передадите в ваш скрипт установки Distutils команду bdist_wininst
.
c:Userspilgrimchardet> c:python31python.exe setup.py bdist_wininst
running bdist_wininst
running build
running build_py
creating build
creating buildlib
creating buildlibchardet
copying chardetbig5freq.py -> buildlibchardet
copying chardetbig5prober.py -> buildlibchardet
...
copying chardetuniversaldetector.py -> buildlibchardet
copying chardetutf8prober.py -> buildlibchardet
copying chardet__init__.py -> buildlibchardet
installing to buildbdist.win32wininst
running install_lib
creating buildbdist.win32
creating buildbdist.win32wininst
creating buildbdist.win32wininstPURELIB
creating buildbdist.win32wininstPURELIBchardet
copying buildlibchardetbig5freq.py -> buildbdist.win32wininstPURELIBchardet
copying buildlibchardetbig5prober.py -> buildbdist.win32wininstPURELIBchardet
...
copying buildlibchardetuniversaldetector.py -> buildbdist.win32wininstPURELIBchardet
copying buildlibchardetutf8prober.py -> buildbdist.win32wininstPURELIBchardet
copying buildlibchardet__init__.py -> buildbdist.win32wininstPURELIBchardet
running install_egg_info
Writing buildbdist.win32wininstPURELIBchardet-1.0.2-py3.1.egg-info
creating 'c:userspilgrimappdatalocaltemptmp2f4h7e.zip' and adding '.' to it
adding 'PURELIBchardet-1.0.2-py3.1.egg-info'
adding 'PURELIBchardetbig5freq.py'
adding 'PURELIBchardetbig5prober.py'
...
adding 'PURELIBchardetuniversaldetector.py'
adding 'PURELIBchardetutf8prober.py'
adding 'PURELIBchardet__init__.py'
removing 'buildbdist.win32wininst' (and everything under it)
c:Userspilgrimchardet> dir dist
c:Userspilgrimchardet>dir dist
Volume in drive C has no label.
Volume Serial Number is AADE-E29F
Directory of c:Userspilgrimchardetdist
07/30/2009 10:14 PM <DIR> .
07/30/2009 10:14 PM <DIR> ..
07/30/2009 10:14 PM 371,236 chardet-1.0.2.win32.exe
07/30/2009 06:29 PM 206,440 chardet-1.0.2.zip
2 File(s) 577,676 bytes
2 Dir(s) 61,424,070,656 bytes free
16.9.1 Сборка устанавливаемых пакетов для других операционных систем
Distutils может помочь вам создать устанавливаемые пакеты для пользователей Linux. На мой взгляд, возможно, это не стоит вашего времени. Если вы хотите, чтобы ваше программное обеспечение распространялось для Linux, вам лучше было бы потратить время на работу с членами сообщества, которые специализируются на создании пакетов программного обеспечения для основных дистрибутивов Linux.
Например, моя библиотека chardet
находится в репозиториях Debian GNU/Linux (и, следовательно, в репозиториях Ubuntu). Я не имел ничего общего с этим; пакеты просто появились там однажды. Сообщество Debian имеет свои собственные политики для создания пакетов библиотек Python, а пакет Debian python-chardet разработан в соответствии с этими соглашениями. А поскольку пакет находится в репозиториях Debian, пользователи Debian будут получать обновления безопасности и/или новые версии в зависимости от общесистемных настроек, выбранных ими для управления своими компьютерами.
Пакеты Linux, которые собирает Distutils, не предлагают ни одно из этих преимуществ. Лучше потратить время на что-то другое.
16.10 Добавление вашего программного обеспечения в Python Package Index
Загрузка программного обеспечения в Python Package Index состоит из трех этапов.
- зарегистрируетесь сами;
- зарегистрируйте свое программное обеспечение;
- загрузите пакеты, которые вы создали с помощью
setup.py sdist
иsetup.py bdist_ *
.
Чтобы зарегистрироваться, перейдите на страницу регистрации пользователя PyPI. Введите имя пользователя и пароль, укажите действующий адрес электронной почты и нажмите кнопку «Create account». (Если у вас есть ключ PGP или GPG, можете также предоставить его. Если у вас его нет или вы не знаете, что это такое, то не беспокойтесь об этом.) Проверьте свою электронную почту; в течение нескольких минут вы получите сообщение от PyPI со ссылкой для проверки. Нажмите на ссылку, чтобы завершить процесс регистрации.
Теперь вам нужно зарегистрировать свое программное обеспечение в PyPI и загрузить его. Вы можете сделать всё это за один шаг.
c:Userspilgrimchardet> c:python31python.exe setup.py register sdist bdist_wininst upload ①
running register
We need to know who you are, so please choose either:
1. use your existing login,
2. register as a new user,
3. have the server generate a new password for you (and email it to you), or
4. quit
Your selection [default 1]: 1 ②
Username: MarkPilgrim ③
Password:
Registering chardet to http://pypi.python.org/pypi ④
Server response (200): OK
running sdist ⑤
... output trimmed for brevity ...
running bdist_wininst ⑥
... output trimmed for brevity ...
running upload ⑦
Submitting distchardet-1.0.2.zip to http://pypi.python.org/pypi
Server response (200): OK
Submitting distchardet-1.0.2.win32.exe to http://pypi.python.org/pypi
Server response (200): OK
I can store your PyPI login so future submissions will be faster.
(the login will be stored in c:home.pypirc)
Save your login (y/N)?n ⑧
- Строка 1. Когда вы публикуете свой проект впервые, Distutils добавит ваше программное обеспечение в Python Package Index и присвоит ему собственный URL. Каждый раз после этого он будет просто обновлять метаданные проекта с любыми изменениями, которые вы могли внести в параметры setup.py. Затем он создает дистрибутив исходного кода (
sdist
) и установщик Windows (bdist_wininst
), а затем загружает их в PyPI (upload
). - Строка 8. Введите 1 или просто нажмите ENTER, чтобы выбрать «использовать существующий логин».
- Строка 9. Введите имя пользователя и пароль, которые вы выбрали на странице регистрации пользователя PyPI. Distuils не будет выводить ваш пароль; он даже не будет отражать звездочки вместо символов. Просто введите свой пароль и нажмите клавишу ENTER.
- Строка 11. Distutils регистрирует ваш пакет в Python Package Index…
- Строка 13. … собирает ваш дистрибутив исходного кода…
- Строка 15. … собирает ваш установщик Windows…
- Строка 17. … и загружает их обоих в Python Package Index.
- Строка 24. Если вы хотите автоматизировать процесс релиза новых версий, то вам нужно сохранить свои учетные данные PyPI в локальном файле. Это совершенно небезопасно и совершенно необязательно.
Поздравляем, теперь у вас есть собственная страница в Python Package Index! Ее адрес: http://pypi.python.org/pypi/NAME, где NAME – это строка, которую вы передали в параметре name
в файле setup.py.
Если вы хотите выпустить новую версию, просто обновите в вашем файле setup.py номер версии, а затем снова выполните ту же команду загрузки:
c:Userspilgrimchardet> c:python31python.exe setup.py register sdist bdist_wininst upload
16.11 Множество возможных вариантов создания пакетов Python
Distutils не является единственным инструментом создания пакетов Python, но на момент написания этой статьи (август 2009 года) это единственный фреймворк создания пакетов, который работает в Python 3. Существует ряд других платформ для Python 2; некоторые фокусируются на установке, другие – на тестировании и развертывании. Некоторые или все из них могут в конечном итоге быть перенесены на Python 3 в будущем.
Эти фреймворки ориентированы на установку:
- Setuptools (портирован)
- Pip (портирован)
- Distribute
Эти сосредоточены на тестировании и развертывании:
virtualenv
(портирован)zc.buildout
(портирован)- Paver
- Fabric (портирован)
py2exe
(портирован)
16.12 Материалы для дальнейшего чтения
О Distutils:
- Distributing Python Modules with Distutils
- Core Distutils functionality список всех возможных аргументов функции
setup()
- Distutils Cookbook
- PEP 370: Per user
site-packages
directory - PEP 370 and “environment stew”
О других фреймворках создания пакетов:
- The Python packaging ecosystem
- On packaging
- A few corrections to “On packaging”
- Why I like Pip
- Python packaging: a few observations
- Nobody expects Python packaging!
Теги
PythonВысокоуровневые языки программированияОбучениеЯзыки программирования
Python — отличный язык программирования, но упаковка — один из его слабых мест. Это общеизвестный факт в обществе. Установка, импорт, использование и создание пакетов значительно улучшились за эти годы, но это все еще не на одном уровне с новыми языками, такими как Go и Rust, которые многому научились из борьбы Python и других зрелых языков.
В этом руководстве вы узнаете все, что вам нужно знать о написании, упаковке и распространении ваших собственных пакетов.
Как написать библиотеку Python
Библиотека Python — это связная коллекция модулей Python, организованная в виде пакета Python. В общем, это означает, что все модули находятся в одном каталоге и этот каталог находится в пути поиска Python.
Давайте быстро напишем небольшой пакет Python 3 и проиллюстрируем все эти концепции.
Пакет патологии
Python 3 имеет отличный объект Path, который является огромным улучшением по сравнению с неуклюжим модулем Python 2 os.path. Но ему не хватает одной важной возможности — найти путь к текущему сценарию. Это очень важно, когда вы хотите найти файлы доступа относительно текущего скрипта.
Во многих случаях сценарий может быть установлен в любом месте, поэтому вы не можете использовать абсолютные пути, а рабочему каталогу может быть присвоено любое значение, поэтому вы не можете использовать относительный путь. Если вы хотите получить доступ к файлу в подкаталоге или родительском каталоге, вы должны быть в состоянии выяснить текущий каталог скриптов.
Вот как вы делаете это в Python:
1 2 3 |
import pathlib script_dir = pathlib.Path(__file__).parent.resolve() |
Для доступа к файлу с именем file.txt в подкаталоге data текущего каталога скрипта вы можете использовать следующий код: print(open(str(script_dir/'data/file.txt').read())
С пакетом pathology у вас есть встроенный метод script_dir , и вы используете его следующим образом:
1 2 3 |
from pathology.Path import script_dir print(open(str(script_dir()/’data/file.txt’).read()) |
Да, это полный рот. Пакет патологии очень прост. Он извлекает свой собственный класс Path из Pathlib’s Path и добавляет статический script_dir (), который всегда возвращает путь вызывающего скрипта.
Вот реализация:
1 2 3 4 5 6 7 8 9 |
import pathlib import inspect class Path(type(pathlib.Path())): @staticmethod def script_dir(): print(inspect.stack()[1].filename) p = pathlib.Path(inspect.stack()[1].filename) return p.parent.resolve() |
Из-за кросс-платформенной реализации pathlib.Path , вы можете наследовать его напрямую и должны наследовать от определенного подкласса ( PosixPath или WindowsPath ). Разрешение dir скрипта использует модуль inspect для поиска вызывающего абонента, а затем его атрибута имени файла.
Тестирование пакета патологии
Всякий раз, когда вы пишете что-то большее, чем просто сценарий, вы должны проверить это. Модуль патологии не является исключением. Вот тесты, использующие стандартную структуру модульных тестов:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import os import shutil from unittest import TestCase from pathology.path import Path class PathTest(TestCase): def test_script_dir(self): expected = os.path.abspath(os.path.dirname(__file__)) actual = str(Path.script_dir()) self.assertEqual(expected, actual) def test_file_access(self): script_dir = os.path.abspath(os.path.dirname(__file__)) subdir = os.path.join(script_dir, ‘test_data’) if Path(subdir).is_dir(): shutil.rmtree(subdir) os.makedirs(subdir) file_path = str(Path(subdir)/’file.txt’) content = ‘123’ open(file_path, ‘w’).write(content) test_path = Path.script_dir()/subdir/’file.txt’ actual = open(str(test_path)).read() self.assertEqual(content, actual) |
Путь Питона
Пакеты Python должны быть установлены где-то на пути поиска Python для импорта модулями Python. Путь поиска Python представляет собой список каталогов и всегда доступен в sys.path
. Вот мой текущий sys.path:
1 2 3 4 5 6 7 |
>>> print(‘n’.join(sys.path)) /Users/gigi.sayfan/miniconda3/envs/py3/lib/python36.zip /Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6 /Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6/lib-dynload /Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6/site-packages /Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6/site-packages/setuptools-27.2.0-py3.6.egg |
Обратите внимание, что первая пустая строка вывода представляет текущий каталог, поэтому вы можете импортировать модули из текущего рабочего каталога, каким бы он ни был. Вы можете напрямую добавлять или удалять каталоги в / из sys.path.
Вы также можете определить переменную среды PYTHONPATH , и есть несколько других способов управления ею. Стандартные site-packages
включены по умолчанию, и именно здесь вы устанавливаете пакеты с помощью pip go.
Как упаковать библиотеку Python
Теперь, когда у нас есть наш код и тесты, давайте упаковываем все это в правильную библиотеку. Python предоставляет простой способ через модуль установки. Вы создаете файл с именем setup.py в корневом каталоге вашего пакета. Затем, чтобы создать исходный дистрибутив, вы запускаете: python setup.py sdist
Чтобы создать бинарный дистрибутив, называемый колесом, вы запускаете: python setup.py bdist_wheel
Вот файл setup.py пакета патологии:
01 02 03 04 05 06 07 08 09 10 11 12 |
from setuptools import setup, find_packages setup(name=’pathology’, version=’0.1′, url=’https://github.com/the-gigi/pathology’, license=’MIT’, author=’Gigi Sayfan’, author_email=’the.gigi@gmail.com’, description=’Add static script_dir() method to Path’, packages=find_packages(exclude=[‘tests’]), long_description=open(‘README.md’).read(), zip_safe=False) |
Он включает в себя множество метаданных в дополнение к элементу «packages», который использует find_packages()
импортированную из setuptools
для поиска find_packages()
.
Давайте создадим исходный дистрибутив:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
$ python setup.py sdist running sdist running egg_info creating pathology.egg-info writing pathology.egg-info/PKG-INFO writing dependency_links to pathology.egg-info/dependency_links.txt writing top-level names to pathology.egg-info/top_level.txt writing manifest file ‘pathology.egg-info/SOURCES.txt’ reading manifest file ‘pathology.egg-info/SOURCES.txt’ writing manifest file ‘pathology.egg-info/SOURCES.txt’ warning: sdist: standard file not found: should have one of README, README.rst, README.txt running check creating pathology-0.1 creating pathology-0.1/pathology creating pathology-0.1/pathology.egg-info copying files to pathology-0.1… copying setup.py -> pathology-0.1 copying pathology/__init__.py -> pathology-0.1/pathology copying pathology/path.py -> pathology-0.1/pathology copying pathology.egg-info/PKG-INFO -> pathology-0.1/pathology.egg-info copying pathology.egg-info/SOURCES.txt -> pathology-0.1/pathology.egg-info copying pathology.egg-info/dependency_links.txt -> pathology-0.1/pathology.egg-info copying pathology.egg-info/not-zip-safe -> pathology-0.1/pathology.egg-info copying pathology.egg-info/top_level.txt -> pathology-0.1/pathology.egg-info Writing pathology-0.1/setup.cfg creating dist Creating tar archive removing ‘pathology-0.1’ (and everything under it) |
Предупреждение связано с тем, что я использовал нестандартный файл README.md. Это безопасно игнорировать. Результатом является tar-gzipped файл в каталоге dist:
1 2 3 4 5 |
$ ls -la dist total 8 drwxr-xr-x 3 gigi.sayfan gigi.sayfan 102 Apr 18 21:20 . drwxr-xr-x 12 gigi.sayfan gigi.sayfan 408 Apr 18 21:20 .. -rw-r—r— 1 gigi.sayfan gigi.sayfan 1223 Apr 18 21:20 pathology-0.1.tar.gz |
А вот бинарный дистрибутив:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
$ python setup.py bdist_wheel running bdist_wheel running build running build_py creating build creating build/lib creating build/lib/pathology copying pathology/__init__.py -> build/lib/pathology copying pathology/path.py -> build/lib/pathology installing to build/bdist.macosx-10.7-x86_64/wheel running install running install_lib creating build/bdist.macosx-10.7-x86_64 creating build/bdist.macosx-10.7-x86_64/wheel creating build/bdist.macosx-10.7-x86_64/wheel/pathology copying build/lib/pathology/__init__.py -> build/bdist.macosx-10.7-x86_64/wheel/pathology copying build/lib/pathology/path.py -> build/bdist.macosx-10.7-x86_64/wheel/pathology running install_egg_info running egg_info writing pathology.egg-info/PKG-INFO writing dependency_links to pathology.egg-info/dependency_links.txt writing top-level names to pathology.egg-info/top_level.txt reading manifest file ‘pathology.egg-info/SOURCES.txt’ writing manifest file ‘pathology.egg-info/SOURCES.txt’ Copying pathology.egg-info to build/bdist.macosx-10.7-x86_64/wheel/pathology-0.1-py3.6.egg-info running install_scripts creating build/bdist.macosx-10.7-x86_64/wheel/pathology-0.1.dist-info/WHEEL |
Пакет pathology содержит только чистые модули Python, поэтому можно создать универсальный пакет. Если ваш пакет включает расширения C, вам придется создать отдельное колесо для каждой платформы:
1 2 3 4 5 6 |
$ ls -la dist total 16 drwxr-xr-x 4 gigi.sayfan gigi.sayfan 136 Apr 18 21:24 . drwxr-xr-x 13 gigi.sayfan gigi.sayfan 442 Apr 18 21:24 .. -rw-r—r— 1 gigi.sayfan gigi.sayfan 2695 Apr 18 21:24 pathology-0.1-py3-none-any.whl -rw-r—r— 1 gigi.sayfan gigi.sayfan 1223 Apr 18 21:20 pathology-0.1.tar.gz |
Чтобы глубже погрузиться в тему упаковки библиотек Python, ознакомьтесь с разделом Как написать свой собственный пакет Python .
Как распространять пакет Python
Python имеет центральное хранилище пакетов, называемое PyPI (индекс пакетов Python). Когда вы устанавливаете пакет Python с помощью pip, он загружает пакет из PyPI (если вы не укажете другой репозиторий). Чтобы распространять наш пакет патологий, нам нужно загрузить его в PyPI и предоставить некоторые дополнительные метаданные, необходимые PyPI. Шаги:
- Создайте аккаунт на PyPI (только один раз).
- Зарегистрируйте свой пакет.
- Загрузите свой пакет.
Завести аккаунт
Вы можете создать учетную запись на сайте PyPI . Затем создайте файл .pypirc в вашем домашнем каталоге:
1 2 3 4 5 6 |
[distutils] index-servers=pypi [pypi] repository = https://pypi.python.org/pypi username = the_gigi |
В целях тестирования вы можете добавить индексный сервер «pypitest» к вашему. файл pypirc :
01 02 03 04 05 06 07 08 09 10 11 12 |
[distutils] index-servers= pypi pypitest [pypitest] repository = https://testpypi.python.org/pypi username = the_gigi [pypi] repository = https://pypi.python.org/pypi username = the_gigi |
Зарегистрируйте свой пакет
Если это первый выпуск вашего пакета, вам необходимо зарегистрировать его в PyPI. Используйте команду register из setup.py. Он попросит вас ввести пароль. Обратите внимание, что я указываю на тестовый репозиторий здесь:
01 02 03 04 05 06 07 08 09 10 11 12 |
$ python setup.py register -r pypitest running register running egg_info writing pathology.egg-info/PKG-INFO writing dependency_links to pathology.egg-info/dependency_links.txt writing top-level names to pathology.egg-info/top_level.txt reading manifest file ‘pathology.egg-info/SOURCES.txt’ writing manifest file ‘pathology.egg-info/SOURCES.txt’ running check Password: Registering pathology to https://testpypi.python.org/pypi Server response (200): OK |
Загрузить свой пакет
Теперь, когда пакет зарегистрирован, мы можем загрузить его. Я рекомендую использовать шпагат , который является более безопасным. Установите его, как обычно, используя pip install twine
. Затем загрузите вашу посылку, используя шпагат, и введите свой пароль (отредактировано ниже):
1 2 3 4 5 6 |
$ twine upload -r pypitest -p <redacted> dist/* Uploading distributions to https://testpypi.python.org/pypi Uploading pathology-0.1-py3-none-any.whl [================================] 5679/5679 — 00:00:02 Uploading pathology-0.1.tar.gz [================================] 4185/4185 — 00:00:01 |
Чтобы глубже погрузиться в тему распространения ваших пакетов, ознакомьтесь с разделом Как поделиться своими пакетами Python .
Вывод
В этом уроке мы прошли полный процесс написания библиотеки Python, ее упаковки и распространения через PyPI. К этому моменту у вас должны быть все инструменты для написания ваших библиотек и обмена ими со всем миром.
Кроме того, не стесняйтесь посмотреть, что у нас есть в наличии для продажи и для изучения на рынке , и, пожалуйста, задавайте любые вопросы и оставляйте ценные отзывы, используя канал ниже.
Трудно представить программу Python без набора операторов import
. Но как опубликовать библиотеку, чтобы её также легко могли импортировать другие разработчики?
В этом руководстве мы покажем на примере, как создать собственную библиотеку Python, которую можно будет установить с помощью менеджера пакетов pip
, как другие сторонние решения. Если ваш код может приносить пользу, это отличный способ внести вклад в сообщество Python. Любой разработчик сможет установить пакет и импортировать его.
1. Создаём элементы библиотеки
Публикация пакета требует знания некоторых деталей. В этом примере мы будем рассматривать предварительно опубликованный пакет под названием dist_alx
. Чтобы вам было удобнее сверяться, эта директория доступна в виде zip-папки в репозитории на GitHub.
Каталог содержит все необходимые элементы, которые должен иметь пакет перед публикацией. Мы будем использовать этот пример в качестве эталона, поскольку все пакеты Python должны иметь одинаковую структуру. Если вам интересно, что именно делает пакет dist_alx
, это объяснено там же в README-файле.
Корневой каталог dist_alx
содержит следующие файлы и директории:
setup.py
– содержит метаданные пакета,
setup.cfg
– конфигурационный файл, используемый для хранения настроек,
- подпапку с тем же именем, что и родительская папка (в данном примере
dist_alx
), где хранится фактический код вашего пакета на Python.
Подробнее об указанных файлах можно прочитать в документации библиотеки setuptools. Примеры содержания файлов в нашем случае:
from setuptools import setup
setup(name='dist_alx',
version='0.0',
description='Gaussian and Binomial distributions',
packages=['dist_alx'],
author_email='mihajlovic.aleksa@gmail.com',
zip_safe=False)
[egg_info]
tag_build =
tag_date = 0
Любая публикуемая на PyPI библиотека обязана иметь три вышеуказанных элемента. Помимо этого, пакет должен выполнять следующие условия:
- Уникальное имя библиотеки. Никакие два существующих пакета Python не могут одинаково называться.
- Файл
setup.py
должен содержать параметрыname
иpackages
. Они также должны иметь то же имя, что и пакет (см. пример выше). - Параметр
version
: в случае если что-то в пакете изменилось, нужно изменить и значениеversion
. - Файла
setup.py
должен иметь параметрauthor_email
с адресом электронной почты для связи. Используйте действующий e-mail, это важно для дальнейшей регистрации программы в репозитории PyPI.
2. Подготавливаем код
Как указано выше, внутри вложенной папки должен находиться фактический код библиотеки. Если вы откроете подпапку dist_alx
, вы увидите, что она содержит файл _init_.py
. По умолчанию ядро Python ищет файл _init_.py
в качестве отправной точки при чтении кода. Файл _init_.py
связан со всеми другими сценариями Python в подпапке. Например, в нашем файле _init_.py
, есть строка импорта from .Gaussiandistribution import Gaussian
. Все .py-файлы связаны. Хорошей идеей, прежде чем пытаться написать код пакета, будет обновить свои знания о классах Python.
Большинство общедоступных пакетов Python хранятся в репозитории PyPI. При установке пакета на свой компьютер инструкцией pip
, вы фактически скачиваете его из репозитория PyPI. Соответственно для публикации нового пакета его нужно наоборот, загрузить на сервер PyPI. Чтобы опубликовать библиотеку, нужно завести аккаунт (это бесплатно). Адрес электронной почты должен быть тот же, что внутри setup.py
в параметре author_email
.
4. Публикуем библиотеку
Публикация осуществляется из командной строки или терминала. Команды идентичны в Windows и Linux.
Для публикации нам потребуется установить две библиотеки – setuptools
и twine
:
pip install setuptools
pip install twine
Переходим к родительскому каталогу.
Развёртываем пакет запустив setup.py
:
python setup.py sdist
Обратите внимание, что теперь в родительской папке будут созданы две новых директории (egg-info
и dist
).
Теперь с помощью twine
развёртываем пакет на PyPI:
twine upload dist/*
Здесь нужно указать своё имя пользователя и пароль PyPI.
Вуаля! Пакет размещён на сервере и готов к использованию!
Переходим в учётную запись на PyPI, идём в раздел Your projects. Если всё в порядке, вы увидите библиотеку.
Обратите внимание, что PyPI не поддерживает на сайте символ подчёркивания в именах файлов. Поэтому dist_alx
отображается как dist-alx
. Однако это не влияет на использование библиотеки – при последующем импорте мы будем вводить, как и задумано, dist_alx
.
5. Используем
Переходим к любимому клиенту Python (например, Jupyter) и устанавливаем пакет с помощью pip
. Импортируем и пользуемся в своё удовольствие!
Заключение
Прежде чем размещать пакет на главном сервере, опубликуйте его сначала на тестовом сервере PyPI.
Итак, последовательность создания библиотеки Python следующая:
- Изготовление необходимых элементов упаковки, проверка значений параметров.
- Подготовка кода пакета.
- Создание учётной записи PyPI (если её ещё не было).
- Публикация пакета на PyPI.
- Тестирование: pip-установка, импорт и запуск модуля.
Если вы думаете, что пока не готовы публиковать свою библиотеку, вам могут быть полезны такие наши публикации:
- Погружаемся в основы и нюансы тестирования Python-кода
- Инструменты для анализа кода Python. Часть 1
- Инструменты для анализа кода Python. Часть 2
- Python: практики для написания эффективного кода
Источники
- https://towardsdatascience.com/make-your-own-python-package-6d08a400fc2d
Работа с модулями: создание, подключение инструкциями import и from
Модулем в Python называется любой файл с программой (да-да, все те программы, которые вы писали, можно назвать модулями). В этой статье мы поговорим о том, как создать модуль, и как подключить модуль, из стандартной библиотеки или написанный вами.
Каждая программа может импортировать модуль и получить доступ к его классам, функциям и объектам. Нужно заметить, что модуль может быть написан не только на Python, а например, на C или C++.
Подключение модуля из стандартной библиотеки
Подключить модуль можно с помощью инструкции import. К примеру, подключим модуль os для получения текущей директории:
После ключевого слова import указывается название модуля. Одной инструкцией можно подключить несколько модулей, хотя этого не рекомендуется делать, так как это снижает читаемость кода. Импортируем модули time и random.
После импортирования модуля его название становится переменной, через которую можно получить доступ к атрибутам модуля. Например, можно обратиться к константе e, расположенной в модуле math:
Стоит отметить, что если указанный атрибут модуля не будет найден, возбудится исключение AttributeError. А если не удастся найти модуль для импортирования, то ImportError.
Использование псевдонимов
Если название модуля слишком длинное, или оно вам не нравится по каким-то другим причинам, то для него можно создать псевдоним, с помощью ключевого слова as.
Теперь доступ ко всем атрибутам модуля math осуществляется только с помощью переменной m, а переменной math в этой программе уже не будет (если, конечно, вы после этого не напишете import math, тогда модуль будет доступен как под именем m, так и под именем math).
Инструкция from
Подключить определенные атрибуты модуля можно с помощью инструкции from. Она имеет несколько форматов:
Первый формат позволяет подключить из модуля только указанные вами атрибуты. Для длинных имен также можно назначить псевдоним, указав его после ключевого слова as.
Импортируемые атрибуты можно разместить на нескольких строках, если их много, для лучшей читаемости кода:
Второй формат инструкции from позволяет подключить все (точнее, почти все) переменные из модуля. Для примера импортируем все атрибуты из модуля sys:
Следует заметить, что не все атрибуты будут импортированы. Если в модуле определена переменная __all__ (список атрибутов, которые могут быть подключены), то будут подключены только атрибуты из этого списка. Если переменная __all__ не определена, то будут подключены все атрибуты, не начинающиеся с нижнего подчёркивания. Кроме того, необходимо учитывать, что импортирование всех атрибутов из модуля может нарушить пространство имен главной программы, так как переменные, имеющие одинаковые имена, будут перезаписаны.
Создание своего модуля на Python
Теперь пришло время создать свой модуль. Создадим файл mymodule.py, в которой определим какие-нибудь функции:
Теперь в этой же папке создадим другой файл, например, main.py:
Поздравляю! Вы сделали свой модуль! Напоследок отвечу ещё на пару вопросов, связанных с созданием модулей:
Как назвать модуль?
Помните, что вы (или другие люди) будут его импортировать и использовать в качестве переменной. Модуль нельзя именовать также, как и ключевое слово (их список можно посмотреть тут). Также имена модулей нельзя начинать с цифры. И не стоит называть модуль также, как какую-либо из встроенных функций. То есть, конечно, можно, но это создаст большие неудобства при его последующем использовании.
Я вижу, что есть некоторые встроенные пакеты, которые я могу импортировать из любого скрипта, например:
Как создать простой пакет и добавить его в системную библиотеку, чтобы я мог импортировать его как datetime в приведенном выше примере?
Вы пытаетесь создать модуль.
Начните с установки пакета setuptools ; на Windows или Linux вы должны иметь возможность набирать pip install setuptools на терминале, чтобы установить это. Теперь вы можете написать import setuptools в командной строке python без получения ошибки.
После этого настройте структуру каталогов, содержащую setup.py и папку для кода проекта. Каталог должен содержать файл __init__.py , который позволяет вам import каталог, как если бы он был файлом.
В setup.py отбросьте следующий контент:
В my_project/__init__.py отбросьте некоторые вещи, которые вы хотите импортировать. Скажем…
Теперь, чтобы установить проект на общесистемном уровне, запустите python setup.py install . Обратите внимание, что вам нужно запустить это как root, если вы работаете в Linux, поскольку вы вносите изменения в общесистемные библиотеки python.
После этого вы сможете запустить python из любого каталога, который вам нравится, и введите:
Обратите внимание, что этого достаточно, чтобы рассказать вам, как сделать модуль, но есть один адский материал, который setuptools может сделать для вас. Взгляните на https://pythonhosted.org/setuptools/setuptools.html для получения дополнительной информации о строительных материалах и https://docs.python.org/2/tutorial/modules.html для получения дополнительной информации о том, как работают модули, Если вы хотите посмотреть на пакет, который (я надеюсь) достаточно прост, то я сделал модуль LazyLog пару недель назад в поезде, и вы можете использовать его для справки.
Быстрый способ, если вы просто делаете что-то для своего собственного использования и не беспокоитесь об упаковке, заключается в том, чтобы поместить модуль (который может быть таким же простым, как один файл) в каталог системных site-packages . (В системах на базе Debian вы, скорее всего, захотите использовать dist-packages ).
Чтобы узнать, где находится каталог site-packages / dist-packages , запустите Python и:
Обратите внимание на последний элемент в этом примере: /usr/lib/python3.4/site-packages . Это то, что вы ищете. Итак, в этом примере, если я сохраню следующее в /usr/lib/python3.4/site-packages/foo.py :
Затем из любой точки моей системы:
Если вам действительно нужен пакет, вы можете сделать это с помощью boost, что позволяет взаимодействовать с C++. Вы можете реализовать алгоритмы с помощью C++ и скомпилировать его как библиотеку Python. Однако он плохо документирован. И, как описал документ, C API должен быть основным вариантом. Boost построен на C API любым способом.
Образец: Я сделал это несколько лет назад в классе. Вы можете сделать: import tfidf .
Если вы просто хотите использовать модуль для личного использования, просто поместите его в папку и добавьте эту папку в переменную среды PYTHONPATH .
Например, создайте папку в домашнем каталоге с именем
/python-packages , затем добавьте следующую строку в ваш .bashrc (если вы используете bash):
Затем просто удалите все модули/пакеты, которые вы хотите сделать доступными в
Как создать свой первый open source проект на Python (17 шагов)
Каждый разработчик ПО должен знать как создать библиотеку с нуля. В процессе работы Вы можете многому научиться. Только не забудьте запастись временем и терпением.
Может показаться, что создать библиотеку с открытым исходным кодом сложно, но Вам не нужно быть потрепанным жизнью ветераном своего дела, чтобы разобраться в коде. Также как Вам не нужна мудреная идея продукта. Но точно понадобятся настойчивость и время. Надеюсь, что данное руководство поможет Вам создать первый проект с минимальной затратой и первого, и второго.
В этой статье мы пошагово разберем процесс создания базовой библиотеки на Python. Не забудьте заменить в приведенном ниже коде my_package, my_file и т.п. нужными вам именами.
Шаг 1: Составьте план
Мы планируем создать простую библиотеку для использования в Python. Данная библиотека позволит пользователю легко конвертировать блокнот Jupyter в HTML-файл или Python-скрипт.
Первая итерация нашей библиотеки позволит вызвать функцию, которая выведет определенное сообщение.
Теперь, когда мы уже знаем, что хотим делать, нужно придумать название для библиотеки.
Шаг 2: Дайте имя библиотеке
Придумывать имена сложно. Они должны быть короткими, уникальными и запоминающимися. Также они должны быть написаны строчными буквами, без прочерков и прочих знаков препинания. Подчеркивание не рекомендуется. В процессе создания библиотеки убедитесь, что придуманное Вами имя доступно на GitHub, Google и PyPi.
Если Вы надеетесь и верите, что однажды Ваша библиотека получит 10000 звезд GitHub, то стоит проверить, доступно ли данное имя в социальных сетях. В данном примере я назову свою библиотеку notebookc, потому что это имя доступное, короткое и более-менее описывает суть моей задумки.
Шаг 3. Настройте среду
Убедитесь, что у вас установлены и настроены Python 3.7, GitHub и Homebrew. Если вам нужно что-то из этого, вот подробности:
Python
Скачайте Python 3.7 здесь и установите его.
GitHub
Если у вас нет учетной записи GitHub, перейдите по этой ссылке и оформите бесплатную подписку. Посмотрите, как установить и настроить Git здесь. Вам потребуется утилита командной строки. Перейдите по ссылкам, скачайте и установите все, что Вам понадобится, придумайте юзернейм и укажите электронную почту.
Homebrew
Homebrew — менеджер библиотек для Mac. Инструкции по установке найдете здесь.
Начиная с Python 3.6 рекомендуется использовать venv для создания виртуальной среды для разработки библиотек. Существует множество способов управления виртуальными средами с помощью Python и все они со временем изменяются. Можете ознакомиться с обсуждением здесь, но, как говорится, доверяй, но проверяй.
Начиная с версии Python 3.3 venv входит в систему по умолчанию. Обратите внимание, что venv устанавливает pip и setuptools начиная с Python 3.4.
Создайте виртуальную среду Python 3.7 с помощью следующей команды:
python3.7 -m venv my_env
Замените my_env вашим именем. Активируйте среду таким образом:
Теперь вы должны наблюдать (my_env) (или имя, которое вы выбрали для вашей виртуальной среды) в крайнем левом углу терминала.
Когда закончите работу, деактивируйте виртуальную среду с помощью deactivate .
Теперь давайте настроим GitHub.
Шаг 4: Создайте организацию в GitHub
GitHub — лидер на рынке реестров контроля версий. Еще две популярные опции — GitLab и Bitbucket. В данном гиде мы будем использовать именно GitHub.
Вам придется часто обращаться к Git и GitHub, поэтому если Вы не знакомы с системой, то можете обратиться к моей статье.
Создайте новую организацию в GitHub. Следуйте инструкциям. Я назвал свою организацию notebooktoall. Вы можете создать репозиторий под своей личной учетной записью, но одна из целей работы — научиться создавать проект с открытым исходным кодом для более широкого сообщества.
Шаг 5: Настройте GitHub Repo
Создайте новый репозиторий. Я назвал свой notebookc.
Добавьте .gitignore из выпадающего списка. Выберите Python для своего репозитория. Содержимое Вашего файла .gitignore будет соответствовать папкам и типам файлов, исключенным из вашего хранилища. Вы можете позже изменить .gitignore, чтобы исключить другие ненужные или конфиденциальные файлы.
Рекомендую выбрать лицензию в списке Выбрать лицензию. Она определяет, что могут делать пользователи Вашего репозитория. Одни лицензии позволяют больше других. Если Вы ничего не выбираете, то автоматически начинают действовать стандартные законы об авторских правах. Узнайте больше о лицензиях здесь.
Для этого проекта я выбрал третью версию Открытого лицензионного соглашения GNU, потому что она популярная, проверенная и “гарантирует пользователям свободу использования, изучения, обмена и изменения программного обеспечения” — источник.
Шаг 6: Клонируйте и добавьте директории
Выберите, куда Вы хотите клонировать Ваш репозиторий или выполните следующую функцию:
git clone https://github.com/notebooktoall/notebookc.git
Подставьте свою организацию и репозиторий.
Перейдите в папку проекта с помощью десктопного графического интерфейса или редактора кода. Или используйте командную строку с cd my-project и после просмотрите файлы с ls —A .
Ваши исходные папки и файлы должны выглядеть так:
.git
.gitignore
LICENSE
README.rst
Создайте вложенную папку для основных файлов проекта. Я советую назвать ее так же, как и вашу библиотеку. Убедитесь, что в имени нет пробелов.
Создайте файл с именем __init__.py в основной вложенной папке. Этот файл пока останется пустым. Он необходим для импорта файлов.
Создайте еще один файл с таким же именем, как у основной вложенной папки, и добавьте .py. Мой файл называется notebookc.py. Вы можете назвать этот Python-файл как захотите. Пользователи библиотеки при импорте модуля будут ссылаться на имя этого файла.
Содержимое моей директории notebookc выглядит следующим образом:
.git
.gitignore
LICENSE
README.rst
notebookc/__init__.py
notebookc/notebookc.py
Шаг 7: Скачайте и установите requirements_dev.txt
На верхнем уровне директории проекта создайте файл requirements_dev.txt. Часто этот файл называют requirements.txt. Назвав его requirements_dev.txt, Вы показываете, что эти библиотеки могут устанавливаться только разработчиками проекта.
В файле укажите, что должны быть установлены pip и wheel.
Обратите внимание, что мы указываем точные версии библиотек с двойными знаками равенства и полными номерами версии.
Закрепите версии вашей библиотеку в requirements_dev.txt
Соавтор, который разветвляет репозиторий проекта и устанавливает закрепленные библиотеки require_dev.txt с помощью pip, будет иметь те же версии библиотеки, что и Вы. Вы знаете, что эта версия будет работать у них. Кроме того, Read The Docs будет использовать этот файл для установки библиотек при сборке документации.
В вашей активированной виртуальной среде установите библиотеку в файл needs_dev.txt с помощью следующей команды:
pip install -r requirements_dev.txt
Настоятельно рекомендую обновлять эти библиотеки по мере выхода новых версий. На данный момент установите любые последние версии, доступные на PyPi.
В следующей статье расскажу, как установить инструмент, облегчающий этот процесс. Подпишитесь, чтобы не пропустить.
Шаг 8: Поработайте с кодом
В целях демонстрации давайте создадим базовую функцию. Свою собственную крутую функцию сможете создать позже.
Вбейте следующее в Ваш основной файл (для меня это notebookc/notebookc/notebookc.py):
Вот наша функция во всей красе.
Строки документа начинаются и заканчиваются тремя последовательными двойными кавычками. Они будут использованы в следующей статье для автоматического создания документации.
Сохраните изменения. Если хотите освежить память о работе с Git, то можете заглянуть в эту статью.
Шаг 9: Создайте setup.py
Файл setup.py — это скрипт сборки для вашей библиотеки. Функция setup из Setuptools создаст библиотеку для загрузки в PyPI. Setuptools содержит информацию о вашей библиотеке, номере версии и о том, какие другие библиотеки требуются для пользователей.
Вот мой пример файла setup.py:
Обратите внимание, что long_description установлен на содержимое файла README.md. Список требований (requirements), указанный в setuptools.setup.install_requires, включает в себя все необходимые зависимости для работы вашей библиотеки.
В отличие от списка библиотек, требуемых для разработки в файле require_dev.txt, этот список должен быть максимально разрешающим. Узнайте почему здесь.
Ограничьте список install_requires только тем, что Вам надо — Вам не нужно, чтобы пользователи устанавливали лишние библиотеки. Обратите внимание, что необходимо только перечислить те библиотеки, которые не являются частью стандартной библиотеки Python. У Вашего пользователя и так будет установлен Python, если он будет использовать вашу библиотеку.
Наша библиотека не требует никаких внешних зависимостей, поэтому Вы можете исключить четыре библиотеки, перечисленных в примере выше.
Соавтор, который разветвляет репозиторий проекта и устанавливает закрепленные библиотеки с помощью pip, будет иметь те же версии, что и Вы. Это значит, что они должны работать.
Измените информацию setuptools так, чтобы она соответствовала информации вашей библиотеки. Существует множество других необязательных аргументов и классификаторов ключевых слов — см. перечень здесь. Более подробные руководства по setup.py можно найти здесь и здесь.
Сохраните свой код в локальном репозитории Git. Пора переходить к созданию библиотеки!
Шаг 10: Соберите первую версию
Twine — это набор утилит для безопасной публикации библиотек Python на PyPI. Добавьте библиотеку Twine в следующую пустую строку файла require_dev.txt таким образом:
Затем закрепите Twine в Вашей виртуальной среде, переустановив библиотеки needs_dev.txt.
Затем выполните следующую команду, чтобы создать файлы библиотеки:
Необходимо создать несколько скрытых папок: dist, build и — в моем случае — notebookc.egg-info. Давайте посмотрим на файлы в папке dist. Файл .whl — это файл Wheel — встроенный дистрибутив. Файл .tar.gz является исходным архивом.
На компьютере пользователя pip будет по мере возможности устанавливать библиотеки как wheels/колеса. Они устанавливаются быстрее. Когда pip не может этого сделать, он возвращается к исходному архиву.
Давайте подготовимся к загрузке нашего колеса и исходного архива.
Шаг 11: Создайте учётную запись TestPyPI
PyPI — каталог библиотек Python (Python Package Index). Это официальный менеджер библиотек Python. Если файлы не установлены локально, pip получает их оттуда.
TestPyPI — это работающая тестовая версия PyPI. Создайте здесь учетную запись TestPyPI и подтвердите адрес электронной почты. Обратите внимание, что у Вас должны быть отдельные пароли для загрузки на тестовый сайт и официальный сайт.
Шаг 12: Опубликуйте библиотеку в PyPI
Используйте Twine для безопасной публикации вашей библиотеки в TestPyPI. Введите следующую команду — никаких изменений не требуется.
Вам будет предложено ввести имя пользователя и пароль. Не забывайте, что TestPyPI и PyPI имеют разные пароли!
При необходимости исправьте все ошибки, создайте новый номер версии в файле setup.py и удалите старые артефакты сборки: папки build, dist и egg. Перестройте задачу с помощью python setup.py sdist bdist_wheel и повторно загрузите с помощью Twine. Наличие номеров версий в TestPyPI, которые ничего не значат, особой роли не играют — Вы единственный, кто будет использовать эти версии библиотек.
После того, как Вы успешно загрузили свою библиотеку, давайте удостоверимся, что Вы можете установить его и использовать.
Шаг 13: Проверьте и используйте установленную библиотеку
Создайте еще одну вкладку в командном интерпретаторе и запустите другую виртуальную среду.
Если Вы уже загрузили свою библиотеку на официальный сайт PyPI, то сможете выполнить команду pip install your-package . Мы можем извлечь библиотеку из TestPyPI и установить его с помощью измененной команды.
Вот официальные инструкции по установке вашей библиотеки из TestPyPI:
Вы можете заставить pip загружать библиотеки из TestPyPI вместо PyPI, указав это в index-url.
Если хотите, чтобы pip также извлекал и другие библиотеки из PyPI, Вы можете добавить — extra-index-url для указания на PyPI. Это полезно, когда тестируемая библиотека имеет зависимости:
Если у вашей библиотеки есть зависимости, используйте вторую команду и подставьте имя вашей библиотеки.
Вы должны увидеть последнюю версию библиотеки, установленного в Вашей виртуальной среде.
Чтобы убедиться, что Вы можете использовать свою библиотеку, запустите сеанс IPython в терминале следующим образом:
Импортируйте свою функцию и вызовите ее со строковым аргументом. Вот как выглядит мой код:
После я получаю следующий вывод:
(Когда-нибудь я конвертирую для тебя блокнот, Джефф)
Шаг 14: Залейте код на PyPI
Залейте Ваш код на настоящий сайт PyPI, чтобы люди могли скачать его с помощью pip install my_package .
Загрузить код можно так:
Обратите внимание, что Вам нужно обновить номер версии в setup.py, если Вы хотите залить новую версию в PyPI.
Отлично, теперь давайте загрузим нашу работу на GitHub.
Шаг 15: Залейте библиотеку на GitHub
Убедитесь, что Ваш код сохранен.
Моя папка проекта notebookc выглядит так:
Исключите любые виртуальные среды, которые Вы не хотите загружать. Файл Python .gitignore, который мы выбрали при создании репозитория, не должен допускать индексации артефактов сборки. Возможно, Вам придется удалить папки виртуальной среды.
Переместите вашу локальную ветку на GitHub с помощью git push origin my_branch .
Шаг 16: Создайте и объедините PR
В браузере перейдите к GitHub. У Вас должна появиться опция сделать pull-запрос. Нажимайте на зеленые кнопки, чтобы создать, объединить PR и чтобы убрать удаленную ветку.
Вернувшись в терминал, удалите локальную ветку с git branch -d my_feature_branch .
Шаг 17: Обновите рабочую версию на GitHub
Создайте новую версию библиотеки на GitHub, кликнув на релизы на главной странице репозитория. Введите необходимую информацию о релизе и сохраните.
На сегодня достаточно!
Мы научимся добавлять другие файлы и папки в будущих статьях.
А пока давайте повторим шаги, которые мы разобрали.
Итог: 17 шагов к рабочей библиотеке
- Составьте план.
- Дайте имя библиотеке.
- Настройте среду.
- Создайте организацию в GitHub.
- Настройте GitHub Repo.
- Клонируйте и добавьте директории.
- Скачайте и установите requirements_dev.txt.
- Поработайте с кодом.
- Создайте setup.py.
- Соберите первую версию.
- Создайте учётную запись TestPyPI.
- Опубликуйте библиотеку в PyPI.
- Проверьте и используйте установленную библиотеку.
- Залейте код на PyPI.
- Залейте библиотеку на GitHub.
- Создайте и объедините PR.
- Обновите рабочую версию на GitHub.
Узнайте подробности, как получить востребованную профессию с нуля или Level Up по навыкам и зарплате, пройдя платные онлайн-курсы SkillFactory:
Вопрос:
Я вижу, что есть некоторые встроенные пакеты, которые я могу импортировать из любого скрипта, например:
from datetime import date
today = date.today()
print today
Как создать простой пакет и добавить его в системную библиотеку, чтобы я мог импортировать его как datetime
в приведенном выше примере?
Лучший ответ:
Вы пытаетесь создать модуль.
Начните с установки пакета setuptools
; на Windows или Linux вы должны иметь возможность набирать pip install setuptools
на терминале, чтобы установить это. Теперь вы можете написать import setuptools
в командной строке python без получения ошибки.
После этого настройте структуру каталогов, содержащую setup.py
и папку для кода проекта. Каталог должен содержать файл __init__.py
, который позволяет вам import
каталог, как если бы он был файлом.
some_folder/
| setup.py
| my_project/__init__.py
В setup.py
отбросьте следующий контент:
# setup.py
from setuptools import setup
setup(name="My Awesome Project",
version="0.0",
packages=["my_project"])
В my_project/__init__.py
отбросьте некоторые вещи, которые вы хотите импортировать. Скажем…
# my_project/__init__.py
greeting = "Hello world!"
Теперь, чтобы установить проект на общесистемном уровне, запустите python setup.py install
. Обратите внимание, что вам нужно запустить это как root, если вы работаете в Linux, поскольку вы вносите изменения в общесистемные библиотеки python.
После этого вы сможете запустить python из любого каталога, который вам нравится, и введите:
>>> from my_project import greeting
>>> print greeting
Hello world!
>>>
Обратите внимание, что этого достаточно, чтобы рассказать вам, как сделать модуль, но есть один адский материал, который setuptools
может сделать для вас. Взгляните на https://pythonhosted.org/setuptools/setuptools.html для получения дополнительной информации о строительных материалах и https://docs.python.org/2/tutorial/modules.html для получения дополнительной информации о том, как работают модули, Если вы хотите посмотреть на пакет, который (я надеюсь) достаточно прост, то я сделал модуль LazyLog пару недель назад в поезде, и вы можете использовать его для справки.
Ответ №1
Быстрый способ, если вы просто делаете что-то для своего собственного использования и не беспокоитесь об упаковке, заключается в том, чтобы поместить модуль (который может быть таким же простым, как один файл) в каталог системных site-packages
. (В системах на базе Debian вы, скорее всего, захотите использовать dist-packages
).
Чтобы узнать, где находится каталог site-packages
/dist-packages
, запустите Python и:
>>> from sys import path
>>> path
['', '/usr/lib/python3.4/site-packages/pip-7.1.2-py3.4.egg', '/usr/lib/python34.zip', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-cygwin', '/usr/lib/python3.4/lib-dynload', '/usr/lib/python3.4/site-packages']
Обратите внимание на последний элемент в этом примере: /usr/lib/python3.4/site-packages
. Это то, что вы ищете. Итак, в этом примере, если я сохраню следующее в /usr/lib/python3.4/site-packages/foo.py
:
def bar():
print('Hello world!')
Затем из любой точки моей системы:
>>> from foo import bar
>>> bar()
Hello world!
Ответ №2
Если вам действительно нужен пакет, вы можете сделать это с помощью boost, что позволяет взаимодействовать с C++. Вы можете реализовать алгоритмы с помощью C++ и скомпилировать его как библиотеку Python. Однако он плохо документирован. И, как описал документ, C API должен быть основным вариантом. Boost построен на C API любым способом.
Образец: Я сделал это несколько лет назад в классе. Вы можете сделать: import tfidf
.
Ответ №3
Если вы просто хотите использовать модуль для личного использования, просто поместите его в папку и добавьте эту папку в переменную среды PYTHONPATH
.
Например, создайте папку в домашнем каталоге с именем ~/python-packages
, затем добавьте следующую строку в ваш .bashrc
(если вы используете bash):
export PYTHONPATH=$HOME/python-packages'
Затем просто удалите все модули/пакеты, которые вы хотите сделать доступными в ~/python-packages
.
Ответ №4
Добавьте скрипт python или путь пакета к sys.path или просто переместите их в одно из мест в sys.path. НО я не предлагаю это делать…