When running my tornado script which should send a request and get the body of the response and append this to some html code on a localhost port. However, I get this error:
TypeError: init() got an unexpected keyword argument 'callback'
It turns out from the documentation Asynchronous HTTP client that the callback has been removed for Future
Changed in version 6.0: The callback argument was removed. Use the returned Future instead.
There are a lack of effective examples and so what is the most appropriate method to use Future in replacement for callback in my script?
import asyncio
import os
import json
import tornado.httpclient
import tornado.web
import tornado.httpserver
import tornado.gen
from tornado.options import define, options
define('port', default = 9060, help="run port 9060", type=int)
class requestFour(tornado.web.RequestHandler):
#tornado.gen.coroutine
def get(self):
#arg = self.get_argument('stock')
client = tornado.httpclient.AsyncHTTPClient()
yield client.fetch('https://books.toscrape.com', callback=self.on_response)
def on_response(self, response):
body = json.load(response.body)
self.write("""
<div style="text-align: center">
<div style="font-size: 72px">%s</div>
<div style="font-size: 144px">%.02f</div>
<div style="font-size: 24px">tweets per second</div>
</div>
""" % (body))
self.finish()
def my_app():
app = tornado.web.Application(handlers = [(r'/', requestFour)])
http_server = tornado.httpserver.HTTPServer(app)
return http_server
async def main():
app = my_app()
app.listen(options.port)
shutdown_event = asyncio.Event()
await shutdown_event.wait()
if __name__ == '__main__':
asyncio.run(main())
You can just call self.on_response directly:
response = yield client.fetch('https://books.toscrape.com')
self.on_response(response)
Additional notes:
Make your life easier by ditching #gen.coroutine and yield and switching to async/await:
async def get(self):
#arg = self.get_argument('stock')
client = tornado.httpclient.AsyncHTTPClient()
response = await client.fetch('https://books.toscrape.com')
self.on_response(response)
Related
This is a Python code for a Tornado web application. The code defines two classes, BaseHandler and MainHandlerIndex, both of which inherit from the Tornado web library's RequestHandler. The BaseHandler class has a method, "get_username_id_get_data", which returns the username ID obtained from a "get_data" module. The MainHandlerIndex class has a "get" method decorated with the "#decoradores.authenticated" and "#gen.coroutine" decorators, which handles incoming GET requests. This method retrieves the username cookie, obtains the username ID using the "get_username_id_get_data" method, and then renders an HTML template "index/index.html" with the title, items, username, and version as variables.
import tornado.web
from tornado import gen
from functools import wraps
import modulos.decoradores as decoradores
import modulos.get_data as get_data
import logging
logging.basicConfig(level=logging.DEBUG)
import tracemalloc; tracemalloc.start()
class BaseHandler(tornado.web.RequestHandler):
async def get_username_id_get_data(self):
print("soy basehandler y estoy siendo ejecutado....")
username_id = await get_data.primero_redis_segundo_query("user", "('username', '=', 'test')", 'x')
print("get_username_id_get_data: ", username_id)
return username_id
class MainHandlerIndex(BaseHandler):
#decoradores.authenticated
#gen.coroutine
async def get(self):
print("Iniciando MainHandlerIndex metodo: GET")
username_cookie_pre = self.get_secure_cookie("user")
username_cookie = username_cookie_pre.decode()
#username_cookie = 'test'
username_id = await self.get_username_id_get_data()
version = self.application.settings['valores_entorno']['version']
print("###########################################################################")
print("00_username_cookie------------>",username_cookie )
print("11_username_id------------>",username_id )
print("22_version------------>",version )
print("###########################################################################")
items_test = ["Item 1_index", "Item 2_index", "Item 3_index"]
#items_test = []
self.render("index/index.html", title="test", items=items_test, username=str(username_cookie).strip("\""), version=version)
This is the contents of the file index.py:
import asyncio
import os
import tornado.web
#----------------------------#
# Definir entorno #
#----------------------------#
from config import Settings, PreProductionSettings, ProductionSettings
import tornado.options
tornado.options.parse_config_file('config.py')
valores_entorno = PreProductionSettings()
#print(tornado.options.options.version)
#----------------------------#
# Handlers from modules #
#----------------------------#
from blueprints.test.handlers import MainHandlerTest #TEST <-- Borrar....from blueprints.index.handlers import MainHandlerIndex #Index
from blueprints.rid_propios.ri_handlers import MainHandlerRid_Propio_Index #Remote_id_propios
from blueprints.login.login_handlers import MainHandlerLogin, LogoutHandler, RegisterHandler, ConfirmeHandler
from blueprints.index.handlers import MainHandlerIndex
#----------------------------#
# Módulos del proyecto #
#----------------------------#
import modulos.gestiondb as gestiondb
import modulos.redis_stack as redisstack
import modulos.tablas as Tablas
from aiopg.sa import create_engine
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
print("BASE_DIR: ", BASE_DIR)
engine = create_engine(
user=tornado.options.options.user,
database=tornado.options.options.database,
host=tornado.options.options.host,
password=tornado.options.options.password,
)
def make_app():
settings = {
"template_path": os.path.join(os.path.dirname(__file__), "templates"), #/home/developer/xrig_torado/web/web/blueprints/base/templates
"blueprints_path": os.path.join(os.path.dirname(__file__), "web/blueprints"), #/home/developer/xrig_torado/web/web/blueprints
"static_path": os.path.join(os.path.dirname(__file__), "static"), #/home/developer/xrig_torado/web/static
"cookie_secret": tornado.options.options.cookie_secret,
"login_url": "/login",
"xsrf_cookies": True,
"valores_entorno": tornado.options.options
}
handlers = (
(r'/', MainHandlerIndex),
(r'/login', MainHandlerLogin),
(r'/logout', LogoutHandler),
(r'/register', RegisterHandler),
(r'/confirmar', ConfirmeHandler),
(r'/test', MainHandlerTest),
(r'/rid_propios_index', MainHandlerRid_Propio_Index)
)
return tornado.web.Application(
handlers,
debug = True,
autoreload = True,
**settings,
#db = db
db_engine = engine,
)
async def main():
app = make_app()
app.listen(tornado.options.options.puerto_xrig)
#await asyncio.Event().wait()
await asyncio.Event().wait()
print(f'🌐 Server is listening on localhost on port {tornado.options.options.puerto_xrig}')
#Comprobando que existen la tablas del proyecto:
db_dsn = tornado.options.options.dsn
#lista_tablas = [gestiondb.tbl_benchmark, gestiondb.alpha, gestiondb.user, ]
lista_tablas = [Tablas.tbl_benchmark, Tablas.alpha, Tablas.user, Tablas.rid, Tablas.rid_propio ]
await gestiondb.rutina_alta_db_proyecto(db_dsn, lista_tablas)
#Comprobaciones Redis Stack.
await redisstack.lista_tablas_para_volcar_en_redis()
shutdown_event = asyncio.Event()
await shutdown_event.wait()
if __name__ == "__main__":
asyncio.run(main())
The extension starts correctly, does the login process and once the authenticated user is when I make a redirect to the root path / (this is where I can not operate a code that can call asynchronous functions). I have tried to follow several examples and there is no way the error is always:
http://http://192.168.196.49:8888/ (depués del proceso login)
[I 230205 19:48:57 web:2271] 200 GET / (192.168.196.4) 14.50ms
/usr/lib/python3.9/asyncio/events.py:80: RuntimeWarning: coroutine 'MainHandlerIndex.get' was never awaited
self._context.run(self._callback, *self._args)
Object allocated at (most recent call last):
File "/home/developer/xrig_torado/lib/python3.9/site-packages/tornado/gen.py", lineno 216
result = ctx_run(func, *args, **kwargs)
[W 230205 19:48:57 web:2271] 404 GET /favicon.ico (192.168.196.4) 7.46ms
I do NOT find enough documentation that explains an architecture to do this kind of thing. The intention is in the requestHandler in the GET or POST method to develop code and be able to call asynchronous functions.
I have requirement to stream huge oracle record set in Python rest API. I am running flask on tornado server. when I use tornado streaming dosent work, whereas on flask native server(werkzeung) it works perfectly. can anyone help me tornado support streaming or not?
Here is a small sample of code just trying to stream by using yield.
import tornado.web
from tornado import gen, httpclient
import asyncio, json, time
class basicReuqestHandler(tornado.web.RequestHandler):
def get(self):
self.write("Helow World!")
class staticReuqestHandler(tornado.web.RequestHandler):
def get(self):
self.render("index.html")
class StreamingHandler(tornado.web.RequestHandler):
#gen.coroutine
def get(self):
self.write("starting ....")
def stream():
a = 1
for i in range(100):
a = a+i
print(i)
print(json.dumps(i))
yield json.dumps(i)
self.write(stream())
self.write("closing...")
self.finish()
if __name__=='__main__':
app = tornado.web.Application([
(r"/", basicReuqestHandler),
(r"/myPage",staticReuqestHandler ),
(r"/StreamTest", StreamingHandler),
])
app.listen(7000)
tornado.ioloop.IOLoop.current().start()
I got my mistake, so answering to my question here to help anyone having similar issue.
here is the code:
import tornado.web
from tornado import gen, httpclient
import asyncio, json, time
class basicReuqestHandler(tornado.web.RequestHandler):
def get(self):
self.write("Helow World!")
class staticReuqestHandler(tornado.web.RequestHandler):
def get(self):
self.render("index.html")
class StreamingHandler(tornado.web.RequestHandler):
#gen.coroutine
def get(self):
self.write("starting ....")
def stream():
for i in range(100):
print(i)
print(json.dumps(i))
self.write(json.dumps(i))
yield self.flush()
self.write("closing...")
self.finish()
if __name__=='__main__':
app = tornado.web.Application([
(r"/", basicReuqestHandler),
(r"/myPage",staticReuqestHandler ),
(r"/StreamTest", StreamingHandler),
])
app.listen(7000)
tornado.ioloop.IOLoop.current().start()
To give you an idea of what I am trying to accomplish with Twisted Web and Autobahn websockets: my UI currently sends an initial HTTP GET request with an upgrade to a websocket in the header. Upon reading that in Twisted Web, the connection needs to switch from HTTP to a websocket protocol to pass data back and forth. Note that this websocket upgrade happens on the same port, port 8000.
Does anyone know how I can implement what I am trying to do? Thank you so much.
EDIT: updated code for working example. You can find it here: Payload from POST Request is Cutoff (Twisted Web)
Here is my code using Twisted Web:
class HttpResource(resource.Resource):
isLeaf = 1
def __init__(self):
self.children = {}
self.ws_port = None
print 'resource invoked'
def render_GET(self, request):
print 'render invoked'
if request.getHeader('Sec-WebSocket-Key'):
# Processing the Key as per RFC 6455
key = request.getHeader('Sec-WebSocket-Key')
h = hashlib.sha1(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
request.setHeader('Sec-WebSocket-Accept', base64.b64encode(h.digest()))
# setting response headers
request.setHeader('Upgrade', 'websocket')
request.setHeader('Connection', 'Upgrade')
request.setResponseCode(101)
return ''
else:
log("Regular HTTP GET request.")
return "<html><body style='margin: 0; overflow: hidden;'><iframe style='width: 100%; height: 100%; border: none;' src='http://tsa-graphiql.herokuapp.com/'></iframe></body></html>"
def render_POST(self,request):
log("POST request")
request.setResponseCode(200)
def handle_single_query(self, queryData):
log("Handle single query data.")
return
class HttpWsChannel(http.HTTPChannel):
def dataReceived(self, data):
log('Data received:\n{}'.format(data))
if data.startswith('GET'):
# This will invoke the render method of resource provided
http.HTTPChannel.dataReceived(self, data)
if data.startswith('POST'):
http.HTTPChannel.dataReceived(self, data)
else:
"""
Pass binary data to websocket class.
"""
ws_protocol = self.site.ws_factory.protocol(self.site.ws_factory.connection_subscriptions)
log(ws_protocol)
#just echo for now
# self.transport.write(data)
class HttpFactory(Site):
"""
Factory which takes care of tracking which protocol
instances or request instances are responsible for which
named response channels, so incoming messages can be
routed appropriately.
"""
def __init__(self, resource):
http.HTTPFactory.__init__(self)
self.resource = resource
self.ws_factory = WsProtocolFactory("ws://127.0.0.1:8000")
self.ws_factory.protocol = WsProtocol
def buildProtocol(self, addr):
try:
channel = HttpWsChannel()
channel.requestFactory = self.requestFactory
channel.site = self
return channel
except Exception as e:
log("Could not build protocol: {}".format(e))
site = HttpFactory(HttpResource())
if __name__ == '__main__':
reactor.listenTCP(8000, site)
reactor.run()
EDIT 7/8/2017: Here is the new code I am trying below. The websocket messages are received successfully via the onMessage method. However the HTTP requests are not working. The current error I am getting on a GET request is:
<html>
<head><title>404 - No Such Resource</title></head>
<body>
<h1>No Such Resource</h1>
<p>No such child resource.</p>
</body>
</html>
Python code
from twisted.web.server import (
Site,
)
from twisted.internet import reactor
from twisted.web.resource import (
Resource,
)
from autobahn.twisted.websocket import (
WebSocketServerProtocol,
WebSocketServerFactory,
)
from autobahn.twisted.resource import (
WebSocketResource,
)
class WebSocketProtocol(WebSocketServerProtocol):
def onConnect(self, request):
print("WebSocket connection request: {}".format(request))
def onMessage(self, payload, isBinary):
print("onMessage: {}".format(payload))
if __name__ == '__main__':
factory = WebSocketServerFactory()
factory.protocol = WebSocketProtocol
resource = WebSocketResource(factory)
root = Resource()
root.putChild(b"ws", resource)
site = Site(root)
reactor.listenTCP(8000, site)
reactor.run()
Use WebSocketResource to expose a WebSocketServerFactory as part of a Site.
from twisted.web.server import (
Site,
)
from twisted.web.resource import (
Resource,
)
from autobahn.twisted.websocket import (
WebSocketServerProtocol,
WebSocketServerFactory,
)
from autobahn.twisted.resource import (
WebSocketResource,
)
class YourAppProtocol(WebSocketServerProtocol):
def onConnect(self, request):
...
...
def main():
factory = WebSocketRendezvousFactory()
factory.protocol = YourAppProtocol
resource = WebSocketResource(factory)
root = Resource()
root.putChild(b"some-path-segment", resource)
root.putChild(...)
site = Site(root)
reactor.listenTCP(8080, site)
reactor.run()
The problems with truncated request bodies is probably because your upgrade protocol implementation is buggy. There is no framing applied at the level of dataReceived so you can't expect checks like startswith("GET") to be reliable.
Using WebSocketResource and Site gives you the correct HTTP parsing code from Twisted Web and Autobahn while also allowing you to speak WebSocket to a particular URL and regular HTTP to others.
So after reading a little bit on Google, I found this website that explains how to upgrade the HTTP connection to a websocket connection via Autobahn Twisted: Read and Set request headers via Autobahn Twisted.
The code that I was able to get to work is shown below!
from twisted.web.server import (
Site,
)
from twisted.internet import reactor
from twisted.web.resource import (
Resource,
)
from autobahn.twisted.websocket import (
WebSocketServerProtocol,
WebSocketServerFactory,
)
from autobahn.twisted.resource import (
WebSocketResource,
)
class HttpResource(Resource):
isLeaf = True
def render_GET(self, request):
return "<html><body style='margin: 0; overflow: hidden;'><iframe style='width: 100%; height: 100%; border: none;' src='http://tsa-graphiql.herokuapp.com/'></iframe></body></html>"
class WebSocketProtocol(WebSocketServerProtocol):
def onConnect(self, request):
custom_header = {}
if request.headers['sec-websocket-key']:
custom_header['sec-websocket-protocol'] = 'graphql-ws'
return (None, custom_header)
def onMessage(self, payload, isBinary):
print("onMessage: {}".format(payload))
if __name__ == '__main__':
factory = WebSocketServerFactory()
factory.protocol = WebSocketProtocol
resource = WebSocketResource(factory)
root = Resource()
root.putChild("", HttpResource())
root.putChild(b"ws", ws_resource)
site = Site(root)
reactor.listenTCP(8000, site)
I am currently trying to use tornado to display my twitter streams. Below is my code:
#!/usr/bin/env python
import time
import logging
from tornado.auth import TwitterMixin
from tornado.escape import json_decode, json_encode
from tornado.ioloop import IOLoop
from tornado import gen
from tornado.options import define, options, parse_command_line, parse_config_file
from tornado.web import Application, RequestHandler, authenticated, HTTPError
define('port', default=8080, help="port to listen on")
define('config_file', default='secrets.cfg',
help='filename for additional configuration')
define('debug', default=True, group='application',
help="run in debug mode (with automatic reloading)")
# The following settings should probably be defined in secrets.cfg
define('twitter_consumer_key', type=str, group='application')
define('twitter_consumer_secret', type=str, group='application')
define('cookie_secret', type=str, group='application',
default='this is a string',
help="signing key for secure cookies")
class BaseHandler(RequestHandler):
COOKIE_NAME = "uuser"
def get_current_user(self):
user_json = self.get_secure_cookie(self.COOKIE_NAME)
if not user_json:
print(" No user_json")
return None
print(" Yes user_json")
return json_decode(user_json)
class MainHandler(BaseHandler, TwitterMixin):
#authenticated
#gen.coroutine
def get(self):
timeline = yield self.twitter_request(
'/statuses/home_timeline',
access_token = self.current_user['access_token'])
self.render('home.html', timeline=timeline)
class LoginHandler(BaseHandler, TwitterMixin):
#gen.coroutine
def get(self):
if self.get_argument('oauth_token', None):
user = yield self.get_authenticated_user()
print(' user:', type(user))
del user["description"]
self.set_secure_cookie(self.COOKIE_NAME, json_encode(user))
print(' get_secure_cookie:', self.get_secure_cookie(self.COOKIE_NAME) )
self.redirect(self.get_argument('next', '/'))
else:
print(" Authorize_redirecting...")
yield self.authorize_redirect(callback_uri=self.request.full_url())
class LogoutHandler(BaseHandler):
def get(self):
self.clear_cookie("user")
def main():
parse_command_line(final=False)
parse_config_file(options.config_file)
app = Application(
[
(r'/', MainHandler),
(r'/login', LoginHandler),
(r'/logout', LogoutHandler),
],
login_url='/login',
**options.group_dict('application'))
app.listen(options.port)
logging.info('Listening on http://localhost:%d' % options.port)
IOLoop.current().start()
if __name__ == '__main__':
main()
So my understanding of the flow is as follows:
1.) Visit '/' - MainHandler, the #authenticated will redirect to login_url if the user is not logged in.
2.) Visit '/login' - LoginHandler, self.authorize_redirect(callback_uri=self.request.full_url()) will append oauth_token argument at the end of url, and re-visit '/login'
3.) Visit'/login' - LoginHandler, obtain user from self.get_authenticated_user(), and set_secure_cookie(self.COOKIE_NAME, json_encode(user))
And here is the problem I think, I can't seem to set the cookie. When I try to access it immediately by self.get_secure_cookie(self.COOKIE_NAME), it returns None, and hence it keeps on re-visiting '/login'
Can anybody offer some help to my problem? Maybe it is something very obvious I am not seeing. Thanks
I have also set http://127.0.0.1:8080/ as the callback url on my twitter app setting, not sure if this has any contribution to the problem.
Final solution!!
#!/usr/bin/env python
import time
import uuid
import logging
from tornado.auth import TwitterMixin
from tornado.escape import json_decode, json_encode, url_escape, url_unescape
from tornado.ioloop import IOLoop
from tornado import gen
from tornado.options import define, options, parse_command_line, parse_config_file
from tornado.web import Application, RequestHandler, authenticated, HTTPError
from urllib.parse import quote
import re
define('port', default=8080, help="port to listen on")
define('config_file', default='secrets.cfg',
help='filename for additional configuration')
define('debug', default=True, group='application',
help="run in debug mode (with automatic reloading)")
# The following settings should probably be defined in secrets.cfg
define('twitter_consumer_key', type=str, group='application')
define('twitter_consumer_secret', type=str, group='application')
# define('cookie_secret', type=str, group='application',
# default='thisisastring',
# help="signing key for secure cookies")
class BaseHandler(RequestHandler):
COOKIE_NAME = "user"
def get_current_user(self):
user_json = self.get_cookie(self.COOKIE_NAME)
if not user_json:
print("\n - Cannot obtain cookie from client browser")
return None
print("\n - Cookie obtained from client browser")
return json_decode(user_json)
class MainHandler(BaseHandler, TwitterMixin):
#authenticated
#gen.coroutine
def get(self):
print("\n - Obtaining timeline from twitter")
timeline = yield self.twitter_request(
'/statuses/home_timeline',
access_token = self.current_user)
self.render('home.html', timeline=timeline)
class LoginHandler(BaseHandler, TwitterMixin):
#gen.coroutine
def get(self):
if self.get_argument('oauth_token', None):
print("\n - Authenticating with oauth_token...")
user = yield self.get_authenticated_user()
encoded_token = json_encode(user['access_token'])
# remove certain ascii symbols which are rejected
# by self.set_cookie() function...
encoded_token = re.sub(r"[\x00-\x20]", '', encoded_token)
# save encoded token as cookie
self.set_cookie(name=self.COOKIE_NAME, value=encoded_token)
self.redirect(self.get_argument('next', '/'))
else:
print("\n - Authorize_redirecting...")
yield self.authorize_redirect(callback_uri=self.request.full_url())
class LogoutHandler(BaseHandler):
def get(self):
self.clear_cookie(self.COOKIE_NAME)
def main():
parse_command_line(final=False)
parse_config_file(options.config_file)
app = Application(
[
(r'/', MainHandler),
(r'/login', LoginHandler),
(r'/logout', LogoutHandler),
],
login_url='/login',
cookie_secret=str(uuid.uuid4().bytes),
**options.group_dict('application'))
app.listen(options.port)
logging.info('Listening on http://localhost:%d' % options.port)
IOLoop.current().start()
if __name__ == '__main__':
main()
I'm creating a web application in python using tornado web server. I'm using Motor for mongo db connection with tornado web server.
i'm referring to tornado motor docs.
in my application i'm uploading data from csv or other data sources and doing some machine learning operations. all the meta data and other required details have to be stored in mongo DB. Web page is a little heavy(as it has a lot of visualizations other operations).
Some examples i tried for learning motor
Example of call back:
import tornado.web, tornado.ioloop
import motor
class NewMessageHandler(tornado.web.RequestHandler):
def get(self):
"""Show a 'compose message' form."""
self.write('''
<form method="post">
<input type="text" name="msg">
<input type="submit">
</form>''')
# Method exits before the HTTP request completes, thus "asynchronous"
#tornado.web.asynchronous
def post(self):
"""Insert a message."""
msg = self.get_argument('msg')
# Async insert; callback is executed when insert completes
self.settings['db'].messages.insert(
{'msg': msg},
callback=self._on_response)
def _on_response(self, result, error):
if error:
raise tornado.web.HTTPError(500, error)
else:
self.redirect('/')
class MessagesHandler(tornado.web.RequestHandler):
#tornado.web.asynchronous
def get(self):
"""Display all messages."""
self.write('Compose a message<br>')
self.write('<ul>')
db = self.settings['db']
db.messages.find().sort([('_id', -1)]).each(self._got_message)
def _got_message(self, message, error):
if error:
raise tornado.web.HTTPError(500, error)
elif message:
self.write('<li>%s</li>' % message['msg'])
else:
# Iteration complete
self.write('</ul>')
self.finish()
db = motor.MotorClient().test
application = tornado.web.Application(
[
(r'/compose', NewMessageHandler),
(r'/', MessagesHandler)
],
db=db
)
#print 'Listening on http://localhost:8888'
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
Example of coroutines:
from tornado import gen
import tornado.web, tornado.ioloop
import motor
class NewMessageHandler(tornado.web.RequestHandler):
def get(self):
"""Show a 'compose message' form."""
self.write('''
<form method="post">
<input type="text" name="msg">
<input type="submit">
</form>''')
#tornado.web.asynchronous
#gen.coroutine
def post(self):
"""Insert a message."""
msg = self.get_argument('msg')
db = self.settings['db']
# insert() returns a Future. Yield the Future to get the result.
result = yield db.messages.insert({'msg': msg})
# Success
self.redirect('/')
class MessagesHandler(tornado.web.RequestHandler):
#tornado.web.asynchronous
#gen.coroutine
def get(self):
"""Display all messages."""
self.write('Compose a message<br>')
self.write('<ul>')
db = self.settings['db']
cursor = db.messages.find().sort([('_id', -1)])
while (yield cursor.fetch_next):
message = cursor.next_object()
self.write('<li>%s</li>' % message['msg'])
# Iteration complete
self.write('</ul>')
self.finish()
db = motor.MotorClient().test
application = tornado.web.Application(
[
(r'/compose', NewMessageHandler),
(r'/', MessagesHandler)
],
db=db
)
print 'Listening on http://localhost:8881'
application.listen(8881)
tornado.ioloop.IOLoop.instance().start()
How do i compare the benefits or performance of each example ? Both example do the same functionality.
What should i use ? callbacks, co-routines, generators ? I need good performance and flexibility in my application. there are some examples in this link also https://motor.readthedocs.org/en/stable/tutorial.html