Всё чаще стал себя ловить на мысли, что нам в питонячей вселенной не хватает классического сервера приложений.
От него хочется совершенно банальных вещей:
- Менеджмента конфигураций
- Абстракции над хранением данных
- Возможности легкого добавления точек входа и компонентов
- Инфраструктуры для отложенного выполнения задач
- Каких-то батареек типа библиотеки с хелперами
- Простой интеграции с другими системами
- Предсказуемых внутренних процессов и возможности на них влиять (явная и контролируемая инициализация например)
Самое интересное, что почти всё это есть как отдельные компонеты, но нет среды которая могла бы их объединить или предложить своё комплексное решение. При этом, конечно, этот сервер должен быть достаточно легким и не давить своим весом на пугливые умы опытных разработчиков.
Эта ситуация мне очень что-то напоминает. Да, это похоже на мир веб-фреймворков. Они, зачастую, как раз закрывают эту нишу. Я уже не один раз приходил к выводу, что проще продолжать использовать веб-фрейморк даже в тех задачах, где нет непосредственой вебной составляющей. Тем более, если он уже применяется и его окружение уже содержит нужный контектс для функционирования других компонентов.
Кажется, что отсутствие такого сервера приложений не продлится вечно и через какое-то время появится новый интересный игрок в этой нише. И как всегда, приходится бить себя по рукам, чтобы не ввязаться в его написание «на ...
Какие у вас планы на 17-18ое мая этого года? Пока не знаете? Тогда я могу вам предложить интересное занятие на эти дни.
В означенные дни в Москве пройдет первая российская конференция DevConf, которая соберет множество веб-разработчиков из различных "вселенных".
Среди прочих вселенных (секций), там будет своя, отдельная, уютная и посвященная Python. Не знаю как вы, а я о чем-то подобном уже давно мечтал.
Если вы хотите послушать доклады, поучаствовать в мастер-классах и пообщаться с интересными людми, обменяться опытом и приобрести новые контакты в сообществе, то вы обязательно должны поучаствовать. Регистрация уже открыта, так что не теряйте время и заполняйте форму.
Поверьте, такие мероприятия проходят не часто и если вы хотите быть в курсе последних трендов в Python мире, то оно того стоит чтобы поучаствовать.
На данный момент мы активно ищем докладчиков и формируем программу. Если у вас есть интересные мысли и желание поделиться ими с сообществом, то регистрируйтесь и предлагайте свои доклады/мастер-классы. Если у вас возникнут какие-то вопросы, то можете смело задавать их мне, т.к. я являюсь членом оргкомитета и отвечаю за питонячью секцию.
Call to arms!
Как оказалось в питоне нет однозначно подходящего варианта. Всего-то хочется удобно дергать какие-то API и иногда стягивать файлы.
Есть несколько библиотек, многие из которых друг друга используют и заимствуют функционал. Но вот чего-то одного, удовлетворяющего достаточно простым (ведь так?) требованиями, нет.
Требования же эти такие:
- поддержка http/https
- возможность использовать любые http verb
- возможность отослать body запроса с произвольным Content-Type
- поддержание коннекта между запросами (keep-alive)
- работа с куками
- стандартная аутентификация
- file-like интерфейс к body ответа
- кеширование
- conditional get
- обработка низкоуровневых ошибок и оборачивание их в какой-то дженериковый
HTTPError и наследников.
- возможность добавить в конвейер запроса хуки, чтобы можно было какие-то действия производить с отсылаемыми данными, либо результатом.
- возможность задать таймаут хотя бы для соединения
Ну и пара экзотических хотелок:
- поддержка http pipelinening
- возможность делать запросы асинхронно
Ведь не невозможного хочется. Но что мы имеем.
httplib
По сути основа всех питонячих "ходилок" по http. Находится в стандартной библиотеке. Главная особенность -- позволяет присоединиться к http серверу и делать запроса к его урлам в рамках одного соединения.
connection = httplib.HTTPConnection('example.com')
result = connection.request('GET', '/foo')
# ...
result = connection.request('GET', '/bar')
# ...
connection.close()
Возвращает file-like объект и с недавних пор позволяет задать таймаут для соединения. Тут фичи заканчиваются и мы остаемся наедине ...
Недавно на форуме случился топик посвященный извечной проблеме всех питонистов -- кодировкам. Человек жаловался на то, что у него в программе получаются строчки вида:
u'\xd0\x9a\xd1\x83\xd1\x80\xd1\x83\xd0\xbc\xd0\xbe\xd1\x87'
Вы заметили что что-то не так? И я вот. Строчки как бы уникодные, но внутри них закодированные utf-8 байты. Что-то pдесь не так. Разбираясь дальше и потребовав скрипт, которые такое генерирует, становится понятно, что данные берутся из веба. Вполне обычным способом через urllib и потом скармливаются в lxml.html для разбора. Поскольку urllib оперирует только байтовыми строками, то он не мог их так превратить в уникод, а значит во всем виноват lxml.
Вообще lxml очень крутая библиотека - и быстрая, и функциональная, и умеет мимикрировать интерфейсом под ElementTree, и взаимодействовать с BeatifulSoup. Она давно уже пользуется популярностью у питонистов, когда надо как-то удобно работать с xml.
Но тут немного другой случай. Тут используется парсер html. И именно в нем происходят эти неприятные метаморфозы со строками.
Я решил понять в чем же всё-таки и дело и как побороть такое поведение.
Для начала, я сходил на http://yandex.ru/ и посмотрел что за html там отдается. Кодировка контента utf8. Сразу что бросилось в глаза -- это ...
Примерно год назад, во время массовой истерии по поводу питонячих и не очень асинхронных серверов, я, пытаясь составить своё мнение обо всем об этом, набрел на интересную библиотеку - greenlet. На которой базируется сетевая библиотека eventlet, а на ней всю очередь WSGI веб-сервер spawning.
Как видно из названия, она позволяет делать легкие треды - гринлеты в обычном не stackless питоне. Я написал небольшой скрипт "на попробовать":
#!/usr/bin/env python
from greenlet import greenlet
def dispatch():
while True:
for w in workers:
w.switch()
print 'dispatch'
if not all(workers):
break
d = greenlet(dispatch)
def worker(name):
for i in range(5):
print name, i
if i % 2 == 0:
print 'switch'
d.switch()
workers = [
greenlet(lambda: worker('foo')),
greenlet(lambda: worker('bar'))
]
print 'start'
d.switch()
print 'done'
вывод:
start
foo 0
switch
dispatch
bar 0
switch
dispatch
foo 1
foo 2
switch
dispatch
bar 1
bar 2
switch
dispatch
foo 3
foo 4
switch
dispatch
bar 3
bar 4
switch
dispatch
done
и вот недавно набрел на него. Правда прекрасно? Такой простор для творчества - передача контекста выполнения в произвольное место с сохранением состояния. Некий намек на потусторонний call/cc из "других" языков.
Ещё тогда у меня родилась идея где это можно ...