среда, 21 октября 2015 г.

MagicPython -- Syntax Highlighter для SublimeText

Мой приятель Юра Селиванов попросил написать рекламный пост о его новом проекте MagicPython.

Это syntax highlighter для Sublime Text и Atom, который поддерживает все новые языковые конструкции Python 3.5 (async def и await например) плюс type annotations, string formatting и регулярные выражения.

Sublime поддерживает Python из коробки, но с Python 3 (а особенно с Python 3.5) у него проблемы. MagicPython понимает всё.
Разметка шаблонов для форматирования строк и регулярок заслуживает отдельного упоминания -- выглядит прекрасно и заметно облегчает жизнь.

Я сам использую ортодоксальный Emacs и переходить (пока) не собираюсь, но MagicPython работает исключительно хорошо и заслуживает доброго слова.

К слову, Юра (https://twitter.com/1st1) Python Core Developer и автор PEP 492 aka async/await -- т.е. очень грамотный спец, который знает как делать качественные продукты.

Пользуйтесь с удовольствием.

P.S.

О редакторе Atom узнал только на этой неделе.
На первый взгляд выглядит как Sublime но при этом Open Source.
Уважаемые читатели, кто-нибудь его использует? Какие ваши впечатления?

среда, 13 мая 2015 г.

Почему я не люблю конфигурацию в django-style

Введение

Сегодня работал над добавлением в aiohttp.web свойства scheme для request object.

Идея простая: отвечать что request.scheme "http" для HTTP запросов, иначе "https".

У меня есть правило: перед началом погляди как другие уже справились с этой задачей.

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

Так вышло что сегодня я смотрел код Django.

И было в том коде примерно такое:

@property
def scheme(self):
    if settings.SECURE_PROXY_SSL_HEADER:
        try:
            header, value = settings.SECURE_PROXY_SSL_HEADER
        except ValueError:
            raise ImproperlyConfigured(
                'The SECURE_PROXY_SSL_HEADER setting must be a tuple containing two values.'
            )
        if self.META.get(header, None) == value:
            return 'https'
    return 'http'

В целом очень хорошо: Django показала, как работать с HTTP и что делать если сервер расположен за HTTPS Reverse Proxy (Nginx, например).

В последнем случае я сконфигурирую Nginx чтобы он добавил несколько полезных HTTP HEADERS для HTTPS connection:

  proxy_set_header        Host $host;
  proxy_set_header        X-Real-IP $remote_addr;
  proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header        X-Forwarded-Proto $scheme;

По X-Forwarded-Proto я пойму что это был HTTPS.

В целом стандартная и всем (надеюсь) известная процедура.

У aiohttp свободы чуть больше: оно может понять что сокет, по которому подключились напрямую, сам уже SSL -- но это пригодно только если мы готовы выставить наш aiohttp сервер прямо в веб.

Куда чаще его прячут за Nginx, HAProxy или похожим reverse proxy и там уже работают с сертификататами, проксируя обычный HTTP connection.

В общем всё прекрасно: Nginx выставит X-Forwarded-Proto HTTP HEADER который будет или "http" или "https".

Django глянет на settings.SECURE_PROXY_SSL_HEADER и если там ("X-Forwarded-Proto", "https") то scheme тоже будет "https".

Очень грамотно сделано, мне нравится.

Проблема

Так почему я этот пост написал?

А потому что settings.SECURE_PROXY_SSL_HEADER может быть чем угодно -- строкой, числом или ещё какой непотребной константой.

Проверка выполняется на момент получения request.scheme.

Нам, питонщикам, плевать на производительность в данном случае -- на самом деле try/except обходится дешево и никак не отразится на работе сайта.

Беда в другом -- ошибка неправильной конфигурации выявится не на этапе старта приложения а тогда, когда его выкатят в production.

У тестов будет свой правильный settings.py, а на production server админ чуть-чуть ошибётся.

И это тоже не слишком большая проблема -- при ручном тестировании команда QA, наверное, обнаружит ошибку очень быстро. Или на следующее утро -- тут уж зависит от того как техроцесс построен.

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

Решение

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

Для начала нужно отказаться от использования общего конфига в API.

Строить код библиотеки так, чтобы она никогда не лезла в settings.py (это и Flask касается если что).

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

Тогда можно быстро понять, что формат параметра не тот или IP address недоступен.

Разделение на этапы:

  • чтение конфига, анализ его и подготовка приложения к работе
  • запуск и работа

помогает избежать досадных недоразумений.

Плюс, к тому же, на явном этапе подготовки к старту можно позволить себе довольно дорогостоящие проверки на корректное функционирование системы (послать PING чтобы убедится что Redis живой, например).

вторник, 24 марта 2015 г.

Подкаст

Неделю назад принимал участие в записи подкаста о Питоне вообще и asyncio в частности.
Прослушать результат нечеловеческих усилий можно здесь.

суббота, 14 февраля 2015 г.

vagga

Паша Коломиец работает над проектом vagga.

Коротко говоря, это система виртуализации на linux контейнерах, предназначенная для разработки программ.

Выполняет роль, в чем-то похожую на virtualenv, но со своими отличиями и особенностями.

Рекомендую прочесть свежую Пашину статью, в которой он даёт обзор возможностей vagga и показывает преимущества над virtualenv.

P.S. Я лично к проекту никакого отношения не имею, поэтому все вопросы, пожалуйста, задавайте сразу Паше.


пятница, 16 января 2015 г.

aiohttp 0.14

Выпустил новую версию библиотеки.

Из вкусного -- Web Sockets для aiohttp.web серверов, оптимизация скорости работы, множество мелких улучшений.

Полный список изменений -- здесь.