Skip to content

Instantly share code, notes, and snippets.

@codeboy
Last active August 30, 2015 14:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save codeboy/dc8a3c57c780994ef557 to your computer and use it in GitHub Desktop.
Save codeboy/dc8a3c57c780994ef557 to your computer and use it in GitHub Desktop.
Example Python3 Tornado + asyncio + peewee_async + aiomcache (this is for Hearthstone card parser)
# coding: utf-8
from tornado.options import options, define, parse_command_line
import tornado.httpserver
import tornado.ioloop
import tornado.web
import tornado.wsgi
import os
import asyncio
import aiomcache
import peewee_async
import tornado_settings.t_settings as TS
from routes import ROUTES
define('port', type=int, default=TS.PORT)
class Application(tornado.web.Application):
def __init__(self):
parse_command_line()
tornado.options.define('debug', default=True)
# Prepare IOLoop class to run instances on asyncio
tornado.ioloop.IOLoop.configure('tornado.platform.asyncio.AsyncIOMainLoop')
handlers = ROUTES
handlers += [
(r"/static/(.*)", tornado.web.StaticFileHandler, {"path": TS.STATIC_PATH}),
]
settings = {
'template_path' : TS.TEMPLATE_PATH,
'debug' : TS.DEBUG,
'static_path': TS.STATIC_PATH,
'st': TS.STATIC_PATH,
'cookie_secret' : TS.COOKIE_SECRET
}
super().__init__(handlers, **settings)
def start_loops(self, loop):
enable_json = False
# self.loop = loop
self.database = peewee_async.PostgresqlDatabase('pyccg',
user=TS.USER, password=TS.PASSWORD, host=TS.SERVER_IP, port='5432')
loop.run_until_complete(self.database.connect_async(loop=loop))
self.mc = aiomcache.Client("127.0.0.1", 11211, loop=loop)
if __name__ == "__main__":
# print("Run Tornado ... http://{0}:{1}".format(TS.SERVER_IP, TS.PORT))
application = Application()
application.listen(TS.PORT)
loop = asyncio.get_event_loop()
application.start_loops(loop)
loop.run_forever()
import asyncio
import tornado.ioloop
import tornado.web
import tornado.gen
from tornado.httpclient import AsyncHTTPClient
class AsyncRequestHandler(tornado.web.RequestHandler):
"""
https://github.com/rudyryk/python-samples/blob/master/hello_tornado/hello_asyncio.py
Base class for request handlers with `asyncio` coroutines support.
It runs methods on Tornado's ``AsyncIOMainLoop`` instance.
Subclasses have to implement one of `get_async()`, `post_async()`, etc.
Asynchronous method should be decorated with `@asyncio.coroutine`.
Usage example::
class MyAsyncRequestHandler(AsyncRequestHandler):
@asyncio.coroutine
def get_async(self):
html = yield from self.application.http.get('http://python.org')
self.write({'html': html})
You may also just re-define `get()` or `post()` methods and they will be simply run
synchronously. This may be convinient for draft implementation, i.e. for testing
new libs or concepts.
"""
@tornado.gen.coroutine
def get(self, *args, **kwargs):
"""Handle GET request asyncronously, delegates to
``self.get_async()`` coroutine.
"""
yield self._run_method('get', *args, **kwargs)
@tornado.gen.coroutine
def post(self, *args, **kwargs):
"""Handle POST request asyncronously, delegates to
``self.post_async()`` coroutine.
"""
yield self._run_method('post', *args, **kwargs)
@asyncio.coroutine
def _run_async(self, coroutine, future_, *args, **kwargs):
"""Perform coroutine and set result to ``Future`` object."""
try:
result = yield from coroutine(*args, **kwargs)
future_.set_result(result)
except Exception as e:
future_.set_exception(e)
print(traceback.format_exc())
def _run_method(self, method_, *args, **kwargs):
"""Run ``get_async()`` / ``post_async()`` / etc. coroutine
wrapping result with ``tornado.concurrent.Future`` for
compatibility with ``gen.coroutine``.
"""
coroutine = getattr(self, '%s_async' % method_, None)
if not coroutine:
raise tornado.web.HTTPError(405)
future_ = tornado.concurrent.Future()
asyncio.async(
self._run_async(coroutine, future_, *args, **kwargs)
)
return future_
def initialize(self):
self.context = dict()
# coding: utf-8
from tornado_apps.BaseAsyncHandler import AsyncRequestHandler
import asyncio
import aiomcache
import json
from tornado_apps.models import Card
from tornado_apps.db_queries import save_card, get_card
class Struct(object):
def __init__(self, **entries):
self.__dict__.update(entries)
class CardParseAHandler(AsyncRequestHandler):
@asyncio.coroutine
def get_async(self):
context = self.context
cards_packs=['Basic', 'Expert', 'Curse of Naxxramas']
counter_all = 0
counter_new = 0
counter_old = 0
for i in cards_packs:
pack = yield from self.process_data('upload/AllSets.enUS.json', i)
for card in pack:
is_new = yield from save_card(self.application.database, **card)
counter_all +=1
if is_new: counter_new +=1
else:counter_old += 1
context['packs'] = cards_packs
context['counter_all'] = counter_all
context['counter_new'] = counter_new
context['counter_old'] = counter_old
self.render('cards-parsing.html', **context)
@asyncio.coroutine
def open_file(self, name):
f = open(name, encoding='cp1251')
return f
@asyncio.coroutine
def close_file(self, file):
file.close()
@asyncio.coroutine
def read_data(self, file):
loop = asyncio.get_event_loop()
data = yield from loop.run_in_executor(None, file.read)
return data
@asyncio.coroutine
def process_data(self, filename, pack):
file = yield from asyncio.async(self.open_file(filename))
data = yield from self.read_data(file)
yield from self.close_file(file)
data = json.loads(data)
cards_list = data[pack]
return cards_list
from random import randint
class CardGetAHandler(AsyncRequestHandler):
@asyncio.coroutine
def get_async(self):
context = self.context
fields_dict = Card._meta.fields
fields_list = list()
for k in fields_dict:
fields_list.append(k)
cid = randint(1,50)
mcached_card = yield from self.get_chached_card(cid)
if mcached_card:
print('cached card')
card = json.loads(mcached_card)
card = Struct(**card) # create object from dict
else:
print('new card')
card = yield from get_card(self.application.database, cid)
card_dict = dict()
# prepare dictionary from object
for i in Card._meta.fields:
i_attr = getattr(card,i)
card_dict[i] = i_attr
card_json = json.dumps(card_dict)
yield from self.set_chached_card(cid, card_json)
context['card'] = card
self.render('card-view.html', **context)
# self.render('main.html', **context)
@asyncio.coroutine
def get_chached_card(self, cid):
"""
try to get card from memcache
:param cid: card id
:return: decoded string from bytecode
"""
# mc = aiomcache.Client("127.0.0.1", 11211, loop=self.application.loop)
# mc = self.application.mc
b_cid = str.encode('c=%s'%cid)
value = yield from self.application.mc.get(b_cid)
if value:
value = value.decode()
return value
@asyncio.coroutine
def set_chached_card(self, cid, cdata):
"""
save card to memcache
:param cid: card id
:param cdata: dict translated to json string
"""
b_cid = str.encode('c=%s'%cid)
b_cdata = str.encode(cdata)
# print(b_cdata)
yield from self.application.mc.set(b_cid, b_cdata)
# coding: utf-8
from tornado_apps.BaseHandler import BaseHandler
from tornado import gen
import asyncio
from tornado_apps.BaseAsyncHandler import AsyncRequestHandler
class HomeHandler(BaseHandler):
@gen.coroutine
def get(self):
context = dict()
context = self.context
context['status'] = "work in progress"
self.render('main.html', **context)
from tornado_apps.db_queries import get_users
class HomeAsyncHandler(AsyncRequestHandler):
@asyncio.coroutine
def get_async(self):
database = self.application.database
context = dict()
context = self.context
context['status'] = "work in progress"
self.render('main.html', **context)
# coding: utf-8
import tornado.web
from tornado_apps import (
BaseHandler,
HomeHandler,
# ErrorsHandler,
# UserHandler,
CardParsing,
WebSocketHandler,
)
# there is routes for all parts of project
ROUTES = [
(r'/', HomeHandler.HomeAsyncHandler),
(r'/cards-parsing/?', CardParsing.CardParseAHandler),
(r'/ws/', WebSocketHandler.WebSocketBase),
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment