﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
15644	django.core.files.base.File enhancement / fix	nickname123	nobody	"Hi,

I think that django.core.files.base.File should be expanded to handle a wider range of file objects.  In my specific case, StringIO/cStringIO and tempfile.SpooledTemporaryFile objects.

Here is a simple demonstration of where the File class breaks:
{{{
from tempfile import SpooledTemporaryFile
from django.core.files import File
f = SpooledTemporaryFile(
		max_size    = 1024,# 1kb
		mode        = 'w+b',# must be open in binary mode
		bufsize     = -1,
		suffix      = '',
		prefix      = 'tmp',
		dir         = None
)
f.write(""hello"")
print len(File(f))
}}}

Here is the result (on Windows using Python2.6):
{{{
Traceback (most recent call last):
  File ""<stdin>"", line 1, in <module>
  File ""C:\...\django\core\files\base.py"", line 33, in __len__
    return self.size
  File ""C:\...\django\core\files\base.py"", line 39, in _get_size
    elif os.path.exists(self.file.name):
  File ""C:\...\lib\tempfile.py"", line 559, in name
    return self._file.name
AttributeError: 'cStringIO.StringO' object has no attribute 'name'
}}}

It should be noted that not only does the current implementation fail, but it breaks in the wrong code block because it doesn't verify that the name attribute is available.

I propose that the file objects seek and tell method be used as an additional fallback before throwing the attribute error as follows:
{{{
def _get_size(self):
	if not hasattr(self, '_size'):
		if hasattr(self.file, 'size'):
			self._size = self.file.size
		elif hasattr(self.file, 'name') and os.path.exists(self.file.name):
			self._size = os.path.getsize(self.file.name)
		elif hasattr(self.file, 'tell') and hasattr(self.file, 'seek'):
			pos = self.file.tell()
			self.file.seek(0,os.SEEK_END)
			self._size = self.file.tell()
			self.file.seek(pos)
		else:
			raise AttributeError(""Unable to determine the file's size."")
	return self._size
}}}

My proposed patch fixes the problems mentioned above.
"	Bug	closed	File uploads/storage	dev	Normal	fixed	file	michael.palumbo87@…	Ready for checkin	1	0	0	0	0	0
