Browse Source

Update library: tornado

pull/2742/merge
Ruud 11 years ago
parent
commit
b47a94852a
  1. 4
      libs/tornado/__init__.py
  2. 27
      libs/tornado/auth.py
  3. 11
      libs/tornado/escape.py
  4. 1
      libs/tornado/gen.py
  5. 26
      libs/tornado/ioloop.py
  6. 91
      libs/tornado/log.py
  7. 6
      libs/tornado/platform/asyncio.py
  8. 1
      libs/tornado/platform/caresresolver.py
  9. 1
      libs/tornado/platform/twisted.py
  10. 9
      libs/tornado/web.py

4
libs/tornado/__init__.py

@ -25,5 +25,5 @@ from __future__ import absolute_import, division, print_function, with_statement
# is zero for an official release, positive for a development branch, # is zero for an official release, positive for a development branch,
# or negative for a release candidate or beta (after the base version # or negative for a release candidate or beta (after the base version
# number has been incremented) # number has been incremented)
version = "3.2b1" version = "3.2"
version_info = (3, 2, 0, -98) version_info = (3, 2, 0, 0)

27
libs/tornado/auth.py

@ -36,7 +36,6 @@ Example usage for Google OpenID::
class GoogleLoginHandler(tornado.web.RequestHandler, class GoogleLoginHandler(tornado.web.RequestHandler,
tornado.auth.GoogleMixin): tornado.auth.GoogleMixin):
@tornado.web.asynchronous
@tornado.gen.coroutine @tornado.gen.coroutine
def get(self): def get(self):
if self.get_argument("openid.mode", None): if self.get_argument("openid.mode", None):
@ -607,7 +606,6 @@ class TwitterMixin(OAuthMixin):
class TwitterLoginHandler(tornado.web.RequestHandler, class TwitterLoginHandler(tornado.web.RequestHandler,
tornado.auth.TwitterMixin): tornado.auth.TwitterMixin):
@tornado.web.asynchronous
@tornado.gen.coroutine @tornado.gen.coroutine
def get(self): def get(self):
if self.get_argument("oauth_token", None): if self.get_argument("oauth_token", None):
@ -669,7 +667,6 @@ class TwitterMixin(OAuthMixin):
class MainHandler(tornado.web.RequestHandler, class MainHandler(tornado.web.RequestHandler,
tornado.auth.TwitterMixin): tornado.auth.TwitterMixin):
@tornado.web.authenticated @tornado.web.authenticated
@tornado.web.asynchronous
@tornado.gen.coroutine @tornado.gen.coroutine
def get(self): def get(self):
new_entry = yield self.twitter_request( new_entry = yield self.twitter_request(
@ -748,7 +745,6 @@ class FriendFeedMixin(OAuthMixin):
class FriendFeedLoginHandler(tornado.web.RequestHandler, class FriendFeedLoginHandler(tornado.web.RequestHandler,
tornado.auth.FriendFeedMixin): tornado.auth.FriendFeedMixin):
@tornado.web.asynchronous
@tornado.gen.coroutine @tornado.gen.coroutine
def get(self): def get(self):
if self.get_argument("oauth_token", None): if self.get_argument("oauth_token", None):
@ -793,7 +789,6 @@ class FriendFeedMixin(OAuthMixin):
class MainHandler(tornado.web.RequestHandler, class MainHandler(tornado.web.RequestHandler,
tornado.auth.FriendFeedMixin): tornado.auth.FriendFeedMixin):
@tornado.web.authenticated @tornado.web.authenticated
@tornado.web.asynchronous
@tornado.gen.coroutine @tornado.gen.coroutine
def get(self): def get(self):
new_entry = yield self.friendfeed_request( new_entry = yield self.friendfeed_request(
@ -877,7 +872,6 @@ class GoogleMixin(OpenIdMixin, OAuthMixin):
class GoogleLoginHandler(tornado.web.RequestHandler, class GoogleLoginHandler(tornado.web.RequestHandler,
tornado.auth.GoogleMixin): tornado.auth.GoogleMixin):
@tornado.web.asynchronous
@tornado.gen.coroutine @tornado.gen.coroutine
def get(self): def get(self):
if self.get_argument("openid.mode", None): if self.get_argument("openid.mode", None):
@ -949,7 +943,10 @@ class GoogleMixin(OpenIdMixin, OAuthMixin):
class GoogleOAuth2Mixin(OAuth2Mixin): class GoogleOAuth2Mixin(OAuth2Mixin):
"""Google authentication using OAuth2.""" """Google authentication using OAuth2.
.. versionadded:: 3.2
"""
_OAUTH_AUTHORIZE_URL = "https://accounts.google.com/o/oauth2/auth" _OAUTH_AUTHORIZE_URL = "https://accounts.google.com/o/oauth2/auth"
_OAUTH_ACCESS_TOKEN_URL = "https://accounts.google.com/o/oauth2/token" _OAUTH_ACCESS_TOKEN_URL = "https://accounts.google.com/o/oauth2/token"
_OAUTH_NO_CALLBACKS = False _OAUTH_NO_CALLBACKS = False
@ -961,22 +958,22 @@ class GoogleOAuth2Mixin(OAuth2Mixin):
Example usage:: Example usage::
class GoogleOAuth2LoginHandler(LoginHandler, tornado.auth.GoogleOAuth2Mixin): class GoogleOAuth2LoginHandler(LoginHandler,
@tornado.web.asynchronous tornado.auth.GoogleOAuth2Mixin):
@tornado.gen.coroutine @tornado.gen.coroutine
def get(self): def get(self):
if self.get_argument("code", False): if self.get_argument('code', False):
user = yield self.get_authenticated_user( user = yield self.get_authenticated_user(
redirect_uri='http://your.site.com/auth/google', redirect_uri='http://your.site.com/auth/google',
code=self.get_argument("code")) code=self.get_argument('code'))
# Save the user with e.g. set_secure_cookie # Save the user with e.g. set_secure_cookie
else: else:
yield self.authorize_redirect( yield self.authorize_redirect(
redirect_uri='http://your.site.com/auth/google', redirect_uri='http://your.site.com/auth/google',
client_id=self.settings["google_consumer_key"], client_id=self.settings['google_oauth']['key'],
scope=['openid', 'email'], scope=['profile', 'email'],
response_type='code', response_type='code',
extra_params={"approval_prompt": "auto"}) extra_params={'approval_prompt': 'auto'})
""" """
http = self.get_auth_http_client() http = self.get_auth_http_client()
body = urllib_parse.urlencode({ body = urllib_parse.urlencode({
@ -1234,7 +1231,6 @@ class FacebookGraphMixin(OAuth2Mixin):
Example usage:: Example usage::
class FacebookGraphLoginHandler(LoginHandler, tornado.auth.FacebookGraphMixin): class FacebookGraphLoginHandler(LoginHandler, tornado.auth.FacebookGraphMixin):
@tornado.web.asynchronous
@tornado.gen.coroutine @tornado.gen.coroutine
def get(self): def get(self):
if self.get_argument("code", False): if self.get_argument("code", False):
@ -1321,7 +1317,6 @@ class FacebookGraphMixin(OAuth2Mixin):
class MainHandler(tornado.web.RequestHandler, class MainHandler(tornado.web.RequestHandler,
tornado.auth.FacebookGraphMixin): tornado.auth.FacebookGraphMixin):
@tornado.web.authenticated @tornado.web.authenticated
@tornado.web.asynchronous
@tornado.gen.coroutine @tornado.gen.coroutine
def get(self): def get(self):
new_entry = yield self.facebook_request( new_entry = yield self.facebook_request(

11
libs/tornado/escape.py

@ -55,7 +55,16 @@ _XHTML_ESCAPE_DICT = {'&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;',
def xhtml_escape(value): def xhtml_escape(value):
"""Escapes a string so it is valid within HTML or XML.""" """Escapes a string so it is valid within HTML or XML.
Escapes the characters ``<``, ``>``, ``"``, ``'``, and ``&``.
When used in attribute values the escaped strings must be enclosed
in quotes.
.. versionchanged:: 3.2
Added the single quote to the list of escaped characters.
"""
return _XHTML_ESCAPE_RE.sub(lambda match: _XHTML_ESCAPE_DICT[match.group(0)], return _XHTML_ESCAPE_RE.sub(lambda match: _XHTML_ESCAPE_DICT[match.group(0)],
to_basestring(value)) to_basestring(value))

1
libs/tornado/gen.py

@ -59,7 +59,6 @@ For more complicated interfaces, `Task` can be split into two parts:
`Callback` and `Wait`:: `Callback` and `Wait`::
class GenAsyncHandler2(RequestHandler): class GenAsyncHandler2(RequestHandler):
@asynchronous
@gen.coroutine @gen.coroutine
def get(self): def get(self):
http_client = AsyncHTTPClient() http_client = AsyncHTTPClient()

26
libs/tornado/ioloop.py

@ -301,6 +301,22 @@ class IOLoop(Configurable):
""" """
raise NotImplementedError() raise NotImplementedError()
def _setup_logging(self):
"""The IOLoop catches and logs exceptions, so it's
important that log output be visible. However, python's
default behavior for non-root loggers (prior to python
3.2) is to print an unhelpful "no handlers could be
found" message rather than the actual log entry, so we
must explicitly configure logging if we've made it this
far without anything.
This method should be called from start() in subclasses.
"""
if not any([logging.getLogger().handlers,
logging.getLogger('tornado').handlers,
logging.getLogger('tornado.application').handlers]):
logging.basicConfig()
def stop(self): def stop(self):
"""Stop the I/O loop. """Stop the I/O loop.
@ -550,15 +566,7 @@ class PollIOLoop(IOLoop):
action if action is not None else signal.SIG_DFL) action if action is not None else signal.SIG_DFL)
def start(self): def start(self):
if not logging.getLogger().handlers: self._setup_logging()
# The IOLoop catches and logs exceptions, so it's
# important that log output be visible. However, python's
# default behavior for non-root loggers (prior to python
# 3.2) is to print an unhelpful "no handlers could be
# found" message rather than the actual log entry, so we
# must explicitly configure logging if we've made it this
# far without anything.
logging.basicConfig()
if self._stopped: if self._stopped:
self._stopped = False self._stopped = False
return return

91
libs/tornado/log.py

@ -60,6 +60,13 @@ def _stderr_supports_color():
return color return color
def _safe_unicode(s):
try:
return _unicode(s)
except UnicodeDecodeError:
return repr(s)
class LogFormatter(logging.Formatter): class LogFormatter(logging.Formatter):
"""Log formatter used in Tornado. """Log formatter used in Tornado.
@ -73,23 +80,37 @@ class LogFormatter(logging.Formatter):
`tornado.options.parse_command_line` (unless ``--logging=none`` is `tornado.options.parse_command_line` (unless ``--logging=none`` is
used). used).
""" """
DEFAULT_PREFIX_FORMAT = '[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]' DEFAULT_FORMAT = '%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]%(end_color)s %(message)s'
DEFAULT_DATE_FORMAT = '%y%m%d %H:%M:%S' DEFAULT_DATE_FORMAT = '%y%m%d %H:%M:%S'
DEFAULT_COLORS = {
logging.DEBUG: 4, # Blue
logging.INFO: 2, # Green
logging.WARNING: 3, # Yellow
logging.ERROR: 1, # Red
}
def __init__(self, color=True, prefix_fmt=None, datefmt=None): def __init__(self, color=True, fmt=DEFAULT_FORMAT,
datefmt=DEFAULT_DATE_FORMAT, colors=DEFAULT_COLORS):
r""" r"""
:arg bool color: Enables color support :arg bool color: Enables color support.
:arg string prefix_fmt: Log message prefix format. :arg string fmt: Log message format.
Prefix is a part of the log message, directly preceding the actual It will be applied to the attributes dict of log records. The
message text. text between ``%(color)s`` and ``%(end_color)s`` will be colored
depending on the level if color support is on.
:arg dict colors: color mappings from logging level to terminal color
code
:arg string datefmt: Datetime format. :arg string datefmt: Datetime format.
Used for formatting ``(asctime)`` placeholder in ``prefix_fmt``. Used for formatting ``(asctime)`` placeholder in ``prefix_fmt``.
.. versionchanged:: 3.2
Added ``fmt`` and ``datefmt`` arguments.
""" """
self.__prefix_fmt = prefix_fmt if prefix_fmt is not None else self.DEFAULT_PREFIX_FORMAT
datefmt = datefmt if datefmt is not None else self.DEFAULT_DATE_FORMAT
logging.Formatter.__init__(self, datefmt=datefmt) logging.Formatter.__init__(self, datefmt=datefmt)
self._color = color and _stderr_supports_color() self._fmt = fmt
if self._color:
self._colors = {}
if color and _stderr_supports_color():
# The curses module has some str/bytes confusion in # The curses module has some str/bytes confusion in
# python3. Until version 3.2.3, most methods return # python3. Until version 3.2.3, most methods return
# bytes, but only accept strings. In addition, we want to # bytes, but only accept strings. In addition, we want to
@ -101,30 +122,17 @@ class LogFormatter(logging.Formatter):
curses.tigetstr("setf") or "") curses.tigetstr("setf") or "")
if (3, 0) < sys.version_info < (3, 2, 3): if (3, 0) < sys.version_info < (3, 2, 3):
fg_color = unicode_type(fg_color, "ascii") fg_color = unicode_type(fg_color, "ascii")
self._colors = {
logging.DEBUG: unicode_type(curses.tparm(fg_color, 4), # Blue for levelno, code in colors.items():
"ascii"), self._colors[levelno] = unicode_type(curses.tparm(fg_color, code), "ascii")
logging.INFO: unicode_type(curses.tparm(fg_color, 2), # Green
"ascii"),
logging.WARNING: unicode_type(curses.tparm(fg_color, 3), # Yellow
"ascii"),
logging.ERROR: unicode_type(curses.tparm(fg_color, 1), # Red
"ascii"),
}
self._normal = unicode_type(curses.tigetstr("sgr0"), "ascii") self._normal = unicode_type(curses.tigetstr("sgr0"), "ascii")
else:
self._normal = ''
def format(self, record): def format(self, record):
try: try:
record.message = record.getMessage() message = record.getMessage()
except Exception as e: assert isinstance(message, basestring_type) # guaranteed by logging
record.message = "Bad message (%r): %r" % (e, record.__dict__)
assert isinstance(record.message, basestring_type) # guaranteed by logging
record.asctime = self.formatTime(record, self.datefmt)
prefix = self.__prefix_fmt % record.__dict__
if self._color:
prefix = (self._colors.get(record.levelno, self._normal) +
prefix + self._normal)
# Encoding notes: The logging module prefers to work with character # Encoding notes: The logging module prefers to work with character
# strings, but only enforces that log messages are instances of # strings, but only enforces that log messages are instances of
# basestring. In python 2, non-ascii bytestrings will make # basestring. In python 2, non-ascii bytestrings will make
@ -141,22 +149,29 @@ class LogFormatter(logging.Formatter):
# it's worth it since the encoding errors that would otherwise # it's worth it since the encoding errors that would otherwise
# result are so useless (and tornado is fond of using utf8-encoded # result are so useless (and tornado is fond of using utf8-encoded
# byte strings whereever possible). # byte strings whereever possible).
def safe_unicode(s): record.message = _safe_unicode(message)
try: except Exception as e:
return _unicode(s) record.message = "Bad message (%r): %r" % (e, record.__dict__)
except UnicodeDecodeError:
return repr(s) record.asctime = self.formatTime(record, self.datefmt)
if record.levelno in self._colors:
record.color = self._colors[record.levelno]
record.end_color = self._normal
else:
record.color = record.end_color = ''
formatted = self._fmt % record.__dict__
formatted = prefix + " " + safe_unicode(record.message)
if record.exc_info: if record.exc_info:
if not record.exc_text: if not record.exc_text:
record.exc_text = self.formatException(record.exc_info) record.exc_text = self.formatException(record.exc_info)
if record.exc_text: if record.exc_text:
# exc_text contains multiple lines. We need to safe_unicode # exc_text contains multiple lines. We need to _safe_unicode
# each line separately so that non-utf8 bytes don't cause # each line separately so that non-utf8 bytes don't cause
# all the newlines to turn into '\n'. # all the newlines to turn into '\n'.
lines = [formatted.rstrip()] lines = [formatted.rstrip()]
lines.extend(safe_unicode(ln) for ln in record.exc_text.split('\n')) lines.extend(_safe_unicode(ln) for ln in record.exc_text.split('\n'))
formatted = '\n'.join(lines) formatted = '\n'.join(lines)
return formatted.replace("\n", "\n ") return formatted.replace("\n", "\n ")

6
libs/tornado/platform/asyncio.py

@ -8,6 +8,8 @@ python3.4 -m tornado.test.runtests --ioloop=tornado.platform.asyncio.AsyncIOMain
(the tests log a few warnings with AsyncIOMainLoop because they leave some (the tests log a few warnings with AsyncIOMainLoop because they leave some
unfinished callbacks on the event loop that fail when it resumes) unfinished callbacks on the event loop that fail when it resumes)
""" """
from __future__ import absolute_import, division, print_function, with_statement
import asyncio import asyncio
import datetime import datetime
import functools import functools
@ -34,7 +36,10 @@ class BaseAsyncIOLoop(IOLoop):
for fd in list(self.handlers): for fd in list(self.handlers):
self.remove_handler(fd) self.remove_handler(fd)
if all_fds: if all_fds:
try:
os.close(fd) os.close(fd)
except OSError:
pass
if self.close_loop: if self.close_loop:
self.asyncio_loop.close() self.asyncio_loop.close()
@ -86,6 +91,7 @@ class BaseAsyncIOLoop(IOLoop):
self.handlers[fd](fd, events) self.handlers[fd](fd, events)
def start(self): def start(self):
self._setup_logging()
self.asyncio_loop.run_forever() self.asyncio_loop.run_forever()
def stop(self): def stop(self):

1
libs/tornado/platform/caresresolver.py

@ -1,3 +1,4 @@
from __future__ import absolute_import, division, print_function, with_statement
import pycares import pycares
import socket import socket

1
libs/tornado/platform/twisted.py

@ -456,6 +456,7 @@ class TwistedIOLoop(tornado.ioloop.IOLoop):
del self.fds[fd] del self.fds[fd]
def start(self): def start(self):
self._setup_logging()
self.reactor.run() self.reactor.run()
def stop(self): def stop(self):

9
libs/tornado/web.py

@ -516,6 +516,10 @@ class RequestHandler(object):
See `clear_cookie` for more information on the path and domain See `clear_cookie` for more information on the path and domain
parameters. parameters.
.. versionchanged:: 3.2
Added the ``path`` and ``domain`` parameters.
""" """
for name in self.request.cookies: for name in self.request.cookies:
self.clear_cookie(name, path=path, domain=domain) self.clear_cookie(name, path=path, domain=domain)
@ -1850,6 +1854,11 @@ class StaticFileHandler(RequestHandler):
class method. Instance methods may use the attributes ``self.path`` class method. Instance methods may use the attributes ``self.path``
``self.absolute_path``, and ``self.modified``. ``self.absolute_path``, and ``self.modified``.
Subclasses should only override methods discussed in this section;
overriding other methods is error-prone. Overriding
``StaticFileHandler.get`` is particularly problematic due to the
tight coupling with ``compute_etag`` and other methods.
To change the way static urls are generated (e.g. to match the behavior To change the way static urls are generated (e.g. to match the behavior
of another server or CDN), override `make_static_url`, `parse_url_path`, of another server or CDN), override `make_static_url`, `parse_url_path`,
`get_cache_time`, and/or `get_version`. `get_cache_time`, and/or `get_version`.

Loading…
Cancel
Save