Removed compatibility code for streaming responses.

This code provided a deprecation path for old-style streaming responses.

Refs #6527, #7581.
This commit is contained in:
Aymeric Augustin 2013-06-29 15:41:57 +02:00
parent 59b0c48ce2
commit 8b9b8d3bda
4 changed files with 16 additions and 86 deletions

View File

@ -2,9 +2,9 @@ from django.http.cookie import SimpleCookie, parse_cookie
from django.http.request import (HttpRequest, QueryDict, UnreadablePostError,
build_request_repr)
from django.http.response import (HttpResponse, StreamingHttpResponse,
CompatibleStreamingHttpResponse, HttpResponsePermanentRedirect,
HttpResponseRedirect, HttpResponseNotModified, HttpResponseBadRequest,
HttpResponseForbidden, HttpResponseNotFound, HttpResponseNotAllowed,
HttpResponseGone, HttpResponseServerError, Http404, BadHeaderError)
HttpResponseRedirect, HttpResponsePermanentRedirect,
HttpResponseNotModified, HttpResponseBadRequest, HttpResponseForbidden,
HttpResponseNotFound, HttpResponseNotAllowed, HttpResponseGone,
HttpResponseServerError, Http404, BadHeaderError)
from django.http.utils import (fix_location_header, conditional_content_removal,
fix_IE_for_attach, fix_IE_for_vary)

View File

@ -2,7 +2,6 @@ from __future__ import absolute_import, unicode_literals
import datetime
import time
import warnings
from email.header import Header
try:
from urllib.parse import urlparse
@ -332,53 +331,27 @@ class HttpResponse(HttpResponseBase):
else:
__str__ = serialize
def _consume_content(self):
# If the response was instantiated with an iterator, when its content
# is accessed, the iterator is going be exhausted and the content
# loaded in memory. At this point, it's better to abandon the original
# iterator and save the content for later reuse. This is a temporary
# solution. See the comment in __iter__ below for the long term plan.
if self._base_content_is_iter:
self.content = b''.join(self.make_bytes(e) for e in self._container)
@property
def content(self):
self._consume_content()
return b''.join(self.make_bytes(e) for e in self._container)
@content.setter
def content(self, value):
if hasattr(value, '__iter__') and not isinstance(value, (bytes, six.string_types)):
self._container = value
self._base_content_is_iter = True
if hasattr(value, 'close'):
self._closable_objects.append(value)
else:
self._container = [value]
self._base_content_is_iter = False
value = b''.join(self.make_bytes(e) for e in value)
self._container = [value]
def __iter__(self):
# Raise a deprecation warning only if the content wasn't consumed yet,
# because the response may be intended to be streamed.
# Once the deprecation completes, iterators should be consumed upon
# assignment rather than upon access. The _consume_content method
# should be removed. See #6527.
if self._base_content_is_iter:
warnings.warn(
'Creating streaming responses with `HttpResponse` is '
'deprecated. Use `StreamingHttpResponse` instead '
'if you need the streaming behavior.',
DeprecationWarning, stacklevel=2)
if not hasattr(self, '_iterator'):
self._iterator = iter(self._container)
return self
def write(self, content):
self._consume_content()
self._container.append(content)
def tell(self):
self._consume_content()
return len(self.content)
@ -416,35 +389,6 @@ class StreamingHttpResponse(HttpResponseBase):
self._closable_objects.append(value)
class CompatibleStreamingHttpResponse(StreamingHttpResponse):
"""
This class maintains compatibility with middleware that doesn't know how
to handle the content of a streaming response by exposing a `content`
attribute that will consume and cache the content iterator when accessed.
These responses will stream only if no middleware attempts to access the
`content` attribute. Otherwise, they will behave like a regular response,
and raise a `DeprecationWarning`.
"""
@property
def content(self):
warnings.warn(
'Accessing the `content` attribute on a streaming response is '
'deprecated. Use the `streaming_content` attribute instead.',
DeprecationWarning, stacklevel=2)
content = b''.join(self)
self.streaming_content = [content]
return content
@content.setter
def content(self, content):
warnings.warn(
'Accessing the `content` attribute on a streaming response is '
'deprecated. Use the `streaming_content` attribute instead.',
DeprecationWarning, stacklevel=2)
self.streaming_content = [content]
class HttpResponseRedirectBase(HttpResponse):
allowed_schemes = ['http', 'https', 'ftp']
@ -478,7 +422,6 @@ class HttpResponseNotModified(HttpResponse):
if value:
raise AttributeError("You cannot set content to a 304 (Not Modified) response")
self._container = []
self._base_content_is_iter = False
class HttpResponseBadRequest(HttpResponse):

View File

@ -14,8 +14,8 @@ try:
except ImportError: # Python 2
from urllib import unquote
from django.http import (CompatibleStreamingHttpResponse, Http404,
HttpResponse, HttpResponseRedirect, HttpResponseNotModified)
from django.http import (Http404, HttpResponse, HttpResponseRedirect,
HttpResponseNotModified, StreamingHttpResponse)
from django.template import loader, Template, Context, TemplateDoesNotExist
from django.utils.http import http_date, parse_http_date
from django.utils.translation import ugettext as _, ugettext_noop
@ -63,8 +63,8 @@ def serve(request, path, document_root=None, show_indexes=False):
return HttpResponseNotModified()
content_type, encoding = mimetypes.guess_type(fullpath)
content_type = content_type or 'application/octet-stream'
response = CompatibleStreamingHttpResponse(open(fullpath, 'rb'),
content_type=content_type)
response = StreamingHttpResponse(open(fullpath, 'rb'),
content_type=content_type)
response["Last-Modified"] = http_date(statobj.st_mtime)
if stat.S_ISREG(statobj.st_mode):
response["Content-Length"] = statobj.st_size

View File

@ -324,19 +324,10 @@ class HttpResponseTests(unittest.TestCase):
r.content = [1, 2, 3]
self.assertEqual(r.content, b'123')
#test retrieval explicitly using iter (deprecated) and odd inputs
#test odd inputs
r = HttpResponse()
r.content = ['1', '2', 3, '\u079e']
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always", DeprecationWarning)
my_iter = iter(r)
self.assertEqual(w[0].category, DeprecationWarning)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always", DeprecationWarning)
result = list(my_iter)
self.assertEqual(w[0].category, DeprecationWarning)
#'\xde\x9e' == unichr(1950).encode('utf-8')
self.assertEqual(result, [b'1', b'2', b'3', b'\xde\x9e'])
self.assertEqual(r.content, b'123\xde\x9e')
#with Content-Encoding header
@ -344,9 +335,8 @@ class HttpResponseTests(unittest.TestCase):
r['Content-Encoding'] = 'winning'
r.content = [b'abc', b'def']
self.assertEqual(r.content, b'abcdef')
r.content = ['\u079e']
self.assertRaises(TypeError if six.PY3 else UnicodeEncodeError,
getattr, r, 'content')
setattr, r, 'content', ['\u079e'])
# .content can safely be accessed multiple times.
r = HttpResponse(iter(['hello', 'world']))
@ -358,15 +348,12 @@ class HttpResponseTests(unittest.TestCase):
# accessing .content still works
self.assertEqual(r.content, b'helloworld')
# XXX accessing .content doesn't work if the response was iterated first
# XXX change this when the deprecation completes in HttpResponse
# Accessing .content also works if the response was iterated first.
r = HttpResponse(iter(['hello', 'world']))
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
self.assertEqual(b''.join(r), b'helloworld')
self.assertEqual(r.content, b'') # not the expected result!
self.assertEqual(b''.join(r), b'helloworld')
self.assertEqual(r.content, b'helloworld')
# additional content can be written to the response.
# Additional content can be written to the response.
r = HttpResponse(iter(['hello', 'world']))
self.assertEqual(r.content, b'helloworld')
r.write('!')