Есть такой популярный microframework: Flask.
Многим нравится: легкий и простой для изучения, то да сё.
А мне --- категорически нет.
Нелюбовь началась с элементарного: request --- это thread local variable:
import flask
from myapp import app
@app.route('/')
def handler():
req = flask.request
if 'arg' in req.args:
process_arg(req.args['arg'])
###
Т.е. для для того чтобы узнать с какими GET или POST параметрами
вызвали мой код -- я должен обращаться к глобальной переменной!
Я знаю разницу между global variable и thread local variable если
что -- но это не избавляет от неприятного послевкусия.
Ага, есть еще и flask.g!
Если уж мне потребуются context local variables -- я их буду
использовать по моему выбору, морщась от осознания собственного
несовершенства. Зачем flask их мне навязывает?
Дальше -- больше.
Смотрим еще раз:
from myapp import app
@app.route('/')
def handler():
###
Имеем наполовину сконфигурированный импортированный откуда-то app, к
которому добавляем обработчик.
Мне это не нравится. Я хочу сделать app и добавить в него route table.
Flask это позволяет, но документация провоцирует делать ровно наоборот.
Исполнять код на этапе импорта модуля не выглядит хорошей идеей,
сейчас в этом я полностью уверен.
Идем дальше.
Параметры в route:
@app.route('/user/<username>')
def handler(username):
pass
Весной это казалось мне удачным. Даже сделал что-то похожее в
aiorest.
Потом понял, что штука абсолютно бесполезная: нам всегда
требовалось что-то из HTTP HEADERS, COOKIES и GET/POST parameres в
обработчике запроста.
Чтобы проверить -- авторизирован ли пользователь, например.
Выпилил.
С другой стороны проблема правильных параметров для обработчика не
имеет красивого решения.
route args, GET, POST, COOKIES -- каждый dict может иметь
перекрывающиеся имена-названия.
Паша Коломиец в zorro попытался
решить проблему через аннотации:
def handler(self, request: Request):
pass
Т.е. handler имеет параметр с аннотацией Request -- он получит в
него request object.
В zorro можно регистрировать свои аннотации для получения
дополнительной информации.
Симпатично и элегантно -- но слишком сложно для библиотеки для чайников.
Это путь настоящих джедаев -- я же в последние годы пропагандирую
применять метапрограммирование как можно реже: когда без трюка совсем
не обойтись и его применение настолько простое и очевидное, что
ошибиться просто невозможно.
Заключение
Я не призываю не использовать flask, у меня нет такой цели. Хотите
граблей -- получайте.
Просто сейчас я занялся добавлением в
aiohttp WEB-сервера, пригодного для
использования простым программистом.
И я точно знаю, чего не будет в aiohttp -- контекстных переменных
и зависимостей на этапе импорта.
aiohttp.web должен быть прост насколько это возможно, но не проще.
Желающие выстрелить себе в ногу пусть делают это в библиотеках,
построенных на основе aiohttp.web -- мы дадим им такую возможность.
Базис должен быть простым и дуракоустойчивым -- даже если для этого
придётся написать несколько лишних строк кода.