Skip to content
This repository has been archived by the owner on May 21, 2020. It is now read-only.

Commit

Permalink
Merge branch 'master' of git://github.com/facebook/tornado into strea…
Browse files Browse the repository at this point in the history
…mbody
  • Loading branch information
jcbsv committed Jan 24, 2012
2 parents 08871d4 + 067e465 commit 68eb7f5
Show file tree
Hide file tree
Showing 37 changed files with 1,146 additions and 298 deletions.
18 changes: 18 additions & 0 deletions .coveragerc
@@ -0,0 +1,18 @@
# Test coverage configuration.
# Usage:
# pip install coverage
# coverage erase # clears previous data if any
# coverage run -m tornado.test.runtests
# coverage report # prints to stdout
# coverage html # creates ./htmlcov/*.html including annotated source
[run]
branch = true
source = tornado
omit =
tornado/platform/*
tornado/test/*
*/_auto2to3*

[report]
# Ignore missing source files, i.e. fake template-generated "files"
ignore_errors = true
11 changes: 7 additions & 4 deletions .gitignore
@@ -1,10 +1,13 @@
*.pyc
*.so
*~
build
dist/
build/
/dist/
MANIFEST
tornado.egg-info
/tornado.egg-info/
_auto2to3*
.tox
.tox/
.vagrant
/.coverage
/htmlcov/
/env/
4 changes: 4 additions & 0 deletions demos/websocket/chatdemo.py
Expand Up @@ -57,6 +57,10 @@ class ChatSocketHandler(tornado.websocket.WebSocketHandler):
cache = []
cache_size = 200

def allow_draft76(self):
# for iOS 5.0 Safari
return True

def open(self):
ChatSocketHandler.waiters.add(self)

Expand Down
5 changes: 3 additions & 2 deletions demos/websocket/static/chat.js
Expand Up @@ -50,10 +50,11 @@ var updater = {
socket: null,

start: function() {
var url = "ws://" + location.host + "/chatsocket";
if ("WebSocket" in window) {
updater.socket = new WebSocket("ws://localhost:8888/chatsocket");
updater.socket = new WebSocket(url);
} else {
updater.socket = new MozWebSocket("ws://localhost:8888/chatsocket");
updater.socket = new MozWebSocket(url);
}
updater.socket.onmessage = function(event) {
updater.showMessage(JSON.parse(event.data));
Expand Down
21 changes: 21 additions & 0 deletions maint/requirements.txt
@@ -0,0 +1,21 @@
# Frozen pip requirements for tools used in the development of tornado

# Tornado's optional dependencies
MySQL-python==1.2.3
Twisted==11.1.0
pycurl==7.19.0

# Other useful tools
Sphinx==1.1.2
coverage==3.5.1
pyflakes==0.5.0
tox==1.3
virtualenv==1.7

# Indirect dependencies
Jinja2==2.6
Pygments==1.4
docutils==0.8.1
py==1.4.6
wsgiref==0.1.2
zope.interface==3.8.0
2 changes: 1 addition & 1 deletion maint/test/websocket/client.py
Expand Up @@ -11,7 +11,7 @@
define('cases', type=str, multiple=True,
default=["*"])
define('exclude', type=str, multiple=True,
default=[])
default=["9.*"])

if __name__ == '__main__':
parse_command_line()
Expand Down
10 changes: 7 additions & 3 deletions maint/test/websocket/run.sh
Expand Up @@ -4,8 +4,8 @@
# python2 and python3. Output goes in ./reports/servers/index.html.
#
# The --cases and --exclude arguments can be used to run only part of
# the suite. --exclude="9.*" is useful to skip the relatively slow
# performance tests.
# the suite. The default is --exclude="9.*" to skip the relatively slow
# performance tests; pass --exclude="" to override and include them.

set -e

Expand All @@ -21,13 +21,17 @@ PY27_SERVER_PID=$!
.tox/py32/bin/python server.py --port=9003 &
PY32_SERVER_PID=$!

.tox/pypy/bin/python server.py --port=9004 &
PYPY_SERVER_PID=$!

sleep 1

.tox/py27/bin/python ./client.py --servers=Tornado/py25=ws://localhost:9001,Tornado/py27=ws://localhost:9002,Tornado/py32=ws://localhost:9003 "$@"
.tox/py27/bin/python ./client.py --servers=Tornado/py25=ws://localhost:9001,Tornado/py27=ws://localhost:9002,Tornado/py32=ws://localhost:9003,Tornado/pypy=ws://localhost:9004 "$@" || true

kill $PY25_SERVER_PID
kill $PY27_SERVER_PID
kill $PY32_SERVER_PID
kill $PYPY_SERVER_PID
wait

echo "Tests complete. Output is in ./reports/servers/index.html"
5 changes: 3 additions & 2 deletions maint/test/websocket/server.py
Expand Up @@ -2,19 +2,20 @@

from tornado.ioloop import IOLoop
from tornado.options import define, options, parse_command_line
from tornado.util import bytes_type
from tornado.websocket import WebSocketHandler
from tornado.web import Application

define('port', default=9000)

class EchoHandler(WebSocketHandler):
def on_message(self, message):
self.write_message(message)
self.write_message(message, binary=isinstance(message, bytes_type))

if __name__ == '__main__':
parse_command_line()
app = Application([
('/', EchoHandler),
])
app.listen(options.port, address='localhost')
app.listen(options.port, address='127.0.0.1')
IOLoop.instance().start()
2 changes: 1 addition & 1 deletion maint/test/websocket/tox.ini
Expand Up @@ -2,7 +2,7 @@
# to install autobahn and deal with 2to3 for the python3 version.
# See run.sh for the real test runner.
[tox]
envlist = py27, py32, py25
envlist = py27, py32, py25, pypy
setupdir=../../..

[testenv]
Expand Down
8 changes: 8 additions & 0 deletions maint/vm/ubuntu11.04/Vagrantfile
@@ -0,0 +1,8 @@
Vagrant::Config.run do |config|
config.vm.box = "ubuntu11.04"

config.vm.network "172.19.1.4"
config.vm.share_folder("tornado", "/tornado", "../../..", :nfs=> true)

config.vm.provision :shell, :path => "setup.sh"
end
56 changes: 56 additions & 0 deletions maint/vm/ubuntu11.04/setup.sh
@@ -0,0 +1,56 @@
#!/bin/sh

set -e

# Ubuntu 10.10+ do some extra permissions checks for hard links.
# Vagrant's nfs shared folders come through with funny uids, but
# attempts to access them still work despite the visible permissions
# being incorrect.
sysctl -w kernel.yama.protected_nonaccess_hardlinks=0

apt-get update

# libcurl4-gnutls-dev is the default if you ask for libcurl4-dev, but it
# has bugs that make our tests deadlock (the relevant tests detect this and
# disable themselves, but it means that to get full coverage we have to use
# the openssl version).
# The oddly-named python-software-properties includes add-apt-repository.
APT_PACKAGES="
python-pip
python-dev
libmysqlclient-dev
libcurl4-openssl-dev
python-software-properties
"

apt-get -y install $APT_PACKAGES


# Ubuntu 11.04 has python 2.7 as default; install more from here.
# The most important thing is to have both 2.5 and a later version so we
# test with both tornado.epoll and 2.6+ stdlib's select.epoll.
add-apt-repository ppa:fkrull/deadsnakes
apt-get update

DEADSNAKES_PACKAGES="
python2.5
python2.5-dev
python2.6
python2.6-dev
python3.2
python3.2-dev
"
apt-get -y install $DEADSNAKES_PACKAGES


PIP_PACKAGES="
virtualenv
tox
MySQL-python
pycurl
twisted
"

pip install $PIP_PACKAGES

/tornado/maint/vm/shared-setup.sh
32 changes: 32 additions & 0 deletions maint/vm/ubuntu11.04/tox.ini
@@ -0,0 +1,32 @@
[tox]
envlist = py27-full, py25-full, py32, py25, py26, py26-full, py27
setupdir=/tornado
toxworkdir=/home/vagrant/tox-tornado

[testenv]
commands = python -m tornado.test.runtests {posargs:}

[testenv:py25]
basepython = python2.5
deps = simplejson

[testenv:py25-full]
basepython = python2.5
deps =
MySQL-python
pycurl
simplejson
twisted==11.0.0

[testenv:py26-full]
deps =
MySQL-python
pycurl
twisted==11.0.0

[testenv:py27-full]
basepython = python2.7
deps =
MySQL-python
pycurl
twisted==11.0.0
9 changes: 8 additions & 1 deletion tornado/__init__.py
Expand Up @@ -16,5 +16,12 @@

"""The Tornado web server and tools."""

# version is a human-readable version number.

# version_info is a four-tuple for programmatic comparison. The first
# three numbers are the components of the version number. The fourth
# is zero for an official release, positive for a development branch,
# or negative for a release candidate (after the base version number
# has been incremented)
version = "2.1.1git"
version_info = (2, 1, 1)
version_info = (2, 1, 1, 1)
11 changes: 8 additions & 3 deletions tornado/auth.py
Expand Up @@ -451,14 +451,14 @@ def _on_auth(self, user):
_OAUTH_NO_CALLBACKS = False


def authenticate_redirect(self):
def authenticate_redirect(self, callback_uri = None):
"""Just like authorize_redirect(), but auto-redirects if authorized.
This is generally the right interface to use if you are using
Twitter for single-sign on.
"""
http = httpclient.AsyncHTTPClient()
http.fetch(self._oauth_request_token_url(), self.async_callback(
http.fetch(self._oauth_request_token_url(callback_uri = callback_uri), self.async_callback(
self._on_request_token, self._OAUTH_AUTHENTICATE_URL, None))

def twitter_request(self, path, callback, access_token=None,
Expand Down Expand Up @@ -499,8 +499,13 @@ def _on_post(self, new_entry):
self.finish("Posted a message!")
"""
if path.startswith('http:') or path.startswith('https:'):
# Raw urls are useful for e.g. search which doesn't follow the
# usual pattern: http://search.twitter.com/search.json
url = path
else:
url = "http://api.twitter.com/1" + path + ".json"
# Add the OAuth resource request signature if we have credentials
url = "http://api.twitter.com/1" + path + ".json"
if access_token:
all_args = {}
all_args.update(args)
Expand Down
12 changes: 6 additions & 6 deletions tornado/curl_httpclient.py
Expand Up @@ -271,7 +271,7 @@ def _curl_create(max_simultaneous_connections=None):


def _curl_setup_request(curl, request, buffer, headers):
curl.setopt(pycurl.URL, request.url)
curl.setopt(pycurl.URL, utf8(request.url))

# libcurl's magic "Expect: 100-continue" behavior causes delays
# with servers that don't support it (which include, among others,
Expand Down Expand Up @@ -307,8 +307,8 @@ def _curl_setup_request(curl, request, buffer, headers):
curl.setopt(pycurl.WRITEFUNCTION, buffer.write)
curl.setopt(pycurl.FOLLOWLOCATION, request.follow_redirects)
curl.setopt(pycurl.MAXREDIRS, request.max_redirects)
curl.setopt(pycurl.CONNECTTIMEOUT, int(request.connect_timeout))
curl.setopt(pycurl.TIMEOUT, int(request.request_timeout))
curl.setopt(pycurl.CONNECTTIMEOUT_MS, int(1000 * request.connect_timeout))
curl.setopt(pycurl.TIMEOUT_MS, int(1000 * request.request_timeout))
if request.user_agent:
curl.setopt(pycurl.USERAGENT, utf8(request.user_agent))
else:
Expand Down Expand Up @@ -383,10 +383,10 @@ def ioctl(cmd):
else:
curl.setopt(pycurl.INFILESIZE, len(request.body))

if request.auth_username and request.auth_password:
userpwd = "%s:%s" % (request.auth_username, request.auth_password)
if request.auth_username is not None:
userpwd = "%s:%s" % (request.auth_username, request.auth_password or '')
curl.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_BASIC)
curl.setopt(pycurl.USERPWD, userpwd)
curl.setopt(pycurl.USERPWD, utf8(userpwd))
logging.debug("%s %s (username: %r)", request.method, request.url,
request.auth_username)
else:
Expand Down
10 changes: 6 additions & 4 deletions tornado/gen.py
Expand Up @@ -82,10 +82,12 @@ def engine(func):
Any generator that yields objects from this module must be wrapped
in this decorator. The decorator only works on functions that are
already asynchronous. For `~tornado.web.RequestHandler`
``get``/``post``/etc methods, this means that both the `tornado.gen.engine`
and `tornado.web.asynchronous` decorators must be used (in either order).
In most other cases, it means that it doesn't make sense to use
``gen.engine`` on functions that don't already take a callback argument.
``get``/``post``/etc methods, this means that both the
`tornado.web.asynchronous` and `tornado.gen.engine` decorators
must be used (for proper exception handling, ``asynchronous``
should come before ``gen.engine``). In most other cases, it means
that it doesn't make sense to use ``gen.engine`` on functions that
don't already take a callback argument.
"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
Expand Down
10 changes: 7 additions & 3 deletions tornado/httpclient.py
Expand Up @@ -54,9 +54,11 @@ class HTTPClient(object):
except httpclient.HTTPError, e:
print "Error:", e
"""
def __init__(self):
def __init__(self, async_client_class=None):
self._io_loop = IOLoop()
self._async_client = AsyncHTTPClient(self._io_loop)
if async_client_class is None:
async_client_class = AsyncHTTPClient
self._async_client = async_client_class(self._io_loop)
self._response = None
self._closed = False

Expand Down Expand Up @@ -391,12 +393,14 @@ def main():
define("print_headers", type=bool, default=False)
define("print_body", type=bool, default=True)
define("follow_redirects", type=bool, default=True)
define("validate_cert", type=bool, default=True)
args = parse_command_line()
client = HTTPClient()
for arg in args:
try:
response = client.fetch(arg,
follow_redirects=options.follow_redirects
follow_redirects=options.follow_redirects,
validate_cert=options.validate_cert,
)
except HTTPError, e:
if e.response is not None:
Expand Down

0 comments on commit 68eb7f5

Please sign in to comment.