Skip to content

Commit

Permalink
allow user to pass content type and encoding, change favicon example …
Browse files Browse the repository at this point in the history
…to use FileResponse
  • Loading branch information
mcdonc committed Feb 23, 2012
1 parent 6b3cca0 commit c2e82a7
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 9 deletions.
15 changes: 9 additions & 6 deletions docs/narr/assets.rst
Expand Up @@ -370,19 +370,22 @@ do so, do things "by hand". First define the view callable.
:linenos:
import os
from pyramid.response import Response
from pyramid.response import FileResponse
def favicon_view(request):
here = os.path.dirname(__file__)
icon = open(os.path.join(here, 'static', 'favicon.ico'), 'rb')
return Response(content_type='image/x-icon', app_iter=icon)
icon = os.path.join(here, 'static', 'favicon.ico')
return FileResponse(icon, request=request)
The above bit of code within ``favicon_view`` computes "here", which is a
path relative to the Python file in which the function is defined. It then
uses the Python ``open`` function to obtain a file handle to a file within
"here" named ``static``, and returns a response using the open the file
handle as the response's ``app_iter``. It makes sure to set the right
content_type too.
"here" named ``static``, and returns a :class:`pyramid.response.Fileresponse`
using the file path as the response's ``path`` argument and the request as
the response's ``request`` argument. :class:`pyramid.response.FileResponse`
will serve the file as quickly as possible when it's used this way. It makes
sure to set the right content length and content_type too based on the file
extension of the file you pass.

You might register such a view via configuration as a view callable that
should be called as the result of a traversal:
Expand Down
15 changes: 12 additions & 3 deletions pyramid/response.py
Expand Up @@ -30,12 +30,21 @@ class FileResponse(Response):
``cache_max_age`` if passed, is the number of seconds that should be used
to HTTP cache this response.
``content_type``, if passed, is the content_type of the response.
``content_encoding``, if passed is the content_encoding of the response.
It's generally safe to leave this set to ``None`` if you're serving a
binary file. This argument will be ignored if you don't also pass
``content-type``.
"""
def __init__(self, path, request=None, cache_max_age=None):
def __init__(self, path, request=None, cache_max_age=None,
content_type=None, content_encoding=None):
super(FileResponse, self).__init__(conditional_response=True)
self.last_modified = getmtime(path)
content_type, content_encoding = mimetypes.guess_type(path,
strict=False)
if content_type is None:
content_type, content_encoding = mimetypes.guess_type(path,
strict=False)
if content_type is None:
content_type = 'application/octet-stream'
self.content_type = content_type
Expand Down
20 changes: 20 additions & 0 deletions pyramid/tests/test_response.py
@@ -1,4 +1,5 @@
import io
import os
import unittest
from pyramid import testing

Expand All @@ -17,6 +18,25 @@ def test_provides_IResponse(self):
inst = self._getTargetClass()()
self.assertTrue(IResponse.providedBy(inst))

class TestFileResponse(unittest.TestCase):
def _makeOne(self, file, **kw):
from pyramid.response import FileResponse
return FileResponse(file, **kw)

def _getPath(self):
here = os.path.dirname(__file__)
return os.path.join(here, 'fixtures', 'minimal.txt')

def test_with_content_type(self):
path = self._getPath()
r = self._makeOne(path, content_type='image/jpeg')
self.assertEqual(r.content_type, 'image/jpeg')

def test_without_content_type(self):
path = self._getPath()
r = self._makeOne(path)
self.assertEqual(r.content_type, 'text/plain')

class TestFileIter(unittest.TestCase):
def _makeOne(self, file, block_size):
from pyramid.response import FileIter
Expand Down

0 comments on commit c2e82a7

Please sign in to comment.