python

Torskel — упрощаем рутину в Tornado

  • четверг, 23 ноября 2017 г. в 03:13:53
https://habrahabr.ru/post/342968/
  • Python


Мне часто приходится делать небольшие сервера на tornado. В каких-то проектах нужна поддержка работы с redis, в каких-то нет. В других надо рендерить ReactJS. И во всех нужно логирование. Для начала я поднял локальный pypi репозитарий, собрал свои наработки в питоний пакет и радовался жизни. Достаточно было установить пакет, импортировать из него классы, отнаследоваться и радостно пилить код дальше.

А потом появилась мысль — а не поделиться ли своими наработками с людьми? Итак представляю вашему вниманию пакет torskel.

Сразу оговорюсь, что он дружит только с Python 3.5+ т. к. во всю использует async/await.

Это обёртка над торнадо, которая позволяет получить из коробки базовый функционал:

Установка библиотеки — pip install torskel

Асинхронная работа с Redis


По умолчанию выключена, чтобы включить надо установить опцию use_redis в True и сделать pip install aioredis

Пример использования:

import asyncio
from torskel.torskel_app import TorskelServer
from torskel.torskel_handler import TorskelHandler
import tornado.web

from tornado.options import options


options.define('use_redis', default=True, help='use redis', type=bool)

class RedisApplication(TorskelServer):
    def __init__(self, handlers, **settings):
        super().__init__(handlers, **settings)
        self.greeting = 'Hello redis!'


class RedisHandler(TorskelHandler):
    async def get(self):
        my_key = self.get_hash_str('my_key')
        await self.set_redis_exp_val(my_key, self.application.greeting, 3000, convert_to_json=False)
        res = await self.get_redis_val(my_key, from_json=False)
        self.write(res)
        await self.del_redis_val(my_key)
        self.finish()

redis_app = RedisApplication(handlers=[(r"/", RedisHandler)])

if __name__ == '__main__':
    redis_app.listen(8888)
    loop = asyncio.get_event_loop()
    redis_app.init_with_loop(loop)
    loop.run_forever()
    tornado.ioloop.IOLoop.instance().start()

Список доступных опций со значениями по умолчанию:

Определяет надо ли вообще использовать редис

use_redis=False

По умолчанию подключение через сокет файл

use_redis_socket=True

Создаем пул коннектов — минимум 5, максимум 10

redis_min_con=5
redis_max_con=10

Как попасть в редис?

redis_host='127.0.0.1'
redis_port=6379
redis_socket='/var/run/redis/redis.sock'

Настройка авторизации

redis_psw=''
База по умолчанию
redis_db=1

Шлём логи на почту


Настраивается следующими опциями:

options.define('use_mail_logging', default=False, help='SMTP log handler', type=bool)
options.define("log_mail_subj", default='', type=str)
options.define("log_mail_from", default='', type=str)
options.define("log_mail_to", default=[], type=list)
options.define("log_mail_host", default='', type=str)
options.define("log_mail_user", default='', type=str)
options.define("log_mail_psw", default='', type=str)

Думаю, здесь особых пояснений не нужно, названия опций говорят сами за себя.

Http запросы


Просто обёртка над стандартным торнадовским AsyncHttpClient

import tornado.web
from torskel.torskel_app import TorskelServer
from torskel.torskel_handler i mport TorskelHandler


class HelloHttpHandler(TorskelHandler):
    async def get(self):
        res = await self.http_request_get('http://example.com')
        self.write(res)
        self.finish()


hello_http_app = TorskelServer(handlers=[(r"/", HelloHttpHandler)])

if __name__ == '__main__':
    hello_http_app.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

Поддержка ReactJS


Включается опцией use_reactjs. Так же надо сделать pip install jinja2 Здесь нам уже понадобится набор js-разработчика, npm, webpack/gulp и прочие babel'ы

Рендер происходит функцией react_render. Предполагается, что вашем html шаблоне, вы подключаете скрипт строчкой

<script src="{{ assets['main']['js'] }}"> </script>

Этот момент довольно тонкий и в будущем я планирую его доработать.

import tornado.web
import os
from tornado.web import url
from tornado.options import options, define
from torskel.torskel_app import TorskelServer
from torskel.torskel_handler import TorskelHandler

settings = {}

options.define('use_reactjs', default=True, help='use reactjs', type=bool)
options.define("react_assets_file", default='webpack-assets.json', type=str)

class MainHandler(TorskelHandler):
    def get(self):
        self.react_render('index.html')
        self.finish()

handlers = [
    url(r"/", MainHandler, name="IndexPage"),

]


class HelloReactApplication(TorskelServer):
    def __init__(self, handlers,  **settings):
        super().__init__(handlers,  **settings)

hello_react = HelloReactApplication(handlers, root_dir=os.path.dirname(__file__), **settings)

if __name__ == "__main__":
    hello_react.listen(options.port)
    tornado.ioloop.IOLoop.current().start()

Это пока альфа-версия библиотеки. В планах еще добавить поддержку создания пулов коннектов к различным базам данных.