Подготовка и публикация модуля Django

Этот материал рассчитан на тех, кто уже написал свой модуль для Django и хочет, чтобы его труд оценили.

Я бы хотел пояснить, зачем нужно готовить пакет для python. Как написано на сайте redsolutioncms.org,

мы столкнулись с тем, что какая-нибудь наша библиотека уходит
за ненадобностью, потому что OpenSource сообщество сделално
подобную вещь хоть позже нас, но лучше

Итак, для чего вам нужно опубликовать свой модуль:

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

Требования к модулям

Насчёт организации кода . При публикации каждый сам решает, на что обратить больше внимания, на что меньше, а что вообще обойти. Я опишу технологию выпуска модулей в нашей компании, которая, судя по практике, имеет право считаться удобной :)

1. Зависимости

Все зависимости от других должны быть прописаны в setup.py, зависимость от самой Django мы не прописываем, чтобы при установке её не скачивал easy_install.

2. Интернационализация

В модуле не должно содержаться ни строчки по-русски. В идеале не должно быть комментариев и текстов коммита не на английском. Мы стараемся в общем придерживаться этого идеала. Ко всем модулям создается русская локаль, так что сразу заметно, если что-то не переведено.

3. Тесты

Наше слабое место. Тем не менее я категорически настаиваю на наличии тестов у сколь бы то ни было сложных модулей. Существует множество удобных фреймворков для тестов (от Selenium до webtest), пользуйетсь ими на здоровье!

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

Каждый наш модуль содержит, как минимум, описание в README. Если модуль требует бОльшей документации, то её необходимо предоставить пользователю.

5. Контроль версий

Мы долго размышляли о том, как публиковать версии того или иного модуля. Мы использ��ем трехзначную систему именования версий:

[0].[мажорный релиз].[минорный релиз]

Вместо нуля первой цифрой станет 1, когда мы посчитаем модуль стабильным и неизменным. В мы делаем так: для мажорных версий созданы ветки, а для минорных - тэги. Это сделано для того, чтобы при использовании одной и той же мажорной версии модуля можно было получить багфиксы в минорных версиях.

Чем мажорные от минорных отличаются спрашиваете? Между двумя мажорными версиями сохраняется API и структура БД. Минорные версии могут добавлять новые возможности и исправлять ошибки.

Стандарт оформления

Мы стараемся оформлять модули по одному алгоритму:

В корень проекта добавляются в обязательном порядке файлы:

  • MANIFEST.in - файл для подключения медиа-файлов в проект.
  • README.rst - файл с кратким описанием и примерами применения модуля в формате
  • README -> README.rst симлинк. Именно такой. Дело в том, что гитхаб не понимает симлинки, а хочется видеть документацию на гитхабе и на PYPI
  • DESCRIPTION - такое описание модуля, чтобы человек не в теме понял для чего нужен этот модуль
  • setup.py - файл установщика

Помимо этого, в __init__.py файле модуля должна быть переменная __version__, которая содержит номер текущей версии модуля. Например

__version__ = '0.1.0'

Текст README проверяйте на валидность , иначе на Python Package Index форматирование не будет отображаться, документация будет в текстовом формате.

Пример MANIFEST.in

Файл MANIFEST.in нужен для того, чтобы в egg-пакет вошли медиа-файлы (шаблоны, стили, js-скрипты)

recursive-include chunks *
include README README.rst DESCRIPTION INSTALL.txt
exclude *.orig *.pyc

Пример setup.py

setup.py по сути, самый главный файл при публикации модуля. Он определяет всю мета-информацию о пакете, разработчике, лицензии, файлах и т.п. в модуле

# -*- coding: utf-8 -*-
import os
from setuptools import setup, find_packages

# Utility function to read the README file.
# Used for the long_description.  It's nice, because now 1) we have a top level
# README file and 2) it's easier to type in the README file than to put a raw
# string in below ...
def read(fname):

    try:
        return open(os.path.join(os.path.dirname(__file__), fname)).read()

    except IOError:
        return ''

setup(
    name="redsolutioncms.django-myapp",

    version=__import__('myapp').__version__,
    description=read('DESCRIPTION'),

    license="GPL",
    keywords="django tag1 tag2",

    author="John Doe",

    author_email="author_email@example.com",

    maintainer='John Doe',
    maintainer_email='maintainer_email@example.com',

    url="http://github.com/redsolution/myapp",
    classifiers=[
        'Development Status :: 3 - Alpha',
        'Intended Audience :: Developers',

        'License :: GPL',
        'Framework :: Django',
        'Environment :: Web Environment',
        'Natural Language :: Russian',
        'Natural Language :: English',

        'Operating System :: OS Independent',
        'Programming Language :: Python',
        'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
    ],
    packages=find_packages(exclude=['example', 'example.*']),

    install_requires=[],
    include_package_data=True,
    zip_safe=False,

    long_description=read('README'),
    entry_points={
        'redsolutioncms': ['myapp = myapp.redsolution_setup', ],

    }
)

Следует привести комментарии к некоторым строкам. Во-первых, данный setup.py подразумевает, что файлы README и DESCRIPTION существуют. Если это не так - опсание будет пустое. Более того, версия будет пустая, если в __init__.py не будет переменной __version__.

Строка packages=find_packages(exclude=['example', 'example.*']), говорит о том, что если в модуле есть папка example, и она является питоновским модулем, то её нужно исключить из пакета - представьте, если дюжина модулей будет импортировать один и тот же модуль example.

Параметр entry_points нужен для интеграции с Redsolution CMS, об этом в статье про интеграцию.

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

Публикация

Опубликовать модуль на PYPI очень легко. В первую очередь, вам нужен будет аккаунт на PYPI. Затем, зайдите в папку проекта и наберите

python setup.py register

Для вас создастся страничка проекта. Для загрузки пишите

python setup.py sdist upload

Готово! Ваш модуль на PYPI, можете проверять главную страницу :)