initial import of urllib3 branch async
authorKenneth Reitz <me@kennethreitz.com>
Fri, 14 Oct 2011 00:11:05 +0000 (20:11 -0400)
committerKenneth Reitz <me@kennethreitz.com>
Fri, 14 Oct 2011 00:11:05 +0000 (20:11 -0400)
requests/async.py

index ab04084..9517064 100644 (file)
@@ -1,41 +1,87 @@
 # -*- coding: utf-8 -*-
 
 """
-    requests.async
-    ~~~~~~~~~~~~~~
+requests.async
+~~~~~~~~~~~~~~
 
-    This module implements the main Requests system, after monkey-patching
-    the urllib2 module with eventlet or gevent..
-
-    :copyright: (c) 2011 by Kenneth Reitz.
-    :license: ISC, see LICENSE for more details.
+This module contains an asynchronous replica of ``requests.api``, powered
+by gevent. All API methods return a ``Request`` instance (as opposed to
+``Response``). A list of requests can be sent with ``map()``.
 """
 
+try:
+    import gevent
+    from gevent import monkey as curious_george
+except ImportError:
+    raise RuntimeError('Gevent is required for requests.async.')
+
+# Monkey-patch.
+curious_george.patch_all(thread=False)
 
-from __future__ import absolute_import
+from . import api
+from .hooks import dispatch_hook
+from .packages.urllib3.poolmanager import PoolManager
 
-import urllib
-import urllib2
 
-from urllib2 import HTTPError
+__all__ = (
+    'map',
+    'get', 'head', 'post', 'put', 'patch', 'delete', 'request'
+)
 
 
-try:
-    import eventlet
-    eventlet.monkey_patch()
-except ImportError:
-    pass
+def _patched(f):
+    """Patches a given API function to not send."""
+
+    def wrapped(*args, **kwargs):
+        return f(*args, _return_request=True, **kwargs)
+
+    return wrapped
+
+
+def _send(r, pools=None):
+    """Sends a given Request object."""
+
+    if pools:
+        r._pools = pools
+
+    r.send()
+
+    # Post-request hook.
+    r = dispatch_hook('post_request', r.hooks, r)
+
+    # Response manipulation hook.
+    r.response = dispatch_hook('response', r.hooks, r.response)
+
+    return r.response
+
+
+# Patched requests.api functions.
+get = _patched(api.get)
+head = _patched(api.head)
+post = _patched(api.post)
+put = _patched(api.put)
+patch = _patched(api.patch)
+delete = _patched(api.delete)
+request = _patched(api.request)
+
+
+def map(requests, keep_alive=False):
+    """Concurrently converts a list of Requests to Responses.
+
+    :param requests: a collection of Request objects.
+    :param keep_alive: If True, HTTP Keep-Alive will be used.
+    """
+
+    if keep_alive:
+        pools = PoolManager(num_pools=len(requests), maxsize=1)
+    else:
+        pools = None
+
+    jobs = [gevent.spawn(_send, r, pools=pools) for r in requests]
+    gevent.joinall(jobs)
 
-if not 'eventlet' in locals():
-    try:
-        from gevent import monkey
-        monkey.patch_all()
-    except ImportError:
-        pass
+    return [r.response for r in requests]
 
 
-if not 'eventlet' in locals():
-    raise ImportError('No Async adaptations of urllib2 found!')
 
 
-from .core import *