This commit is contained in:
Benoît Bryon 2013-05-28 06:22:06 -07:00
commit 46d084d444
3 changed files with 56 additions and 0 deletions

View file

@ -6,6 +6,8 @@ Changelog
Bugfixes and documentation improvements.
- Bug #26 - Prevented computation of virtual file's size, unless the file
wrapper implements was_modified_since() method.
- Bug #34 - Improved support of files that do not implement modification time.
- Bug #35 - Fixed README conversion from reStructuredText to HTML (PyPI).

View file

@ -173,6 +173,27 @@ class VirtualDownloadView(BaseDownloadView):
"""Return wrapper."""
raise NotImplementedError()
def was_modified_since(self, file_instance, since):
"""Delegate to file wrapper's was_modified_since, or return True.
This is the implementation of an edge case: when files are generated
on the fly, we cannot guess whether they have been modified or not.
If the file wrapper implements ``was_modified_since()`` method, then we
trust it. Otherwise it is safer to suppose that the file has been
modified.
This behaviour prevents file size to be computed on the Django side.
Because computing file size means iterating over all the file contents,
and we want to avoid that whenever possible. As an example, it could
reduce all the benefits of working with dynamic file generators...
which is a major feature of virtual files.
"""
try:
return file_instance.was_modified_since(since)
except (AttributeError, NotImplementedError):
return True
class HTTPDownloadView(BaseDownloadView):
"""Proxy files that live on remote servers."""

View file

@ -48,3 +48,36 @@ class DownloadMixinTestCase(unittest.TestCase):
mixin = views.DownloadMixin()
since = mock.sentinel.since
self.assertTrue(mixin.was_modified_since(file_wrapper, since))
class VirtualDownloadViewTestCase(unittest.TestCase):
"""Test suite around
:py:class:`django_downloadview.views.VirtualDownloadView`."""
def test_was_modified_since_specific(self):
"""VirtualDownloadView.was_modified_since() delegates to file wrapper.
"""
file_wrapper = mock.Mock()
file_wrapper.was_modified_since = mock.Mock(
return_value=mock.sentinel.from_file_wrapper)
view = views.VirtualDownloadView()
since = mock.sentinel.since
return_value = view.was_modified_since(file_wrapper, since)
self.assertTrue(return_value is mock.sentinel.from_file_wrapper)
file_wrapper.was_modified_since.assert_called_once_with(since)
def test_was_modified_since_not_implemented(self):
"""VirtualDownloadView.was_modified_since() returns True if file
wrapper does not implement ``was_modified_since()``."""
file_wrapper = mock.Mock()
file_wrapper.was_modified_since = mock.Mock(side_effect=AttributeError)
modified_time = mock.PropertyMock()
setattr(file_wrapper, 'modified_time', modified_time)
size = mock.PropertyMock()
setattr(file_wrapper, 'size', size)
view = views.VirtualDownloadView()
since = mock.sentinel.since
result = view.was_modified_since(file_wrapper, since)
self.assertTrue(result is True)
self.assertFalse(modified_time.called)
self.assertFalse(size.called)