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

Работа с потоками всегда была не самым лёгким занятием для программистов. А если брать особенность работы с потоками в Python ветки 2.x и 3.x (не считая версий 3.2 и 2.7), то кроме потоков нам на голову падали ещё проблемы в GIL (Global Interpreter Lock). Но прогресс не стоит на месте и многопоточность используется уже практически везде. Проблема с cuncerrency встречается всё чаще и решать её приходится так же часто. 

При необходимости реализации такой задачи мне под руку попалась библиотеке eventlet (http://eventlet.net/), которая уже использовалась у нас на проекте и мне очень понравилась. Основная задача этой библиотеки - дать возможность реализации высокомашстабируемых не блокирующих I/O задач (highly scalable nonblocking I/O).

Описывать подробно все достоинства и недостатки данной библиотеки не буду, т.к. таких пока было обнаружено не слишком уж много. Больше всего, что мне не понравилось - это, на мой взгляд, не очень хорошая документация (http://eventlet.net/doc/), но открытые исходники с подробными комментариями и кучей примеров эту проблему решили.

В рамках моей задачи, мне понадобилось сделать какое-то подобие COMET-сервера с помощью long polling - один из способов сделать push-уведомления (http://en.wikipedia.org/wiki/Push_technology) для веб-приложений. Основная особенность - клиент делает один за другим (ajax)запросы на сервер, а сервер, в свою очередь отвечает клиенту только тогда, когда у него появились необходимые данные.

Простой пример такого приложения на Django доступен на гитхабе: https://github.com/e0ne/BlogSamples/tree/master/djangolp


Сегодня вышел Google App Engine 1.5.0. Кроме большого числа пофикшенных багов, появилось несколько достаточно интересных изменений.

Среди них стоит отметить такие:

 

  • Backends - постоянно запущенный инстанс одной из четырех конфигураций, который не связан с запросами (http requests) и может занимать до 1GB памяти. Один из способов применения - генерация отчетов, которая занимает много времени или другие ресурсоемкие задач
  • Изменения в Task Queue - поддержка pull-запросов, увеличение лимита на используемую память
  • Размер HTTP Request и Response увеличен до 32MB
  • High Replication Datastore теперь является хранилищем по умолчанию для новых приложений
  • Много изменений, связанных с квотами - некоторые были увеличены, а некоторые, наоборот - уменьшены
  • К моему сожалению, Full Text Search еще не закончили :(. 

 

 Отдельным пунктом хочу отметить экспериментальную поддержку языка программирования Go. Новости об этом языке, в основном, проходили мимо меня и я только иногда слышал упоминания о нем. Теперь же, когда Google добавил пусть и эксперементальную, но все-же поддержку, то многие захотят посмотреть на него более внимательно. Особенно, учитывая то, что он создан для ресурсо(процессоро)-емких задач будет компилироваться в native code.

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

 

 

 

 P.S. Интересно, насколько будет популярен Go в Украине через полгода-год, по сравнению с Python и Ruby?


DevTime прошел, а отчёт так и не был написан. В этот раз писать буду мало и только об одном докладчике. Вообщем могло быть и хуже, могло быть и лучше. Если коротко - сказывается недостаток выступлений на публику. Это был 3-й доклад, предыдущие два были для UNETA. Буду стараться в будущем делать лучше и больше.

Собстенно, сам доклад (видео):

 

Презентация:

 

 

Примеры кода, уже традиционно, на github: https://github.com/e0ne/events/tree/master/devtime/tipfy

 

P.S. Ну хоть один пост написал в этом месяце...


Dev Time #4 - Python

Published 3/31/2011 by e0ne in Events | Python | Web Development

Среда, 13 апреля этого года должна была пройти так же, как и остальные среды, но не тут-то было. В этот день состоится очередная встреча харьковского сообщества разработчиков Dev Time (мой отчет с первой встречи: http://blog.e0ne.info/post/First-Kharkov-DevTime-event-summary.aspx). 

Особенностью этой встречи будет то, что это первое подобное события на моей памяти в Харькове, посвященное языку программирования Python. О Python будет говорить Настя Хоменко aka @Eva__Brown с докладом "Python Tips" (детали уточняются). Вторым докладчиком буду я. И поговорю я о Google App Engine и web фреймворке tipfy

Примерное содержание моего доклада:

  • Goole App Engine (GAE) и Python
  • Почему не Django?
  • Преимущества и недостатки фреймворка tipfy
  • Быстрая разработка веб-приложений с помощью фреймворка tipfy
  • Расширяем tipfy или "после сборке доработать напильником"

Пожелания, относительно моего доклада, приветствуются. 

Приходите, надеюсь вам понравится.

 

P.S. Для посещения мероприятие чтение поста "tipfy - маленький, но мощьный web framework для GAE" является не обязательным, а вот регистрация на сайте Dev Time - обязательна.


Буквально на днях вышло сразу два интеречных релиза: Python 3.2 и PyCharm 1.2 EAP Build 105.13.

Так как сейчас в новых версиях Python изменений в синтаксисе нет (сделано это для ускорения перехода с ветки 2.x на 3.x), то все изменения сводятся к более стабильной работе, фиксам багов и всяким маленьким и не очень плюшкам.

На фоне этого релиза новая версия PyCharm кроме некоторых небольших улучшений/изменений несет в себе одну достаточно важную функцию под названием "Python version compatibility inspection".

 

Идея этой фичи очень простая: при написании кода среда разработки (IDE) будет вам подсказывать, что данный код будет или не будет работать на разных версиях интерпритатора Python. На мой взгляд, эта функция будет очень полезна тем, кто пишет под Google App Engine или если на машине разработчика версия Python отличается от версии на других environment'ах (окружениях) и по каким-то, надеюсь объективным причинам, не используется virtualenv.

[Update] Хороший комментарий по этой фичи PyCharm дал мне в твиттере Dmitry Jemerov (@intelliyole)

 


 

Так уж сложилось, что мне было необходимо выбрать framework для разработки небольшого приложения на python + GAE. Первым делом я посмотрел в сторону Django и немного огорчился, узнав что теперь GAE team рекомендуют использовать форк django-nonrel - практически тот же django, но дающий возможность простой работы с NoSQL базами данных. Так как django-nonrel все ещё не достиг версии 1.0 и имеет ряд недоработок, которые разработчики обещают исправить в ближайшее время. Из недостатков, которые для меня оказались решающими стоит отметить - не работает с GAE “из коробки”, соответственно необходимо многое доустанавливать-настраивать руками, на что не хотелось тратить время. Позже я обязательно напишу про этот фреймворк, но уже на примере django-nonrel + MongoDB. Тем временем мне порекомендовали посмотреть в сторону tipfy, на котором я остановился и о котором написан этот пост.

Как написано на сайте http://www.tipfy.org/, tipfy - маленький, но мощьный web framework, сделанный специально для GAE (“tipfy is a small but powerful framework made specifically for Google App Engine”). Текущая версия - 0.6.4, что говорит нам о том, что у него всё ещё впереди.

tipfy действительно очень маленький и быстрый, но благодаря расширениям (extensions) быстро приобретает необходимую функциональность. Посмотрим на структуру архива, который можно скачать по адресу http://www.tipfy.org/tipfy.zip

 

 

 

Всё, что лежит в корне архиве необходимо только для сборки своей версии tipfy, с добавленными или отключенными расширениями. К слову, добавление или отключение какого-либо расширение осуществляется редактированием всего одной строчки в файле buildout.cfg и запуском билд-скрипта, который загрузит и установит нужные расширения. Подробнее об этом можно почитать на странице http://www.tipfy.org/wiki/guide/extensions/#adding-or-removing-extensions

 

Всё, что необходимо для запуска и работы приложения находится в каталоге app. Как видно на скриншоте, там уже есть приложение “hello world” (куда же без него? :)). После “hello world” сразу же бросается в глаза jinja2 - достаточно известный template engine с хорошей докоментацией и сообществом. Если по каким-то причинам вам не нравится(перечеркнуто) подходит jinja, можно использовать Genshi или Mako.

В целом, приложение с использованием tipfy практически ничем не отличается от любого MVC-приложения, за исключением, конечно, специфики фреймворка.

Рассмотрим приложение “hello world” более детально.

Так как, это достаточно простой пример, то никакой модели нет. Но в случае необходимости - модели будут представлять собой обычные классы, наследуемые от GAE db.Model:

 

Наше приложение состоит из двух модулей (url.py и handlers.py) и одного шаблона (hello_world.html).

urls.py:

Содержит правила маппинга url-адресов на обработчики. По умолчанию их два:

 

  • Rule('/', endpoint='hello-world', handler='apps.hello_world.handlers.HelloWorldHandler') - указывает какой обработчик должен обрабатывать default page
  • Rule('/pretty', endpoint='hello-world-pretty', handler='apps.hello_world.handlers.PrettyHelloWorldHandler') - обработчик, который выполнится при открытии http://yoursite.com/pretty

 

handlers.py:

Каджый handler представляет собой класс, который наследуется от RequestHandler и имеет методы get(), post и др. для обработки соответствующих типов запросов.

В нашем случай это: 

 

 

 

В целом отмечу что переход с django на tipfy не вызывает никаких трудностей, только несколько маленьких неудобств, а именно: отсутствие уже готовой админки (частично, её может заменить аналога приложения в GAE) и другой template engine (хотя, многие успешно используют jinja в djanпo).

Такое короткое введение в tipfy и GAE. Продолжение следует...

 


Проблема с использованием разных версий софта практически настолько же стара как мир разработки этого самого софта. Смотря со стороны разработчика, то самый простой случай - это когда нужно пофиксить какие-либо баги в предыдущей версии. Проблема заключается в том, что для dev environment уже используется более новая версия python, django и/или другого, необходимого для проекта, ПО. В более “тяжелом” случае все становится еще интересней: в production одно, на stage -  другое, на машине разработчика - третье, а тут еще нужно писать под google app engine, для которого требуются специфические (старые) версия python/django. 

Первой моей идеей было поднять разные виртуалки для тестирования, но немного погуглив наткнулся на такую замечательную вещь, как virtualenv. Как написано на оффициальном сайте - “virtualenv is a tool to create isolated Python environments”, что в переводе звучит, примерно, так: “virtualenv - приложение для созданий изолированных рабочих сред для python”. Таким образом вы можете создать несколько окружений с разными версиями python и/или других библиотек. 

Установка virtualenv ничем не отличается от установки любой библиотеки, написанной на python. В моем случае установка выглядила так:

sudo easy_install virtualenv

После установки virtualenv процесс создание виртуального окружения состоит всего лишь из одной команды:

virtualenv -p /usr/bin/python2.5 ./gae/

Здесь с помощью параметра -p я указал версию python, которую необходимо использовать для виртуального окружения. Последним параметром идет путь к  директории, в которой необходимо все создать. Так же рекомендуется добавлять параметр --no-site-packages, для того, чтобы из виртуального окружения не было доступа к пакетам из “реальной” среды (из встроенной справки: Don't give access to the global site-packages dir to the virtual environment). У себя этот параметр я не использовал по следующей причине: на рабочем PC mbp я использую такую схему библиотек:

  • последняя версия python и необходимых библиотек устанавливается обычным образм, без virtualevn;
  • если для каких-то причин необходимы другие версии интерпретатора или библиотек - создаю virtualenv;
  • в virtualenv доустанавливаю только те библиотеки, версии которых должны отличаться от реальной среды моей ОС (в моем случае - необходимо использовать более старую версию).

Теперь, после создания virtualenv появилась такая структура папок:

bin include lib

В Windows-like OS структура папок может немного отличаться.

$ python --version

Python 2.6.5

$  ./bin/python --version

Python 2.5.4

Например, мне нужно запустить GAE-приложение с использованием django.  Если я его запущу в текущей конфигурации моей рабочей машины, то получу следеющую ошибку:

UnacceptableVersionError: django 1.0 was requested, but 1.2.1.final.0 is already in use.

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

Для переключения в виртуальное окружение проще всего использовать скрипт activate, который лежит в каталоге bin нашего  vitrualevn:

e0ne-macbook:gae e0ne$ source bin/activate

(gae)e0ne-macbook:gae e0ne$ python --version

Python 2.5.4

Для выхода из виртуального окружения существует команда deactivate:

(gae)e0ne-macbook:gae e0ne$ deactivate 

e0ne-macbook:gae e0ne$ 

Перейдем непосредственно к установке djngo в созданное виртуальное окружение. Установка любого python-пакета в virtualenv ничем не отличается от обычного процесса установки и выполняется всем знакомой командой:

(gae)e0ne-macbook:Django-1.0.4 e0ne$ python setup.py install

Теперь у меня есть 2 полноценных рабочих среды с простым и быстрым переключением между ними.

Я описал лишь базовые возможности пакета virtualenv, но и этого вполне достаточно для того, чтобы увидеть всю его мощь, спрятанную я простым и понятным интерфейсом. Как всегда, все подробности на оффициальной странице: http://pypi.python.org/pypi/virtualenv


Те, кто фолловит меня в твиттере, уже знают о существовании сайта notacash.com. Сейчас я хочу немного рассказать о нем.

Более чем 3.5 года моя работа связана с технологиями Microsoft, в частности - .NET framework и платформа ASP.NET. Но  так, как кроме языка программирования C# существует ещё большое количество других - я решил попробовать что-то другой. Выбор пал на скриптовые языки,а именно - python. По мере приобретения теоретических знаний о python, появлялась необходимость в их практическом применении. Приложения уровня "Hello World!" быстро надоели и хотелось чего-то большего. Сначала хотел написать движок для блога, но лень взяла своё. Ближе к середине лета у меня появилась идея о создании сайта, которая в последствии переросла в сайт notacash.com. Что это за сайт и для чего он нужен - писать тут не буду, всё это уже написано на странице About.

За обновлениями можно слежить в твиттере @notacash и по RSS.

Используемые технологии:

  • язык программирования (на сервере / на клиенте) - python/javascript;
  • веб-фреймворк (на сервере / на клиенте) - django/jquery;
  • СУБД - PostgreSQL

 


HTML Decode/Encode.

Если кто-то слышал об такой атаке на веб-сайты, как XSS Injection, то он(она) знает что для предотвращение такой атаки необходимо использовать функции HtmlEncode/HtmlDecode. XSS Injection (Cross-site injection) - один из способов атак веб-приложений, главной идеей которого является вставка(инъекция) чужого javascript-кода на атакуемый веб-сайт. Как минимум, это может привести к краже печенек cookies и получении прав администратора сайта. ...

1.1. ASP.NET

Это происходит, примерно, так:
Допустим, у нас есть форма для отправки комментарием, где пользователь вводит свой еmail и текст коммеентария. Самый простой обработчик кнопки добавить окмментарий будет выглядить так:

protected void OnAddCommentClick(object sender, EventArgs e)
{
 var pageId = this.GetPageId();
 var email = this.txtEmail.Text;
 var comment = this.txtComment.Text;
 CommentsService.AddComment(pageId, email, comment);
}

С первой точки зрения этот код не содержит никаких ошибок, компилируется и корректно сохраняет данные в БД. Но, если в тексте  комментария будет любой HTML или JavaScript-код, то при отображении этого комментария на страницу без предварительной обработки мы увидем, что HTML и JavaScript-код без особых проблем обрабатываются браузером.
Таким образом, мы сделали наш сайт уязвимым и нарушили одно из базовых правил проектирования ПО: “Не доверять данным, которые пришли извне нашей системы”. От себя еще добавлю: вдвойне недоверять данным, которые были введенны пользователем. Чтобы исправить это ошибку, необходимо всего-лишь вызвать метод HttpServerUtility.HtmlEncode(), перед сохранением данных в базу:


 var email = Server.HtmlEncode(this.txtEmail.Text);
 var comment = Server.HtmlEncode(this.txtComment.Text);

После чего, строка вида “<script>alert(‘hello!’);</script>” будет сохранена в базу в таком виде:

 &lt;script&gt;alert(‘hello!’);&lt;/script&gt;

Теперь все хорошо: любой введенный пользователем текст не ламает нашу верстку и не вызывает выполнения стороннего javascript (пример 2).
Но все не так просто, как кажется. Теперь, если такой код вставить в обработчике OnAddPage(), где администратор сайта будет добавлять страницы, то вместо красивого текста пользователи увидят набор непонятных символов. Поэтому, при отображении содержимого страницы мы вызываем метод HttpServerUtility.HtmlDecode(), который переведет сохраненный в базе данных текст в такой вид, чтобы браузер его корректно обрабатывал.

Таким образом, мы избавили наш сайт от XSS Injection дали возможность пользователям воодить разнообразные данные без вреда для сайта.

Примечание. Во всех примерах выше свойство странице EnableRequestValidation было установлено в false для возможноти ввода символов “<“ и “>”.
Примечание для ASP.NET 4.0/ASP.NET MVC 2.0. В ASP.NET 4.0/ASP.NET MVC 2.0 появилась конструкция <%: ... %>, которая делает за нас HTML Decode/Encode.

1.2. JavaScript

Если нам необходимо реализовать данную функциональность на клиенте с помощью javascript, то нам на помощь приходит jQuery:

function htmlEncode(html) {
 return $('<div/>').text(html).html();
}
function htmlDecode(text) {
 return $('<div/>').html(text).text();
}

1.3 Python/Django

В фреймворке Django HTML Decode работает по умолчанию, и для его отключение в шаблоне (template) добавить блок {% autoescape off %} и в нем поместить все элементы, для которых нам не нужен HTML Decode, после чего закрыть блок с помощью {% endautoescape %}.

2. URL Decode/Encode.

В отличии от HTML Encode/Decode незаэкранированный url больших проблем не вызывает, за исключением двух моментов: url становится не таким простым и понятным для пользователя и это не очень хорошо влияет на SEO.

2.1 ASP.NET

Рассмотрим такую ситуацию: у нас есть сайт с функцией поиска по нем. Стандартная форма поиска содержит поле для вводи и кнопу "Поиск". В простейшем случае при нажатии на кнопку “Поиск” у нас есть такой обработчик:


protected void OnSerachClick(object sender, EventArgs e)
{
 var searchText = this.txtSearch.Text;
 car url = String.Format(“{0}?q={1}”, VirtualPathUtility.ToAbsoluteUrl(“~/Search.aspx”), searchText);
 Response.Redirect(url);
}

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

/Search.aspx?q=some%20keywords

Конечно, такой url правильно обрабатывается браузером, но не всем пользователям будет понятно что он значит. Происходит это из-за того, что браузер автоматически заменяет символ пробела и ряд других символов на  их шестнадцатиричное значение вида %XX, где XX - код символа в шестнадцатиричной системе.
Сделано это было давно, кода браузеры были маленкими еще не умели отображать нелатинские символы в строке ввода адреса и для правильного отображения разнообразных символов.
И тут нам на помощь приходят методы HttpServerUtility.UrlEncode() и HttpServerUtility.UrlDecode() которые предназначены для переобразования параметров строки запроса в понятный для пользователей вид. Отдельно отчему, что эти методы предназначены для обработки исключительно параметров url, а для переобразования адреса к необходимому ресурсу существует метод HttpServerUtility.UrlPathEncode(), работа которого больше похожа на работу метода HttpServerUtility.HtmlEncode(), но учитывает все особенности построения url. Этот метод не имеет метода для обратного переобразования, но при правильном подходе к проектированию приложенич это не понадобится.

2.2. JavaScript

Аналог URL Encode в javascript - функция encodeURI()


DevConf 2010

Published 5/16/2010 by e0ne in Python | Web Development

DevConf 2010 уже завтра. До поезда в Москву осталось чуть более 3-х часов. Посмотрел финальную програму и немного расстроился: даже не смотря на то, что едем мы вдвоём, из-за плотного расспеисания и немкольких паралельных потоков врядли получится попасть на все интересующие доклады :(. Надеюсь что организаторы запишут и выложут видео.