Introduced more flexible callbacks.

Callbacks are now called when the response
is about to be written.
A callback now takes the actual request as
first parameter. And can be any object that is
callable. Furthermore the signature of the
return value has changed to a tuple returning
the status code along with the headers and the body.
This allows for more logic in the callbacks.

Callbacks and regex url matching now work together
because the real request is used for passing the
url the callback instead of the Regex
This commit is contained in:
Kai Richard Koenig
2013-03-20 11:15:36 +01:00
parent d3fe69469a
commit 6671320cc5
4 changed files with 74 additions and 14 deletions

View File

@@ -320,7 +320,6 @@ class fakesock(object):
for matcher, value in HTTPretty._entries.items():
if matcher.matches(info):
entries = value
info = matcher.info
break
if not entries:
@@ -328,6 +327,13 @@ class fakesock(object):
return
self._entry = matcher.get_next_entry(method)
# Attach more info to the entry
# So the callback can be more clever about what to do
# This does also fix the case where the callback
# would be handed a compiled regex as uri instead of the
# real uri
self._entry.info = info
self._entry.request = request
def debug(*a, **kw):
frame = inspect.stack()[0][0]
@@ -464,17 +470,21 @@ class Entry(Py3kObject):
self.method = method
self.uri = uri
self.info = None
self.request = None
if isinstance(body, types.FunctionType):
self.body = body(method, uri, headers)
else:
self.body = body
self.body_is_callable = False
if hasattr(body,"__call__"):
self.body_is_callable = True
self.body = body
self.streaming = streaming
if not streaming:
if not streaming and not self.body_is_callable:
self.body_length = len(self.body or '')
else:
self.body_length = 0
self.adding_headers = adding_headers or {}
self.forcing_headers = forcing_headers or {}
self.status = int(status)
@@ -541,8 +551,11 @@ class Entry(Py3kObject):
headers.update(self.normalize_headers(self.adding_headers))
headers = self.normalize_headers(headers)
status = headers.get('status', self.status)
if self.body_is_callable:
status, headers, self.body = self.body(self.request,self.info.full_url(),headers)
headers.update({'content-length':len(self.body)})
string_list = [
'HTTP/1.1 %d %s' % (status, STATUSES[status]),
]

View File

@@ -266,8 +266,8 @@ def test_callback_response(now):
(u"HTTPretty should all a callback function to be set as the body with"
" httplib2")
def request_callback(method, uri, headers):
return "The {0} response from {1}".format(decode_utf8(method), uri)
def request_callback(request, uri, headers):
return [200,headers,"The {0} response from {1}".format(decode_utf8(request.method), uri)]
HTTPretty.register_uri(
HTTPretty.GET, "https://api.yahoo.com/test",

View File

@@ -391,11 +391,11 @@ def test_multipart():
@httprettified
@within(two=microseconds)
def test_callback_response(now):
(u"HTTPretty should all a callback function to be set as the body with"
(u"HTTPretty should call a callback function and set its return value as the body of the response"
" requests")
def request_callback(method, uri, headers):
return "The {0} response from {1}".format(decode_utf8(method), uri)
def request_callback(request, uri, headers):
return [200, headers,"The {0} response from {1}".format(decode_utf8(request.method), uri)]
HTTPretty.register_uri(
HTTPretty.GET, "https://api.yahoo.com/test",
@@ -416,6 +416,53 @@ def test_callback_response(now):
expect(response.text).to.equal("The POST response from https://api.yahoo.com/test_post")
@httprettified
@within(two=microseconds)
def test_callback_setting_headers_and_status_response(now):
(u"HTTPretty should call a callback function and uses it retur tuple as status code, headers and body"
" requests")
def request_callback(request, uri, headers):
headers.update({'a':'b'})
return [418,headers,"The {0} response from {1}".format(decode_utf8(request.method), uri)]
HTTPretty.register_uri(
HTTPretty.GET, "https://api.yahoo.com/test",
body=request_callback)
response = requests.get('https://api.yahoo.com/test')
expect(response.text).to.equal("The GET response from https://api.yahoo.com/test")
expect(response.headers).to.have.key('a').being.equal("b")
expect(response.status_code).to.be(418)
HTTPretty.register_uri(
HTTPretty.POST, "https://api.yahoo.com/test_post",
body=request_callback)
response = requests.post(
"https://api.yahoo.com/test_post",
{"username": "gabrielfalcao"}
)
expect(response.text).to.equal("The POST response from https://api.yahoo.com/test_post")
expect(response.headers).to.have.key('a').being.equal("b")
expect(response.status_code).to.be(418)
@httprettified
def test_httpretty_should_allow_registering_regexes_and_give_a_proper_match_to_the_callback():
u"HTTPretty should allow registering regexes with requests and giva a proper match to the callback"
HTTPretty.register_uri(
HTTPretty.GET,
re.compile("https://api.yipit.com/v1/deal;brand=(?P<brand_name>\w+)"),
body=lambda method,uri,headers: [200,headers,uri]
)
response = requests.get('https://api.yipit.com/v1/deal;brand=gap?first_name=chuck&last_name=norris')
expect(response.text).to.equal('https://api.yipit.com/v1/deal;brand=gap?first_name=chuck&last_name=norris')
expect(HTTPretty.last_request.method).to.equal('GET')
expect(HTTPretty.last_request.path).to.equal('/v1/deal;brand=gap?first_name=chuck&last_name=norris')
@httprettified
def test_httpretty_should_allow_registering_regexes():

View File

@@ -284,8 +284,8 @@ def test_callback_response(now):
(u"HTTPretty should all a callback function to be set as the body with"
" urllib2")
def request_callback(method, uri, headers):
return "The {0} response from {1}".format(decode_utf8(method), uri)
def request_callback(request, uri, headers):
return [200, headers, "The {0} response from {1}".format(decode_utf8(request.method), uri)]
HTTPretty.register_uri(
HTTPretty.GET, "https://api.yahoo.com/test",