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. 121
      libs/tornado/log.py
  7. 8
      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

121
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 = {
def __init__(self, color=True, prefix_fmt=None, datefmt=None): logging.DEBUG: 4, # Blue
logging.INFO: 2, # Green
logging.WARNING: 3, # Yellow
logging.ERROR: 1, # Red
}
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,62 +122,56 @@ 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()
assert isinstance(message, basestring_type) # guaranteed by logging
# Encoding notes: The logging module prefers to work with character
# strings, but only enforces that log messages are instances of
# basestring. In python 2, non-ascii bytestrings will make
# their way through the logging framework until they blow up with
# an unhelpful decoding error (with this formatter it happens
# when we attach the prefix, but there are other opportunities for
# exceptions further along in the framework).
#
# If a byte string makes it this far, convert it to unicode to
# ensure it will make it out to the logs. Use repr() as a fallback
# to ensure that all byte strings can be converted successfully,
# but don't do it by default so we don't add extra quotes to ascii
# bytestrings. This is a bit of a hacky place to do this, but
# it's worth it since the encoding errors that would otherwise
# result are so useless (and tornado is fond of using utf8-encoded
# byte strings whereever possible).
record.message = _safe_unicode(message)
except Exception as e: except Exception as e:
record.message = "Bad message (%r): %r" % (e, record.__dict__) 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) record.asctime = self.formatTime(record, self.datefmt)
prefix = self.__prefix_fmt % record.__dict__
if self._color: if record.levelno in self._colors:
prefix = (self._colors.get(record.levelno, self._normal) + record.color = self._colors[record.levelno]
prefix + self._normal) record.end_color = self._normal
else:
# Encoding notes: The logging module prefers to work with character record.color = record.end_color = ''
# strings, but only enforces that log messages are instances of
# basestring. In python 2, non-ascii bytestrings will make formatted = self._fmt % record.__dict__
# their way through the logging framework until they blow up with
# an unhelpful decoding error (with this formatter it happens
# when we attach the prefix, but there are other opportunities for
# exceptions further along in the framework).
#
# If a byte string makes it this far, convert it to unicode to
# ensure it will make it out to the logs. Use repr() as a fallback
# to ensure that all byte strings can be converted successfully,
# but don't do it by default so we don't add extra quotes to ascii
# bytestrings. This is a bit of a hacky place to do this, but
# it's worth it since the encoding errors that would otherwise
# result are so useless (and tornado is fond of using utf8-encoded
# byte strings whereever possible).
def safe_unicode(s):
try:
return _unicode(s)
except UnicodeDecodeError:
return repr(s)
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 ")

8
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:
os.close(fd) try:
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