diff -r 6641e941ef1e -r ff1a9aa48cfd app/django/core/files/base.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/django/core/files/base.py Tue Oct 14 16:00:59 2008 +0000 @@ -0,0 +1,169 @@ +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)