Last active
August 30, 2015 14:51
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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