Unverified Kaydet (Commit) 4f474607 authored tarafından Simon Charette's avatar Simon Charette

Fixed #26646 -- Added IOBase methods required by TextIOWrapper to File.

Thanks Tim for the review.
üst 6ab0d135
......@@ -64,10 +64,6 @@ class File(FileProxyMixin):
size = property(_get_size, _set_size)
def _get_closed(self):
return not self.file or self.file.closed
closed = property(_get_closed)
def chunks(self, chunk_size=None):
"""
Read the file and yield chunks of ``chunk_size`` bytes (defaults to
......
......@@ -58,15 +58,6 @@ if os.name == 'nt':
except (OSError):
pass
@property
def closed(self):
"""
This attribute needs to be accessible in certain situations,
because this class is supposed to mock the API of the class
tempfile.NamedTemporaryFile in the Python standard library.
"""
return self.file.closed
def __del__(self):
self.close()
......
from django.utils import six
class FileProxyMixin(object):
"""
A mixin class used to forward file methods to an underlaying file
......@@ -27,8 +24,31 @@ class FileProxyMixin(object):
write = property(lambda self: self.file.write)
writelines = property(lambda self: self.file.writelines)
xreadlines = property(lambda self: self.file.xreadlines)
if six.PY3:
seekable = property(lambda self: self.file.seekable)
@property
def closed(self):
return not self.file or self.file.closed
def readable(self):
if self.closed:
return False
if hasattr(self.file, 'readable'):
return self.file.readable()
return True
def writable(self):
if self.closed:
return False
if hasattr(self.file, 'writable'):
return self.file.writable()
return 'w' in getattr(self.file, 'mode', '')
def seekable(self):
if self.closed:
return False
if hasattr(self.file, 'seekable'):
return self.file.seekable()
return True
def __iter__(self):
return iter(self.file)
......@@ -92,8 +92,13 @@ The ``File`` class
the following attributes and methods of its ``file`` object:
``encoding``, ``fileno``, ``flush``, ``isatty``, ``newlines``,
``read``, ``readinto``, ``readlines``, ``seek``, ``softspace``, ``tell``,
``truncate``, ``writelines``, ``xreadlines``. If you are using
Python 3, the ``seekable`` method is also available.
``truncate``, ``writelines``, ``xreadlines``, ``readable()``,
``writable()``, and ``seekable()``.
.. versionchanged:: 1.11
The ``readable()`` and ``writable()`` methods were added and the
``seekable()`` method was made available on Python 2.
.. currentmodule:: django.core.files.base
......
......@@ -122,7 +122,9 @@ Email
File Storage
~~~~~~~~~~~~
* ...
* To make it wrappable by :class:`io.TextIOWrapper`,
:class:`~django.core.files.File` now has the ``readable()``, ``writable()``,
and ``seekable()`` methods.
File Uploads
~~~~~~~~~~~~
......
......@@ -972,6 +972,7 @@ wordcount
wordwrap
workflow
worksforme
wrappable
wsgi
www
xe
......
......@@ -6,7 +6,7 @@ import os
import struct
import tempfile
import unittest
from io import BytesIO, StringIO
from io import BytesIO, StringIO, TextIOWrapper
from django.core.files import File
from django.core.files.base import ContentFile
......@@ -120,18 +120,39 @@ class FileTests(unittest.TestCase):
f = File(StringIO('one\ntwo\nthree'))
self.assertEqual(list(f), ['one\n', 'two\n', 'three'])
def test_readable(self):
with tempfile.TemporaryFile() as temp, File(temp, name='something.txt') as test_file:
self.assertTrue(test_file.readable())
self.assertFalse(test_file.readable())
def test_writable(self):
with tempfile.TemporaryFile() as temp, File(temp, name='something.txt') as test_file:
self.assertTrue(test_file.writable())
self.assertFalse(test_file.writable())
with tempfile.TemporaryFile('rb') as temp, File(temp, name='something.txt') as test_file:
self.assertFalse(test_file.writable())
def test_seekable(self):
"""
File.seekable() should be available on Python 3.
"""
with tempfile.TemporaryFile() as temp:
temp.write(b"contents\n")
test_file = File(temp, name="something.txt")
if six.PY2:
self.assertFalse(hasattr(test_file, 'seekable'))
if six.PY3:
self.assertTrue(hasattr(test_file, 'seekable'))
self.assertTrue(test_file.seekable())
with tempfile.TemporaryFile() as temp, File(temp, name='something.txt') as test_file:
self.assertTrue(test_file.seekable())
self.assertFalse(test_file.seekable())
def test_io_wrapper(self):
content = "vive l'été\n"
with tempfile.TemporaryFile() as temp, File(temp, name='something.txt') as test_file:
test_file.write(content.encode('utf-8'))
test_file.seek(0)
wrapper = TextIOWrapper(test_file, 'utf-8', newline='\n')
self.assertEqual(wrapper.read(), content)
# The following seek() call is required on Windows Python 2 when
# switching from reading to writing.
wrapper.seek(0, 2)
wrapper.write(content)
wrapper.seek(0)
self.assertEqual(wrapper.read(), content * 2)
test_file = wrapper.detach()
test_file.seek(0)
self.assertEqual(test_file.read(), (content * 2).encode('utf-8'))
class NoNameFileTestCase(unittest.TestCase):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment