Из wiki.openstack.org:

Quantum is an OpenStack project to provide "network connectivity as a service" between interface devices (e.g., vNICs) managed by other Openstack services (e.g., nova).

Из описания можно предположить, что в будущем это станет заменой nova network, что не далеко от правды. Ниже я расскажу об установки OpenStack + Quantum и немного о самом Quantum.

Установка OpenStack c помощью скриптов devstack является одной из самых простых и быстрых. В простейшем случае, это выглядит так:

$ git clone https://github.com/openstack-dev/devstack.git
$ cd devstack && ./stack.sh

После этого нужно будет лишь ввести свой root-пароль, пароль к MySql серверу и пароли к Openstack’у. При установке Quantum нужно создать и/или отредактировать файл localrc в каталоге с Devstack’ом и добавить туда следующие строчки:

disable_service n-net
enable_service q-svc
enable_service q-agt
enable_service q-dhcp
enable_service quantum
LIBVIRT_FIREWALL_DRIVER=nova.virt.firewall.NoopFirewallDriver
Q_PLUGIN=openvswitch

Разберем эти строчуки подробнее:

 

  • LIBVIRT_FIREWALL_DRIVER=nova.virt.firewall.NoopFirewallDriver - настраивваем libvirt для корректной работы файрволла с Quantum
  • Q_PLUGIN=openvswitch - указываем, что в качестве плагина (back-end’а) использовать Open vSwitch.
  • disable_service n-net - отключение nova-network, теперь вместо этого компонента будет работать Quantum.
  • enable_service q-svc - включаем Quantum Server. По сути, после скачивания исходников и первоначальной настройки выполнится такая команда: “/opt/stack/quantum/bin/quantum-server --config-file /etc/quantum/quantum.conf --config-file /etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini”. На момент написания этого поста есть баг, в котором описано что Quantum plugins должны использовать тот жу конфигурационный файл, что и Quantum. Но пока это не пофикшено.
  • enable_service q-agt - запустить Quantum agent. Т.к. в качестве плагина был выбран Open vSwitch, то и запустится, соответственно, Open vSwitch Plugin: $ sudo python /opt/stack/quantum/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py --config-file /etc/quantum/quantum.conf --config-file /etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini
  • enable_service q-dhcp - Quantum DHCP Agent, который управляет DHCP сервером внутри нашей виртуальной сети. Запускается он следующей командой:  sudo python /opt/stack/quantum/bin/quantum-dhcp-agent --config-file /etc/quantum/quantum.conf --config-file=/etc/quantum/dhcp_agent.ini.  Из коробки это dnsmasq, но можно написать поддержку любого сервера.

 

После правки localrc можно запускать stack.sh и подождать пока все будет установленно.

Кроме установки самого OpenStack’а, devstack так же создает тестовых пользователей, проектов и сети. Т.к. говорим о Quantum, то о сетях подробнее.

Сам по себе Quantum (так сказать, его core) предоставляет только API для создания и управления сетями. Самим управлением занимаются его плагины (plugins), которые, imho, правильнее было бы назвать бэк-ендами (back-ends). В текущей версии (Folsom) возможна одновременная работа только одного плагина. Т.к. мы установили Open vSwitch, то далее буду описывать работу Quantum с ним.

Основные понятия в Quantum:

 

  • network - изолированный L2 сегмент сети, аналог VLAN;
  • subnet - блок IPv4 или IPv6 адресов и их конфигурация (маршрутизатор, DNS-сервер)
  • port - точка подключения устройств (vNICs) в сеть Quantum.

 

Если смотреть на взаимодействие Quantum Network и OpenStack, то это выглядит так:

У каждого тенанта может быть одна и более сетей. У каждой сети может быть от 1 до n подсетей (конечно, может быть и 0 сетей/подсетей, по смысла в этом нет). Если смотреть на то, как все рабтало без Quantum, то теперьешине subnets это аналоги nova networks. При замуске виртуалки (инстанса), ей нужног передать к какой из сетей тенанта она подключена. Для каждой подсети будет создан отдельный vNIC у инстанса, который будет подключен к какому-либо порту. В нашем случае - это порт в Open vSwitch.

Посмотрим как это работает на практики:

Open vSwitch работает поверх бриджей (bridge), поэтому посмотрим какие “мосты” у нас есть:

$ sudo ovs-vsctl list-br
br-int
br-tun

Сейчас нас интересует br-int, поэтому посмотрим какие у него есть порты:

$ sudo ovs-vsctl list-ports br-int

patch-tun
tap6d98326d-5a
tap6e1a8612-27
tapf842abe0-27

В данной конфигурации, у меня запущено два инстанса, которые подключены к портам tap6e1a8612-27 и tapf842abe0-27. Порт patch-tun служит для “проброса” трафика между виртуальной сетью и физической через TUN-интерфейс. К порту tap6d98326d-5a подключен DHCP-сервер(dnsmasq) для инстансов внутри subnet.

Посмотрим, какие у нас есть сети в Quantum:

$ quantum net-list

 

И подсети:

$ quantum subnet-list

 

Порты:

$ quantum port-list

 

Тут мы видем, что у нашего DHCP-сервера адрес 10.0.1.2, а у инстансов 10.0.1.3 и 10.0.1.4.

 

Теперь, когда мы хоть немного имеем представление о сети, попробуем запустить новый инстанс:

$ nova boot --flavor 1 --image 4032fc9c-4688-4e71-ba2d-5a90e7698230 --nic net-id=3d5a9b8d-40cf-4f7b-a344-3db20f1a4783 test_vm_3

Синтаксис стандартный за исключением того, что я явно передал к какой сети подключать инстанс “--nic net-id=3d5a9b8d-40cf-4f7b-a344-3db20f1a4783”

Убедимся, что инстанс запустился командой “nova list”. И если у него статус ACTIVE, то можно попробовать попинговать или зайти по SSH:

Тут мы обнаруживае, что из хоста у нас нет доступа к виртуалкам :(. Хотя, если зайти через VNC на виртуалки, то они нормально будут видет другие инстансы в той же подсети.

 

Все дело в том, что Quantum организует работу с сетями через network netspace (http://stuff.onse.fi/man?program=ip-netns&section=8), поэтому, алгоритм работы немного усложняется:

смотрим список текущих неймспейсов:

$ ip netns

Выполняем ping/ssh внутри нужного неймспейса:

~$ sudo ip netns exec qdhcp-3d5a9b8d-40cf-4f7b-a344-3db20f1a4783 ssh 10.0.1.4

 

Ссылки по теме:

 

Продолжение следует...


 

Создать свой PyPI репозиторий для рабочего проекта мне пришлось сразу по нескольким причинам: начиная от архитектурных особенностей, заканчивая простотой удобством такого решения. Началось все с того, что наше приложение состоит из набора независимых между собой частей, packages. Соответственно, каждый такой пакет может зависить от любого числа других - как самописных так и нет. В таком случае создавать для каждого пакета свой файл pip-requirements для разворачивания окружения стало сложно и неудобно. Следующая причина - это сделать возможность установки любого пакета нужной верисии не имея доступа к нашей системе контроля версий (mercurial). Все-таки набрать команду “pip install my-package-name” намного проще и быстрее, чем указывать путь к исходникам или source control. И последняя причина для меня была в том, что необходимо следить за всеми зависимостями к внешним библиотекам: не только использовать нужную версию, устанавливать пропатченную, но и иметь список всего используемого в проекте (с этим пунктом возникло больше всего трудностей).

И так, что же представляет собой любой PyPI репозиторий? В простейшем случае - это папка с пакетами. Но для более легкого использования все же удобнее использовать веб-сервер. Так же можно использовать любой, но есть и специально написанные для этого приложения, которые имеют ряд примуществ. Я для себя пока остановился на pypiserver (http://pypi.python.org/pypi/pypiserver). Он достаточно простой, но при этом может работать как stand alone приложение или wsgi приложение с разными веб-серверами. Из недостатков, которые сразу бросились в глаза - это лишь то, что он не поддерживает upload пактов, т.е. команда “python setup.py upload” с ним работать не будет, но это автор обещает исправить в следующих версиях.

Установка pypiserver, самом простом случае выглядит так:

 

  • $ pip install pypiserver
  • $ mkdir ~/packages
  • копируем нужные пакеты в папку ~/packages и запускаем сервер:
  • $ pypi-server -p 8080 ~/packages

 

После чего репозиторий будет доступен по ссылке http://localhost:8080/simple/.

Теперь собственно про создание своих пакетов. С этим хорошо справляется ditsutils, которые идут вместе с Python (к сожалению, не так хорошо, как это будет в Python 3.3).

Для начала создаем в нашем пакете файл setup.py. В простейшем случае он будет выглядеть примерно так:

setup(name='package-name',
      version='0.2.1',
      description='description',
      author='e0ne',
      author_email='e0ne@e0ne.info,
      url='http://blog.e0ne.info',
      packages=['package_name', ],
     )

 

Далее создаем дистрибутив нашего пакета. В моем случае это только питоновские модули, поэтому меня вполне устроил sources distrib:

$ python setup.py bdist 

Эта команда создаст каталог dist и положит туда архив с дистрибудивом пакета, который, в моем случае, нужно положить в ~/packages. После чего остается лишь выполнить команду для его установки:

$ pip install package-name -i http://localhost:8080/simple

Для более простого использования можно переопределить переменную окружения PIP_INDEX_URL, чтобы еще упростить вызов команды:

$ export PIP_INDEX_URL=http://localhost:8080/simple/
$ pip install package-name

Следующим шагом что нужно сделать - это автоматизировать процесс создангия и выкладывания на свой PyPI-сервер пакетов путем интеграции с continuous integration (CI) сервером. Но так, как это сильно зависит от проекта, выбора CI и структыры исходного кода - приводить пример сдесь не буду. Кому нужно сможет сделать это сам или задать нужные вопросы в комментариях.

И последняя проблема у меня заключалась в том, что нужно полностью отказаться от http://pypi.python.org/pypi по двум причинам: ускорить процесс сборки билда путем удаления необходимости выкачивать нужные зависимости с интернета и иметь полный список всех зависимостей. При этом делать полное зеркало не хотелось. Как оказалось, в Python 2.7 сделать это не так уж и просто (на досуге нужно будет посмотреть как там с этим в Python 3.3). Проблема в том, что pip installer, который у нас используется устанавливает пакеты с помощью стандартных setuptools, что практически аналогично вызову команды “python setup.py install”. И если в setup.py есть строки типа install_requires=’django’, то setuptools не найдет это в локальном репо полезет в интернет. Заставить его работать по-другому без фикса кода можно несколькими способами. Самые простые - это:

 

  • добавить запись в /etc/hosts вида “127.0.0.1    pypi.python.org
  • настроить прокси-сервер для блокирования доступа к pypi.python.org с билд-машины.

 

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

Ссылки по теме:

 

 

 

 

 


 

Статические файлы (картинки, скрипты, css), как правило кешируются для более быстрой работы сайтов (уменьшение трафика - это уже скорее побочное явление). И в этом, казалось бы, нет ничего плохого. За исколючением одного - когда это самое кеширование мешает разработке. В моем случае используется стандартная связка nginx для статики + Tornado для всего остального. Но так как создавать вторую версию конфигурации nginx’а с отключенным кешированием мне не хотелось, да и в процессе разработке во многих случаях можно обойтить самим лишь Tornado, то я решил отключить кеширование в Tornado.

За отдачу статических файлов в Tornado отвечает StaticFileHandler. То логичным было предположить что кеширование отключается где-то в его настройках. Но единственное что там можно сделать, это переопределить метод get_cache_time, который и так во всех случаях возвращает 0. Исключение составляет лишь случай, когда в параметрах запроса есть ключ “v” - тогда время жизни кеша будет 10 лет.

Если посмотреть внимательно на код StaticFileHandler’а, в частности метогда, то увидем что 304-й ответ (not modified) выдаются только при соблюдении такого условия: в заголовках запроса (request headers) есть “If-Modified-Since” и время модификации файла больше, чем значение “If-Modified-Since”. Казалось бы все хорошо, но вот только дата последней модификации файла никак не может нам гарантировать, что содержимое не поменялось. В качестве значения заголовка “If-Modified-Since” браузеры передают то, что они получили от сервера на предыдущий запрос к данному ресурсу в заголовке “Last-Modified”. Таким образом для отключения кеширования статики необходимо отдать заведомо старое значение Last-Modified. Делается жто так:

 

 

Тут я указываю дату модификации на год меньше текущей даты. Так же для большей уверености выставляю значение “Expires” в 0, что сообщит браузеру о необходимости заново загрузить файл. И последнее - “Cache-Control='no-cache, must-revalidate” для большей уверенности. 

Теперь останется лишь указать наш хэндлев к как обработчик запросов к статике и все готово. А учитывая что в testing и production окружениях наверняка будет использоваться nginx, то код можно не менять, т.к. до нашего обаботчика запросы не дойдут, их обработает nginx.

Исходный код описанного хэндлера: https://github.com/e0ne/BlogSamples/blob/master/tornado-nocache/handlers.py

 


Хотя python и является интерпретируемым языком программирования, но все-же какае-то компиляция в нем есть. Это не такая компиляция, которую многие привыкли в C/C++. Скорее это нечно похожее на JVM (java virtual machine) и CLR (Common Language Runtime). 

Это компиляция в bytecode - низкоуровневый платформонезависимый язык, который выполняется внутри Python Virtual Machine (PVM). Более полное и официалное определение с сайта python.org:

Python source code is compiled into bytecode, the internal representation of a Python program in the CPython interpreter. The bytecode is also cached in .pyc and .pyo files so that executing the same file is faster the second time (recompilation from source to bytecode can be avoided). This “intermediate language” is said to run on a virtual machine that executes the machine code corresponding to each bytecode. Do note that bytecodes are not expected to work between different Python virtual machines, nor to be stable between Python releases.

Работает это так:

При первой загрузке модуля интерпритатор python (имеется в виду реализация CPython) парсит исходный код и компилирует его в bytecode, который размещает в файле .pyc (compiled python source) рядом с исходным файлом. При следующей загрузки модуля интерпритатор ищет pyc-файл и если нахотит, то сравнивает его время создания с py-файлом. Если время последнего меньше, чем время создания pyc-файла, то повторная “компиляция” не происходит. На самом деле время создания лишь один из критериев, но он, как правило, является решающим. К примеру в Python 2.7 так же сравнивается атрибут co_filename. Таким образом уменьшается время на загрузку модуля. Стоит отметить, что время выполнения кода остается таким же, т.к. он исполняется на той же PVM, что и первый раз. Из этого свойста не совсем явно вытекеает другое - для загрузки модулей нужны только pyc-файл, исходники в виде py-файлов не обязательны. Рассмотрим это на простом примере:

Я создал два очень простых файла. world.py:

def hello():
    print ‘hello’

И hello.py:

from world import hello
hello()

При первом запуске командой “$ python hello.py”, который произойдет немного медленнее интерпритатор создаст pyc-файл. Теперь “выполнение” (время выполнения кода осталось прежним, но время запуска уменьшилось, что в данном примере играет большую роль, в более сложных и реальных ситуациях время загрузки модуля зачастую чем время выполнения кода) этих скриптов занимает меньше времени. 

Идем дальше. Удаляем world.py и запускаем все ту же команду “$ python hello.py”. Результат оказался неизменным - на экран напечаталась слово ‘hello’. Такой жке результат получаем и при изменении файла hello.py. 

Особенности pyc-файлов заключаются в том, что они являются платформо-независимые, из-за чего их можно распространять вместо исходников своего приложения. Должно лишь соблюдаться одно условие - одна и та же версия PVM (CPython) как для компиляции, так и для запуска.

Внимательые читатели должны были заметить, что упоминались так же pyo-файлы. Для получения их необходимо передать интерпритатору опцию -O или -OO. Первая немного оптимизирует код путем удаления инструкций, необходимых для дебага (assert  и т.е.) (из python --help: -O     : optimize generated bytecode slightly). Вторая добавляет к такой оптимизации так же и удаления docstring-ов, что позволяет имень меньший размер “скомпилированного” файла.

И в завершении несколько копеек о распространении приложения в виде pyc/pyo-файлов. Хотя это и можно, но лично я не встречал такого пока, не считая разных вариция на тему py2exe. Если верить гуглу, то при запуске и развертывании таких прихожений часто возникают проблемы. В основном из-за версии CPython и, наверное всеми нелюбимого, случая с неправильной датой/временем/часовым поясом.  Также стоит отметить, что при установки пакета с помощью setup.py, pyc-файлы генерируются в момент установки. При создании RPM в с помощью setup.py также гененрируются эти файлы и кладутся внутрь RPM.

 

Несколько ссылок по теме:

модуль для компиляции в bytecode: http://docs.python.org/library/compileall.html

ну и куда же без disassempler’а http://docs.python.org/library/dis.html?


На днях узнал об одной интересной особенности типа bool в python:

>>> b = True
>>> b + 1
2

Поведение достатчно логичное, если учесть, что:

>>>> isinstance(b, int)
True

Всё дело в том, что тип bool - это всего-лишь синтаксический сахар и наследник от типа int, который, для удобства использования, может иметь всего два значения - 0 (False) и 1 (True). Пример выше врядли встретится в коде, но зать об этом стоит на случай если где-то случайно поменяется тип переменной с bool на int или наоборот.


 

Продолжаю сравнивать различные python-библиотеки. На этот раз выбор пал на два тест-фреймворка: nose и pytest. Первый позиционирует себя как unit test framework, второй - как для модульных, так и для функциональных и других тестов. Но так, как грань между модульными, интеграционными и функциональными тестами достаточно тонкая, то ее часто не замечают. Поэтому, эти библиотеки можно использовать для всех вышеперечисленных тестов.

Краткое сравнение функциональности фреймворков (тут я выбрал наиболее важные для меня вещи):

  nose pytest
Репозиторий  https://github.com/nose-devs/nose https://bitbucket.org/hpk42/pytest/
Дата последнего изменения 15.02.2012 6.02.2012 
Последняя версия 1.1.3 2.2.3 
Лицензия   As is 
Документация  +, подробная, легко разобраться +, подробная, легко разобраться 
Запуск определенного набора тестов +
Генерация отчета в формате xUnit +
Настройка детализации отчетов  +  
Изменение стандартного наименования
+
Поддержка fixtures fixeures, setup* и *teardown методы +, parametrized tests 
Интеграция с django +, сторонний плагин +, сторонний плагин 
Соответствие PEP8  +
Расширяемость +, механизм плагинов +, механизм плагинов 
Интеграция с setuptools  +/- 

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

Nose. Легко писать тесты, если до этого был опыт работы со стандартным модулем unittests или ТеstNG/nUnit в Java и .NET соответственно.

pytest. Мне показался более легким для начинающих. Может из-за более удобной для меня документации, но времени на то, чтоб написать тест для “hello world” приложения мне потребовалось меньше, чем при использовании nose.

Что буду использовать на текущем проекте - пока не решил. Скорее всего, главную роль сыграют плагины для интеграции с django и continius integration


RabbitMQ - одна из реализаций сервера для обмена сообщениями на базе протокола AMPQ(http://en.wikipedia.org/wiki/Advanced_Message_Queuing_Protocol, http://amqp.org/). Подробно описывать его работу, достоинства и недостатки я сейчас не буду. Цель этого поста - сравнить две библиотеки для работы с ним с помощью Python. На самом деле, этих библиотек значительно больше, краткий список их доступен на сайте RabbitMQ: http://www.rabbitmq.com/devtools.html#python-dev.

Сравнивал по принципу "нужно это, это и еще вооон то". Детальное описание фич на сайте - ниже только те, которые были критичные для меня.

Pika - Python AMQP Client Library - изначально разрабатывалась для работы с RabbitMQ и предоставляет собой реализацию протокола AMQP 0-9-1, в следствии чего, все примеры работы с RabbitMQ на Python в официальной документации написаны с использованием этой библиотеки.

Kombu известна тем, кто работал с OpenStack.

Небольшая сравнительная таблица с комментариями:


pika kombu
Репозиторий https://github.com/pika/pika https://github.com/ask/kombu
Дата последнего обновления 19.02.2012 21.02.2012
Последняя версия 0.9.6-pre0 2.1.0
Лицензия MPL 1.1 / GLP 2 BSD License / As is
Подход к написанию кода простой и понятный код явно прослеживается Publish–subscribe pattern
Поддержка SSL +(последняя версия из репозитория) +(последняя версия из репозитория)

Интеграция с Django из коробки
(есть документация и примеры)

- +
Асинхронная работа + +
Поддрежка Tornado/Twisted +/+ -/-
Кеширование из коробки - +
Поддержка разных транспортов для очереди сообщений ampq

amqplib
librabbitmq
pika
pika2
memory
redis
beanstalk
mongodb
couchdb
django (django models)

Документация +, примеры работы с RabbitMQ на сайте “кролика” +, примеры кода более сложные, чем “hello world”

 

В целом, после незначительного использования обоих библиотек (читать как “написал “hello world”” и чтения документации пришел к таким выводам:

 

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

 

 

Небольшой пример кода: https://github.com/e0ne/BlogSamples/tree/master/rabbitmq-sample

 

P.S. Хочется посмотреть еще celery и py-ampqlib, но пока до них руки не дошли.

P.S.S. Комментарии, замечания и дополнения приветствуются.

 


 

Время от времени, при разработке очередного API, которое работает поверх HTTP или создается Socket-сервер после остановки и попытки запуска сервера получаю ошибку:

socket.error: [Errno 98] Address already in use

Проблема заключается в том, что при аварийном (Ctrl+Z) завершении сервера в операционной системе остается запущенным процесс, который слушает нужный мне порт. В разных ОС время жизни такого процесса разное: в RHEL это около двух минут, в Ubuntu - больше. 

Решение достаточно простое. Т.к. при нажатии клавиш Ctrl+Z процесс получает команду “keyboard interrupt”, то достаточно обработать нужное исключение и корректно завершить процесс:

 

 

Надеюсь теперь не буду забывать писать нужный try-except...

 

Пример кода на GitHub: https://github.com/e0ne/BlogSamples/tree/master/SocketError. Для его запуска необходимо наличие утановленного пакета SOAPPy.


 

Мне всегда казалось, что для небольших проектов использование buildout - это как с пушки по воробьям: долго, сложно и неудобно. Хотелось чего-то более простого и понятного. И таким оказалась связка virtualenv + pip.

Про virtualenv я уже писал тут. pip - это замена easy_install, менеджер пакетов для python, который позволяет быстро и удобно устанавливать, обновлять и удалять пакеты. Более подробно можно почитать на официальном сайте. Сейчас же меня интересует возможность быстрого развертывания необходимого окружения для запуска проекта. В двух словах, задача выглядит так:

Нужно запустить проект, который для работы требует следующие пакеты:

 

  • Django;
  • SQL Alchemy;
  • pep8 & pylint для проверки кода.

 

Стандартный алгоритм решения - создать новое окружение с помощью virtualenv и установить нужные пакеты. Но ведь не делать же это каждый раз каждому разработчику руками? А на build-сервере? Пришедшая мне первая мысль (написание нужного bash-скрипта) к счастью, оказалась не совсем правильной. Т.е. для полной автоматизации небольшой bash-скрипт будет не лишним, но вот устанавливать пакеты проще и правильнее через pip. Итак, как же нам установить все необходимые пакеты?

 

Шаг 1. Создаем virtual environment

$ virtualenv ./pip-test/ --no-site-packages

Ключ --no-site-packages указывает на то, что в нашем окружении не будет доступа к пакетам, установленных в операционной системе. Такая себе чистая, ничем не испачканная песочница.

 

Шаг 2. Устанавливаем нужные пакеты

Первый раз все-таки будет необходимо установить все пакеты вручную, т.к. список нужных пакетов на данном этапе бывает далеко не всегда.

$ pip install Django
$ pip install SQLAlchemy
$ pip install pep8
$ pip install pylint

 

Шаг 3. Автоматизируем установку пакетов

После установки нужных пакетов можно выполнить команду pip freeze -l, которая выведет на экран список установленных пакетов с их версиями. В моем случае, это выглядит так:

$ pip freeze -l
Django==1.3.1
SQLAlchemy==0.7.4
logilab-astng==0.23.1
logilab-common==0.57.1
pep8==0.6.1
pylint==0.25.1

 

Ключ -l выводит пакеты установленный только внутри virtualenv, что при создании окружения с ключем --no-site-packages теряет всякий смысл.

Далее этот список нужно сохранить:

$ pip freeze -l > pip-requirements

Тепреь в файле pip-requirements лежит список всех необходимых для запуска пакетов. Этот нужно положить в вашу source control и при необходимости обновлять.

Чтобы установить все необходимые пакеты, необходимо выполнить команду:

$ pip install -r pip-requirements

 

Несколько рускоязычных статей про buildout можно найту тут: http://www.vurt.ru/tag/buildout

 


Все сказанное ниже является личным мнением автора и не является объективной точкой зрения и/или истиной последней инстанции.

Я всегда считал и продолжаю это делать, что Django - не очень-то и модульный фреймворк. Он расширяемый, но не модульный, IMHO. В моем понимании модульный фреймворк, это фреймворк, который состоит из ядра (core), и каких-то модулей, которые можно к нему подключать при желании/необходимости. Но и без них будет доступна минимальная функциональность. В случае же Django - выкинуть из него некоторые модули (e.g. models, template engine) достаточно сложно. Что-бы сделать что-то подобное, необходимо самостоятельно удалять ненужные куски кода, что тянет за собой проверку работоспособности оставшихся частей и прочие неприятности в виде сложной поддержки полученного кода и обновление фреймворка.

Django - легко расширяемый фреймворк. Это видно по django.contrib и многочисленных сторонних дополнений и приложений. Но при добавлении нового, все-равно есть возможность пользоваться старыми стандартными модулями Django.

Т.к. этот вопрос интересует меня давно, я его задавал одному из Django Core Developers, Andrew Goodwin’уб на прошедшем в октябре UA Pycon. Далее в вольном пересказе пишу его слова так, как я их понял:

“Мы знаем об этой проблеме и у нас есть в планах заняться этой задачей. Но есть еще масса более важных задач, которые нужно делать. Поэтому я не могу сказать, когда мы начнем это реализовывать. Также по идеологии Django нужно совместимость версий: код, написанный для текущей версии, должен без изменений работать на следующей.

И есть еще одна проблема: community хочет не только модульность самого Django, но и возможность использование его компонентов, например models, вне Django. В данной это невозможно, но мы хотим когда-нибудь это сделать”

Несколько ссылок по теме из википедии: