| import os |
| |
| from django.utils.encoding import smart_str, smart_unicode |
| |
| try: |
| from cStringIO import StringIO |
| except ImportError: |
| from StringIO import StringIO |
| |
| class File(object): |
| DEFAULT_CHUNK_SIZE = 64 * 2**10 |
| |
| def __init__(self, file): |
| self.file = file |
| self._name = file.name |
| self._mode = file.mode |
| self._closed = False |
| |
| def __str__(self): |
| return smart_str(self.name or '') |
| |
| def __unicode__(self): |
| return smart_unicode(self.name or u'') |
| |
| def __repr__(self): |
| return "<%s: %s>" % (self.__class__.__name__, self or "None") |
| |
| def __nonzero__(self): |
| return not not self.name |
| |
| def __len__(self): |
| return self.size |
| |
| def _get_name(self): |
| return self._name |
| name = property(_get_name) |
| |
| def _get_mode(self): |
| return self._mode |
| mode = property(_get_mode) |
| |
| def _get_closed(self): |
| return self._closed |
| closed = property(_get_closed) |
| |
| def _get_size(self): |
| if not hasattr(self, '_size'): |
| if hasattr(self.file, 'size'): |
| self._size = self.file.size |
| elif os.path.exists(self.file.name): |
| self._size = os.path.getsize(self.file.name) |
| else: |
| raise AttributeError("Unable to determine the file's size.") |
| return self._size |
| |
| def _set_size(self, size): |
| self._size = size |
| |
| size = property(_get_size, _set_size) |
| |
| def chunks(self, chunk_size=None): |
| """ |
| Read the file and yield chucks of ``chunk_size`` bytes (defaults to |
| ``UploadedFile.DEFAULT_CHUNK_SIZE``). |
| """ |
| if not chunk_size: |
| chunk_size = self.__class__.DEFAULT_CHUNK_SIZE |
| |
| if hasattr(self, 'seek'): |
| self.seek(0) |
| # Assume the pointer is at zero... |
| counter = self.size |
| |
| while counter > 0: |
| yield self.read(chunk_size) |
| counter -= chunk_size |
| |
| def multiple_chunks(self, chunk_size=None): |
| """ |
| Returns ``True`` if you can expect multiple chunks. |
| |
| NB: If a particular file representation is in memory, subclasses should |
| always return ``False`` -- there's no good reason to read from memory in |
| chunks. |
| """ |
| if not chunk_size: |
| chunk_size = self.DEFAULT_CHUNK_SIZE |
| return self.size > chunk_size |
| |
| def xreadlines(self): |
| return iter(self) |
| |
| def readlines(self): |
| return list(self.xreadlines()) |
| |
| def __iter__(self): |
| # Iterate over this file-like object by newlines |
| buffer_ = None |
| for chunk in self.chunks(): |
| chunk_buffer = StringIO(chunk) |
| |
| for line in chunk_buffer: |
| if buffer_: |
| line = buffer_ + line |
| buffer_ = None |
| |
| # If this is the end of a line, yield |
| # otherwise, wait for the next round |
| if line[-1] in ('\n', '\r'): |
| yield line |
| else: |
| buffer_ = line |
| |
| if buffer_ is not None: |
| yield buffer_ |
| |
| def open(self, mode=None): |
| if not self.closed: |
| self.seek(0) |
| elif os.path.exists(self.file.name): |
| self.file = open(self.file.name, mode or self.file.mode) |
| else: |
| raise ValueError("The file cannot be reopened.") |
| |
| def seek(self, position): |
| self.file.seek(position) |
| |
| def tell(self): |
| return self.file.tell() |
| |
| def read(self, num_bytes=None): |
| if num_bytes is None: |
| return self.file.read() |
| return self.file.read(num_bytes) |
| |
| def write(self, content): |
| if not self.mode.startswith('w'): |
| raise IOError("File was not opened with write access.") |
| self.file.write(content) |
| |
| def flush(self): |
| if not self.mode.startswith('w'): |
| raise IOError("File was not opened with write access.") |
| self.file.flush() |
| |
| def close(self): |
| self.file.close() |
| self._closed = True |
| |
| class ContentFile(File): |
| """ |
| A File-like object that takes just raw content, rather than an actual file. |
| """ |
| def __init__(self, content): |
| self.file = StringIO(content or '') |
| self.size = len(content or '') |
| self.file.seek(0) |
| self._closed = False |
| |
| def __str__(self): |
| return 'Raw content' |
| |
| def __nonzero__(self): |
| return True |
| |
| def open(self, mode=None): |
| if self._closed: |
| self._closed = False |
| self.seek(0) |