From d29e518449c50ee482e98dd98694154bb7d185b2 Mon Sep 17 00:00:00 2001 From: "Christopher H. Casebeer" Date: Thu, 21 Jun 2012 19:05:52 -0400 Subject: [PATCH] v0.1.2, Add async support based on asynchttp - Attempt to use the asynchttp module in place of httplib2. - Add async kwarg to Request and Session run() methods. - Remove unneeded imports from version specific session modules. - Update docs with changelog. - Bump to version 0.1.2 --- README.md | 7 +++++++ factual/common/requests.py | 19 +++++++++++++++++-- factual/common/session.py | 36 +++++++++++++++++++++++++++++------- factual/v2/session.py | 5 ----- factual/v3/session.py | 5 ----- setup.py | 2 +- 6 files changed, 54 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index e378460..ef64933 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,13 @@ See also the Python documentation for session.Session and requests.Read and [Fac - Write support for v3, when available - Multiple search filters (search filters currently replace one another) +## Changelog + +- v0.1.2 - Add async option to Request.run() to permit delaying the processing of the HTTP response. + If the asynchttp module is installed, this will cause the initial call to run(async=True) + to immediately return a get_response function, allowing you to defer the blocking + call until the results are needed. + [factual_docs]: http://developer.factual.com/display/docs/Factual+Developer+APIs+Version+3 [factual_requests_KEY]: http://developer.factual.com/display/docs/Core+API+-+Oauth#CoreAPI-Oauth-KeysandSecrets [factual_signup]: https://www.factual.com/api-keys/request diff --git a/factual/common/requests.py b/factual/common/requests.py index 2ee2eff..581e970 100644 --- a/factual/common/requests.py +++ b/factual/common/requests.py @@ -16,8 +16,23 @@ def __init__(self, session, table): self.session = session # instantiate the table class if we're passed a type rather than an instance (or a string) self.table = table() if isinstance(table, type) else table - def run(self): - return self.session.run(self) + def run(self, async=False): + ''' + Perform the Factual API HTTP request. + + By default, process and return the API response wrapped in a + FactualResponse object. + + Pass `async = True` to perform the request asynchronously; in + async mode, `run` returns a function, get_response, that will + process and return the response when called. + + Additionally, if the asynchttp module is available and async is + True, the initial HTTP request will not block, and get_response + will be returned immediately. get_response function will block + when called if the HTTP requst is not yet complete. + ''' + return self.session.run(self, async) def make_response(self, *args, **kwargs): response = self.response_type(*args, **kwargs) return response diff --git a/factual/common/session.py b/factual/common/session.py index 985d172..b30cbb5 100644 --- a/factual/common/session.py +++ b/factual/common/session.py @@ -1,5 +1,9 @@ import logging -import httplib2 +try: + import asynchttp as http +except ImportError: + import httplib2 as http + try: import simplejson as json except ImportError: @@ -39,17 +43,35 @@ def get_url(self, request): } def get_headers(self, request, defaults={}): return {}.update(defaults) - def run(self, request): + def run(self, request, async=False): url = self.get_url(request) headers = self.get_headers(request) logging.debug(url) logging.debug(headers) - h = httplib2.Http() + h = http.Http() http_response, http_body = h.request(url, headers=headers) - # todo: timing and other metrics - meta = {} - response = request.make_response(json.loads(http_body), meta=meta) - return response + + def get_response(): + ''' + Process and return the HTTP response from Factual. + + Performs the post-request processing needed to handle a Factual + response. Broken into a separate function so the post processing + can be deferred, e.g. for use with asynchttp in place of + httplib2. + + When the asynchttp module is installed, this call will block + if the HTTP request to Factual is not yet complete. + ''' + # todo: timing and other metrics + meta = {} + response = request.make_response(json.loads(str(http_body)), meta=meta) + return response + + if async: + return get_response + else: + return get_response() diff --git a/factual/v2/session.py b/factual/v2/session.py index 313c759..ee0f899 100644 --- a/factual/v2/session.py +++ b/factual/v2/session.py @@ -1,9 +1,4 @@ import logging -import httplib2 -try: - import simplejson as json -except ImportError: - import json import requests import tables diff --git a/factual/v3/session.py b/factual/v3/session.py index 2bf976e..c160b23 100644 --- a/factual/v3/session.py +++ b/factual/v3/session.py @@ -1,10 +1,5 @@ import logging -try: - import simplejson as json -except ImportError: - import json -import httplib2 import oauth2 import requests diff --git a/setup.py b/setup.py index cf67179..967f770 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ setup( name="factual", - version="0.1.1", + version="0.1.2", description="", author="Christopher H. Casebeer", author_email="",