__TOC__
Справжні художники продають. Принаймі так каже Стів Джобс. Хочете випустити скрипт, бібліотеку чи програму? Чудово. Світ потребує більше коду Python. Python 3 розповсюджується разом з фреймворком для створення пакетів який називається Distutils. Distutils це багато речей: інструмент для побудови проекту (для вас), інструмент для встановлення (для ваших користувачів), формат метаданих пакету (для пошукових програм), і багато іншого. Він інтегрується з Python Package Index ("PyPI") - центральним репозиторієм для бібліотек Python з відкритим кодом.
Всі ці грані Distutils зосереджуються навколо скрипта встановлення, який традиційно називається setup.py. Насправді ви вже могли бачити кілька скриптів встановлення Distutils протягом цієї книги. Ви використовували Distutils для того щоб встановити httplib2 в розділі веб-сервіси HTTP а також щоб встановити chardet в розділі Перенесення chardet на Python3.
В цьому розділі ви дізнаєтесь як працює скрипт встановлення для chardet та httplib2, та пройдемо процес випуску власного програмного забезпечення на мові Python.
# chardet's setup.py from distutils.core import setup setup( name = "chardet", packages = ["chardet"], version = "1.0.2", description = "Universal encoding detector", author = "Mark Pilgrim", author_email = "[email protected]", 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. """ )
Речі які Distutils не зможе зробити за вас Випуск вашого пакета мови Python - це гнітючий процес. (Випуск другого трішки легший.) Distutils намагається автоматизувати стільки скільки може, але є деякі речі які ви просто повинні зробити самостійно.
Обрати ліцензію. Це складна тема, насичена політикою та небезпеками. Якщо бажаєте випустити своє програмне забезпечення з відкритим кодом, я скромно дам вам п'ять порад: Не пишіть власну ліцензію. Не пишіть власну ліцензію. Не пишіть власну ліцензію. Це не обов'язково повинна бути GPL, але обов'язково повинна бути GPL-сумісна Не пишіть власну ліцензію. Класифікуйте своє програмне забезпечення використавши систему класифікації PyPi. Я поясню що це означає пізніше в даному розділі. Напишіть файл "README". Не пропускайте це. Щонайменше, він повинен давати вашим користувачам огляд того що ваше програмне забезпечення робить, і як його встановити.
Структура каталогів Щоб почати пакувати своє програмне забезпечення, потрібно впорядкувати свої файли та каталоги. Каталог з httplib виглядає так:
httplib2/ ① | +--README.txt ② | +--setup.py ③ | +--httplib2/ ④
+--__init__.py
+--iri2uri.py
① Створіть кореневий каталог що міститиме все решта. Дайте йому таке ж ім'я як ім'я вашого модуля.
② Щоб пристосуватись до користувачів Windows, ваш файл "read me" повинен мати розширення .txt, та використовувати символи повернення каретки в стилі Windows. Тільки тому що ви використовуєте вишуканий текстовий редактор що запускається з командного рядка та має власну мову макросів, не варто робити життя складним для ваших користувачів. (Ваші користувачі використовутимуть "Блокнот". Сумно, але правда). Навіть якщо ви користуєтесь Linux чи Mac OS, ваш сучасний текстовий редактор повинен мати опцію для зберігання текстових файлів з розділювачами рядків в Windows-стилі.
③ Ваш скрипт Distutils повинен називатись setup.py, якщо звісно ви не маєте вагомої причини називати його інакше. Але в вас немає вагомої причини.
④ Якщо ваше програмне забезпечення поміщується в єдиному .py файлі, потрібно помістити його в кореневу директорію разом з файлом "read me" та скриптом встановлення. Але 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 міститься повний текст ліцензії.
chardet/ | +--COPYING.txt | +--setup.py | +--README.txt | +--docs/
| +--index.html
| +--usage.html
| +--images/ ... | +--chardet/
+--__init__.py
+--big5freq.py
+--...
Написання власного встановлювального скрипта Скрипт Distutils є Python-скриптом. В теорії, він може все що може Python. На практиці, він повинен робити настільки мало, настільки можливо, в настільки стандартний спосіб наскільки можливо. Встановлювальні скрипти повинні бути нудними. Чим екзотичнішим є ваш процес інсталяції, тим більш екзотичними будуть повідомлення про помилки.
Перший рядок кожного скрипта Distutils завжди однаковий:
from distutils.core import setup
Це імпортує функцію setup(), яка є головною точкою входу в Distutils. 95% всіх скриптів Distutils складаються з виклику функції setup() і нічого більше. (Я просто вигадав статистику, але якщо ваш встановлювальний скрипт робить щось більше ніж викликає функцію setup(), ви повинні мати гарний привід. У вас є гарний привід? Я так не думаю.)
Функція setup може приймати десятки параметрів. Для того щоб ті хто його читатиме не з'їхали з глузду, ви повинні використовувати іменовані аргументи для кожного параметру. Це не звичай, це жорстка вимога. Ваш встановлювальний скрипт поламається якщо ви спробуєте викликати функцію setup() з неіменованими аргументами.
Наступні іменовані аргументи є обов'язковими:
name - назва пакета version - номер версії пакета author - ваше ім'я author_email - адреса вашої електронної поштової скриньки url - домашня сторінка проекту. Це може бути сторінка пакету на PyPI якщо в вас немає окремого сайту проекту.
Я також рекомендую додати в свій встановлювальний скрипт наступне:
description - однорядковий опис проекту. long_description - багаторядковий рядок в форматі reStructuredText. PyPI перетворить його в HTML, та відобразить на сторінці пакету. classifiers - список по особливому відформатованих рядків описаних в наступному розділі.
Тепер давайте глянемо на скрипт встановлення 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). Але це не те що описує параметр packages. Він стосується того факту що chardet це багатофайловий модуль, часом відомий як... "пакет". Параметр packages каже Distutils включити в пакет директорію chardet/, її файл __init__.py та інші файли .py що складають модуль chardet. Це дещо важливо, так як всі ці веселі розмови про метадані та документацію не мають сенсу якщо ви забудете додати сам код!
Класифікація вашого пакета Індекс пакетів Python ("PyPI") містить тисячі бібліотек Python. Правильні метадані класифікації дозволять людям знайти ваш пакет швидше. PyPI дозволяє вам переглядати пакети за класами. Можна навіть вибрати кілька класифікаторів для того щоб звузити пошук. Класифікатори не є невидимими метаданими які ви можете просто проігнорувати!
Щоб класифікувати ваше програмне забезпечення передайте параметр classify у функцію setup(). Цей параметр є списком рядків. Ці рядки не довільні. Всі рядки класифікації повинні братись із цього списку на PyPI.
Класифікатори не обов'язкові. Можна написати скрипт встановлення Distutils без жодних класифікаторів взагалі. Не робіть цього. Ви завжди повинні включати принаймі наступні класифікатори:
Мова програмування. Особливо, ви повинні включати як і "Programming language :: Python" так і "Programming language :: Python :: 3". Якщо ви не включите їх, ваш пакет не буде поміщено в цьому списку бібліотек сумісних з Python 3, на який посилається бічне меню кожної сторінки на pypi.python.org. Ліцензія. Це найперше на що я дивлюсь оцінюючи сторонню бібліотеку. Не змушуйте мене полювати за цією життєвоважливою інформацією. Не включайте більш ніж один класифікатор ліцензії, якщо ваш код не є явно доступним під кількома ліцензіями одночасно. (І не випускайте програмне забезпечення під кількома ліцензіями, якщо вас не змушують цього робити. І не змушуйте інших людей так робити. Ліцензування це й без того геморой, не робіть його гіршим.) Операційна система. Якщо ваше програмне забезпечення працює тільки під Windows (чи MacOS чи Linux), мені краще знати про це якомога раніше. Якщо ваше програмне забезпечення повинно працювати всюди і не покладається на який-небудь платформо-залежний код, використайте класифікатор "Operating System :: OS Independent". Кілька класифікаторів Operating System необхідні лише тоді коли ваше програмне забезпечення вимагатиме підтримки для кожної платформи. (Це не типово.)
Також рекомендую додати наступні класифікатори: Development Status. Ваше програмне забезпечення знаходиться в бета версії? Альфа версії? Гірше за альфу? Виберіть. Будьте чесними. Intended Audience. Кому варто завантажувати ваше програмне забезпечення? Типовими варіантами є Developers, End Users/Desktop, Science/Research та System Administrators. Topic. Є купа різних тематик, виберіть ту яка підходить.
Приклади гарних класифікаторів пакетів Заради прикладу наведу тут класифікатори для Django - готового до використання, кросплатформенного веб-фреймворка ліцензованого під BSD. (Django поки що не сумісний з Python 3, тому класифікатор Programming Language :: Python :: 3 не перелічується.)
Programming Language :: Python License :: OSI Approved :: BSD License Operating System :: OS Independent Development Status :: 5 - Production/Stable Environment :: Web Environment Framework :: Django Intended Audience :: Developers Topic :: Internet :: WWW/HTTP Topic :: Internet :: WWW/HTTP :: Dynamic Content Topic :: Internet :: WWW/HTTP :: WSGI Topic :: Software Development :: Libraries :: Python Modules
А ось класифікатори для chardet, бібліотека для визначення кодування символів, яка описується в розділі Перенесення 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