app: Fixed an issue with unicode responses in Python 2.7
If a controller callable returns a string, it needs to be wrapped in a Response object. To determine if this is the case, the Application tests to see if the returned object is an instance of `basestring`. Since `basestring` doesn't exist in Python 3, only `str` is a valid return type. Unfortunately, my way of testing whether the `basestring` type existed was flawed. Instead of raising `NameError` when it doesn't exist, `UnboundLocalError` (a subclass `NameError`) is *always* raised. Since the exception handler sets `basestring` equal to `str` assuming this is Python 3, most of the time this isn't a problem. If, however, the controller returns a `unicode` object in Python 2, the `isinstance` call returns `False`, so the response is not wrapped in a Response object. Rather than try to reassign the `basestring` name, now we just use `_string`, which will either be `basestring` (in Python 2) or `str` (in Python 3). Apparently, the unit tests didn't cover this case...master
parent
a2d8f6f098
commit
cf94a4d600
|
@ -103,12 +103,11 @@ class Application(object):
|
||||||
# but we need to wrap it in a Response object
|
# but we need to wrap it in a Response object
|
||||||
try:
|
try:
|
||||||
# In Python 2, it could be a str or a unicode object
|
# In Python 2, it could be a str or a unicode object
|
||||||
basestring = basestring #@UndefinedVariable
|
_string = basestring
|
||||||
except NameError:
|
except NameError:
|
||||||
# Python 3 has no unicode objects and thus no need for
|
# In Python 3, we are only interested in str objects
|
||||||
# basestring so we, just make it an alias for str
|
_string = str
|
||||||
basestring = str
|
if isinstance(response, _string) or not response:
|
||||||
if isinstance(response, basestring) or not response:
|
|
||||||
response = request.ResponseClass(response)
|
response = request.ResponseClass(response)
|
||||||
|
|
||||||
if not start_response_wrapper.called:
|
if not start_response_wrapper.called:
|
||||||
|
|
|
@ -3,13 +3,31 @@
|
||||||
:Created: Nov 27, 2012
|
:Created: Nov 27, 2012
|
||||||
:Author: dustin
|
:Author: dustin
|
||||||
'''
|
'''
|
||||||
|
from unittest.case import SkipTest
|
||||||
import functools
|
import functools
|
||||||
import milla.app
|
import milla.app
|
||||||
import milla.dispatch
|
import milla.dispatch
|
||||||
import nose.tools
|
import nose.tools
|
||||||
|
import sys
|
||||||
import wsgiref.util
|
import wsgiref.util
|
||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
|
def python2_only(test):
|
||||||
|
@functools.wraps(test)
|
||||||
|
def wrapper():
|
||||||
|
if sys.version_info[0] != 2:
|
||||||
|
raise SkipTest
|
||||||
|
return test()
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
def python3_only(test):
|
||||||
|
@functools.wraps(test)
|
||||||
|
def wrapper():
|
||||||
|
if sys.version_info[0] != 3:
|
||||||
|
raise SkipTest
|
||||||
|
return test()
|
||||||
|
return wrapper
|
||||||
|
|
||||||
class StubResolver(object):
|
class StubResolver(object):
|
||||||
'''Stub resolver for testing purposes'''
|
'''Stub resolver for testing purposes'''
|
||||||
|
|
||||||
|
@ -145,6 +163,64 @@ def test_emulated_method():
|
||||||
response.finish_response(app_iter)
|
response.finish_response(app_iter)
|
||||||
assert response.headers.startswith('HTTP/1.1 200'), response.headers
|
assert response.headers.startswith('HTTP/1.1 200'), response.headers
|
||||||
|
|
||||||
|
def test_return_none():
|
||||||
|
'''Controllers can return None
|
||||||
|
'''
|
||||||
|
|
||||||
|
def controller(request):
|
||||||
|
return None
|
||||||
|
|
||||||
|
app = milla.app.Application(StubResolver(controller))
|
||||||
|
environ = environ_for_testing()
|
||||||
|
response = ResponseMaker()
|
||||||
|
app_iter = app(environ, response.start_response)
|
||||||
|
response.finish_response(app_iter)
|
||||||
|
assert not response.body, response.body
|
||||||
|
|
||||||
|
def test_return_str():
|
||||||
|
'''Controllers can return str objects
|
||||||
|
'''
|
||||||
|
|
||||||
|
def controller(request):
|
||||||
|
return 'Hello, world'
|
||||||
|
|
||||||
|
app = milla.app.Application(StubResolver(controller))
|
||||||
|
environ = environ_for_testing()
|
||||||
|
response = ResponseMaker()
|
||||||
|
app_iter = app(environ, response.start_response)
|
||||||
|
response.finish_response(app_iter)
|
||||||
|
assert response.body == b'Hello, world', response.body
|
||||||
|
|
||||||
|
@python2_only
|
||||||
|
def test_return_unicode():
|
||||||
|
'''Controllers can return unicode objects
|
||||||
|
'''
|
||||||
|
|
||||||
|
def controller(request):
|
||||||
|
return unicode('Hello, world')
|
||||||
|
|
||||||
|
app = milla.app.Application(StubResolver(controller))
|
||||||
|
environ = environ_for_testing()
|
||||||
|
response = ResponseMaker()
|
||||||
|
app_iter = app(environ, response.start_response)
|
||||||
|
response.finish_response(app_iter)
|
||||||
|
assert response.body == unicode('Hello, world'), response.body
|
||||||
|
|
||||||
|
@nose.tools.raises(AttributeError)
|
||||||
|
@python3_only
|
||||||
|
def test_return_bytes():
|
||||||
|
'''Controllers cannot return bytes objects
|
||||||
|
'''
|
||||||
|
|
||||||
|
def controller(request):
|
||||||
|
return b'Hello, world'
|
||||||
|
|
||||||
|
app = milla.app.Application(StubResolver(controller))
|
||||||
|
environ = environ_for_testing()
|
||||||
|
response = ResponseMaker()
|
||||||
|
app_iter = app(environ, response.start_response)
|
||||||
|
response.finish_response(app_iter)
|
||||||
|
|
||||||
@nose.tools.raises(BeforeCalled)
|
@nose.tools.raises(BeforeCalled)
|
||||||
def test_function_before():
|
def test_function_before():
|
||||||
'''__before__ attribute is called for controller functions
|
'''__before__ attribute is called for controller functions
|
||||||
|
@ -484,4 +560,3 @@ def test_static_resource_undefined():
|
||||||
app_iter = app(environ, response.start_response)
|
app_iter = app(environ, response.start_response)
|
||||||
response.finish_response(app_iter)
|
response.finish_response(app_iter)
|
||||||
assert response.body == b'/image.png', response.body
|
assert response.body == b'/image.png', response.body
|
||||||
|
|
Loading…
Reference in New Issue