Скорее заметка для себя. Постоянно забываю об этом ключе.

Иногда нужно очень быстро поднять HTTP-сервер с минимальным функционалом. Например, нужно проверить HTML+JavaScript, который работает только через веб-сервер. Я, конечно понимаю, что у меня под рукой всегда есть, как минимум nginx, и поднять на нем сайт, который будет раздавать статические фалы, делов на 5-10 минут. Но, во-первых, это долго, а во-вторых, этот самый nginx у меня находится на виртуалке, пусть и включенной в 90% времени на ноутбуке. А тут прийдется не только веб-сервер настроить, но и расшаренные папки в VirtualBox-е, и так далее...

Единственное, что у меня действительно всегда есть под рукой, это Python (уже несколько лет не пользуюсь ОС Windows, а на всех *nix он есть из коробки). Поднять простой тестовый веб-сервер на питоне можно всего одной командой:

$ python -m SimpleHTTPServer 8100

После этой команды, у вас локально запустится веб-сервер на 8100-м порту, который покажет содержимое текущей папки.

Работает это благодаря ключу -m, который указывает интерпритатору о том, что необходимо выполнить модуль как скрипт. Это идентично команде "$ python /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SimpleHTTPServer.py", но писать значительно проще. Единственное ограничение, что этот модуль должен быть доступен в sys.path


В очередной раз чуть не наткнулся на давнюю проблему, но вовремя опомнился. При pylint “радостно” сообщил, что в некоторых модулях есть unused imports и их можно(нужно) удалить. Все было бы хорошо, если б не одно но: python очень даже динамический язык, а pylint ничего не знает о том, что будет происходить с кодом во время выполнения. Исходя из этого, уже можно представить какие проблемы могут быть. В моем случае, код был такой:

from quantum.openstack.common import cfg
...
from quantum.plugins.openvswitch.common import config

И pylint “ругался” на 2-й импорт, который нигде больше не использовался. Но если посмотреть на код этого модуля (https://github.com/openstack/quantum/blob/master/quantum/plugins/openvswitch/common/config.py) и вспомнить как работает механизм импорта в Python’е, то становится ясно, какие проблемы могут быть: при загрузке модуля config, он устанавливает значения по умолчанию настроек. А так, как со всемы настройками принято работать через общий интерфейс cfg, и не импортировать можуль config, то, с большой вероятностью, где-то в runtime у нас произойдет исключение. 

Описанный выше пример простой и банальный, но приводит нас к двум простым правилам:

  • нельзя слепо доверять анализаторам кода, особенно, если этот код динамический;
  • при проведении review кода нужно смотреть не только на новый/измененный фрагмент, а следует держать в голове полную картину и представлять как этот код будет работать с остальными частями приложения.

Вот интересно, если бы не unit-тесты и понимание работы import’ов, сколько бы времени потратил на фикс бага, после такого “улучшения” кода?


 

Создать свой 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 с билд-машины.

 

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

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

 

 

 

 

 


Уже не помню когда у меня перестал ратотать клиент к mercurial (hg) - после перехода на Python 2.7 или апгрейда дла Lion. Но так, как я им не пользовался, то решил не тратить время на восстановлние работоспособности. Но тут на проекте решили использовать Mercurial в качестве source control. Соответственно пришлось разбираться с hg. Сразу скажу что установка последней версии проблему не решила.

Шаг 1. Выполняем команду hg и получаем ошибку:

 

$ hg
abort: couldn't find mercurial libraries in [/usr/platlib/Library/Python/2.7/site-packages /usr/local/bin ...

Тут понятно что клиент написан на Python и при запуске не может импортировать нужные модули.

 

Шаг 2. Смотрим исходники:

Выполняем команду

$ sudo vim `which hg`

и практически в самом начале файла (не считая комменатиев - 3-я строка) видем такую строчку:

libdir = '../../platlib/Library/Python/2.7/site-packages/'

Для тех кто знаком с расположением биболиотек, в частности Python'а, в MacOS сразу поймет что путь к Python указан неправильно, соответственно меняем его на:

libdir = '/Library/Python/2.7/site-packages/'

Шаг 3. Пользуемся mercurial:

 

$ hg
Mercurial Distributed SCM
...

 


 

Время от времени, при разработке очередного 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.


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

Я всегда считал и продолжаю это делать, что 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. В данной это невозможно, но мы хотим когда-нибудь это сделать”

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



В Киеве ежегодно проходит PyCon, переодически собираются встречи Kyiv.Py - жизнь python community по немного идет своим ходом. А вот в Харькове, к сожалению, ничего подобного не было (не считая DevTime прошедшей весной). Вот мне и хахотелось собрать харькоское python community для общения, обменом знаниями и опытом.

Подробности на http://kharkivpy.org.ua/


При установке пакетов psycopg2 и lxml easy_install радостно падал с криками:

 

unable to execute gcc-4.2: No such file or directory
error: command 'gcc-4.2' failed with exit status 1

 

Вполне логично, т.к. gcc у меня не стоял :(. Странно только что в Snow Leopard все работало. Немного полазив по инету нашел, что gcc ставится вместе с XCode, который ставится бесплатно из Mac App Store. Но и это не сразу помогло. Ниже привожу список шагов, которые понадобились для установки gcc и psycopg2 после этого.

 

  1. Из Mac App Store устанавливаем XCode.
  2. Добавляем в переменную PATH путь к gcc: export PATH=$PATH:/Developer/usr/bin
  3. Чтобы работало после перезагрузки и для всех пользователей прописываем этот путь и в /etc/paths

 


Пару слов о UA Pycon 2011

Published 10/25/2011 by e0ne in Events

 

На прошедших выходных прошла уже вторая ежегодная конференция Ua Pycon 2011. Как видно из названия - конференция посвящена языку программирования Python. Людей было действительно много, наверное 300+. Официальных цифр я не видел/не помню. Также, в отличии от прошлого года, было целых 2 потока докладов, что является доказательством того, что конференция растет, а вместе с ней растет и Python-сообщество Украины, что меня очень радует. На фоне этого хочется создать свое маленькое или не очень харьковской сообщество, т.ч. кому интересно - пишите мне :).

 

Организация конференции была очень хорошей, место - в самом центре Киева, на майдане. Небольшой минус в виде плохого wi-fi ни капли не повлиял на всю атмосферу и мои впечатления от происходящего. Докладчики были как с Украины, так и из других стран. Чего стоят только Armir Ronacher и Andrew Goodwin!

 

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

В этом году я решил попробовать свои силы в роли докладчика. Epic fail’а, кажется не было, но судить не мне. Доклад назывался “Django - инструкция по применению”, который некоторые назвали “Инструкция по НЕ применению”. Я говорил о случаях когда Django нам подходит, а когда не подходит.

Моя презентация на slideshare: http://www.slideshare.net/ivankolodyazhny/django-9855408

Небольшой фотоотчет на Google Picassa: https://picasaweb.google.com/105438605215260896047/UAPycon2011

 

До встречи на UA Pycon 2011


Выбор веб-фреймворка не в .NET стеке для нового проекта достаточно нетривиальная задача. Их много - больших, маленьких, хороших и не очень, горячих и зелёных. Так как при работе с Python больше сталкивался с Django, то для себя, т.е. очень IMHO, сделал несколько правил.

Использовать Django нужно когда: 

  • нужно получить опыт с Django;
  • нужно сделать быстро сайт с админской частью (блог, CMS и т.д.);
  • есть хорошее готовое приложение/модуль для Django и его нужно сомсем немного доточить напильником;
  • нет необходимости заморачиватья с DAL (data access layer) и стандартного ORM вполне достаточно;
  • какие-то из модулей Django уж ооочень хорошо подходят для текущей задачи;
  • нужно сделать что-то очень быстро и нет опыта с другими фреймворками.
Итого получилось 6 пунктов. Если не выполняются хотя бы 3, то нужно задуматься о целесобразности использования Django. IMHO.

Как сказал один из авторов Django в своей книге: "Django - это всего-лишь приложение на Python".