Contenido

Python Tornado

Contenido

En esta ocasión trataré de ver cómo utilizar un framework de red, como es el caso de python-tornado.

Crearemos un site pequeño y básico, lo justo como para tener una idea de sus posibilidades.

En cuanto al uso, yo últimamente lo utilizo para todo: desde pequeñas aplicaciones web hasta herramientas de soporte en el escritorio, donde necesito un servidor.

Python

Lo básico

Cuando comenzamos con python-tornado, necesitamos crear una estructura básica:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import tornado.httpserver
import tornado.ioloop
import tornado.web

application = tornado.web.Application()
server = tornado.httpserver.HTTPServer(application)
server.listen(8000)
tornado.ioloop.IOLoop.instance().start()

Es tan básica que no hace nada, pero nos viene bien para explicar la parte común a cualquier cosa que hagamos.

Lo primero es crear nuestra aplicación, que heredará de Application. Luego ejecutamos un servidor HTTP que dé soporte a nuestra aplicación. A continuación indicamos en qué puerto deseamos que escuche el servidor. Finalmente, lanzamos el bucle de eventos que se quedará “a la escucha” de peticiones.

Vamos a complicarlo un poquito más, soportando nuestra primera petición:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import tornado.httpserver
import tornado.ioloop
import tornado.web

handlers = [
    (r"/(.*)", tornado.web.StaticFileHandler, {'path':'.'}),
    ]

application = tornado.web.Application(handlers)
server = tornado.httpserver.HTTPServer(application)
server.listen(8000)
tornado.ioloop.IOLoop.instance().start()

Lo que hemos añadido es un RequestHandler de los proporcionados por Tornado. En este caso, permite servir archivos estáticamente. Como véis, el manejador está asociado a una expresión regular que, en este caso, se ajustará a cualquier cosa. Podemos comprobarlo si accedemos a la URL https://localhost:8000/example.py (asumiendo que hayáis guardado el archivo en “example.py”). Podéis probar a crear otro archivo y ver cómo se puede acceder.

Nuestros propios manejadores

La gracia de esto está en crearnos nuestros propios manejadores:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import tornado.httpserver
import tornado.ioloop
import tornado.web

class HelloworldHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world!")

handlers = [
    (r"/", HelloworldHandler),
    ]

application = tornado.web.Application(handlers)
server = tornado.httpserver.HTTPServer(application)
server.listen(8000)
tornado.ioloop.IOLoop.instance().start()

Python tornado acepta los parámetros “GET” como parámetros de nuestro método “get”:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import tornado.httpserver
import tornado.ioloop
import tornado.web

class HelloworldHandler(tornado.web.RequestHandler):
    def get(self, name):
        if not name:
            name = 'world'
        self.write("Hello, {}!".format(name))

handlers = [
    (r"/(.*)", HelloworldHandler),
    ]

application = tornado.web.Application(handlers)
server = tornado.httpserver.HTTPServer(application)
server.listen(8000)
tornado.ioloop.IOLoop.instance().start()

En este ejemplo, si accedemos a la url https://localhost:8000/ mostrará “Hello, world!”, pero si accedemos a la url: https://localhost:8000/magmax, mostrará “Hello, magmax!”.

Opciones

Una de las características que más me gustan de Tornado es la gestión de opciones. Vamos a establecer el puerto de forma dinámica:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import tornado.httpserver
import tornado.ioloop
import tornado.web
from tornado.options import define, options

class HelloworldHandler(tornado.web.RequestHandler):
    def get(self, name):
        if not name:
            name = 'world'
        self.write("Hello, {}!".format(name))


define('port', default=8000, help='Port to be used')
tornado.options.parse_command_line()

handlers = [
    (r"/(.*)", HelloworldHandler),
    ]

application = tornado.web.Application(handlers)
server = tornado.httpserver.HTTPServer(application)
server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()

Como veréis, es sencillísimo definir nuevas opciones. Y encima, Tornado ya nos da algunas, relacionadas con el logging:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ ./basic.py --help
Usage: ./basic.py [OPTIONS]

Options:

  --help                           show this help information
  --log_file_max_size              max size of log files before rollover
                                   (default 100000000)
  --log_file_num_backups           number of log files to keep (default 10)
  --log_file_prefix=PATH           Path prefix for log files. Note that if you
                                   are running multiple tornado processes,
                                   log_file_prefix must be different for each
                                   of them (e.g. include the port number)
  --log_to_stderr                  Send log output to stderr (colorized if
                                   possible). By default use stderr if
                                   --log_file_prefix is not set and no other
                                   logging is configured.
  --logging=debug|info|warning|error|none
                                   Set the Python log level. If 'none', tornado
                                   won't touch the logging configuration.
                                   (default info)
  --port                           Port to be used (default 8000)
$

Otras características

Tornado tiene otras muchas características. En otro post veremos algunas de ellas. De todas maneras, este post tan solo trata de ser meramente introductorio. Para más información, lo suyo es acceder a la documentación oficial.