From 7750fe7773366d19937038d2a2fd12b66445f674 Mon Sep 17 00:00:00 2001 From: Ben Darnell Date: Mon, 15 Nov 2010 16:11:09 -0800 Subject: [PATCH] Port pseudo-singleton magic from AsyncHTTPClient to SimpleAsyncHTTPClient --- tornado/simple_httpclient.py | 28 +++++++++++++++++++++++--- tornado/test/simple_httpclient_test.py | 10 +++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/tornado/simple_httpclient.py b/tornado/simple_httpclient.py index 86a6c0dd..07d655af 100644 --- a/tornado/simple_httpclient.py +++ b/tornado/simple_httpclient.py @@ -16,6 +16,7 @@ import re import socket import time import urlparse +import weakref import zlib try: @@ -43,9 +44,30 @@ class SimpleAsyncHTTPClient(object): Python 2.6 or higher is required for HTTPS support. Users of Python 2.5 should use the curl-based AsyncHTTPClient if HTTPS support is required. """ - # TODO: singleton magic? - def __init__(self, io_loop=None): - self.io_loop = io_loop or IOLoop.instance() + _ASYNC_CLIENTS = weakref.WeakKeyDictionary() + + def __new__(cls, io_loop=None, max_clients=10, + max_simultaneous_connections=None): + """Creates a SimpleAsyncHTTPClient. + + Only a single SimpleAsyncHTTPClient instance exists per IOLoop + in order to provide limitations on the number of pending connections. + + max_clients is the number of concurrent requests that can be in + progress. max_simultaneous_connections has no effect and is accepted + only for compatibility with the curl-based AsyncHTTPClient. Note + that these arguments are only used when the client is first created, + and will be ignored when an existing client is reused. + """ + io_loop = io_loop or IOLoop.instance() + if io_loop in cls._ASYNC_CLIENTS: + return cls._ASYNC_CLIENTS[io_loop] + else: + instance = super(SimpleAsyncHTTPClient, cls).__new__(cls) + instance.io_loop = io_loop + instance.max_clients = max_clients + cls._ASYNC_CLIENTS[io_loop] = instance + return instance def close(self): pass diff --git a/tornado/test/simple_httpclient_test.py b/tornado/test/simple_httpclient_test.py index c99e547a..24b67b02 100644 --- a/tornado/test/simple_httpclient_test.py +++ b/tornado/test/simple_httpclient_test.py @@ -5,6 +5,7 @@ import logging import socket from contextlib import closing +from tornado.ioloop import IOLoop from tornado.simple_httpclient import SimpleAsyncHTTPClient from tornado.testing import AsyncHTTPTestCase, LogTrapTestCase, get_unused_port from tornado.web import Application, RequestHandler, asynchronous @@ -122,3 +123,12 @@ class SimpleHTTPClientTestCase(AsyncHTTPTestCase, LogTrapTestCase): response = self.fetch('/hang', request_timeout=0.1) self.assertEqual(response.code, 599) self.assertEqual(str(response.error), "HTTP 599: Timeout") + + def test_singleton(self): + # Class "constructor" reuses objects on the same IOLoop + self.assertTrue(SimpleAsyncHTTPClient(self.io_loop) is + SimpleAsyncHTTPClient(self.io_loop)) + # different IOLoops use different objects + io_loop2 = IOLoop() + self.assertTrue(SimpleAsyncHTTPClient(self.io_loop) is not + SimpleAsyncHTTPClient(io_loop2))