~ubuntu-branches/ubuntu/jaunty/python-django/jaunty

« back to all changes in this revision

Viewing changes to django/core/files/uploadedfile.py

  • Committer: Bazaar Package Importer
  • Author(s): Scott James Remnant, Eddy Mulyono
  • Date: 2008-09-16 12:18:47 UTC
  • mfrom: (1.1.5 upstream) (4.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080916121847-mg225rg5mnsdqzr0
Tags: 1.0-1ubuntu1
* Merge from Debian (LP: #264191), remaining changes:
  - Run test suite on build.

[Eddy Mulyono]
* Update patch to workaround network test case failures.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""
 
2
Classes representing uploaded files.
 
3
"""
 
4
 
 
5
import os
 
6
try:
 
7
    from cStringIO import StringIO
 
8
except ImportError:
 
9
    from StringIO import StringIO
 
10
 
 
11
from django.conf import settings
 
12
from django.core.files.base import File
 
13
from django.core.files import temp as tempfile
 
14
from django.utils.encoding import smart_str
 
15
 
 
16
__all__ = ('UploadedFile', 'TemporaryUploadedFile', 'InMemoryUploadedFile',
 
17
           'SimpleUploadedFile')
 
18
 
 
19
class UploadedFile(File):
 
20
    """
 
21
    A abstract uploaded file (``TemporaryUploadedFile`` and
 
22
    ``InMemoryUploadedFile`` are the built-in concrete subclasses).
 
23
 
 
24
    An ``UploadedFile`` object behaves somewhat like a file object and
 
25
    represents some file data that the user submitted with a form.
 
26
    """
 
27
    DEFAULT_CHUNK_SIZE = 64 * 2**10
 
28
 
 
29
    def __init__(self, name=None, content_type=None, size=None, charset=None):
 
30
        self.name = name
 
31
        self.size = size
 
32
        self.content_type = content_type
 
33
        self.charset = charset
 
34
 
 
35
    def __repr__(self):
 
36
        return "<%s: %s (%s)>" % (self.__class__.__name__, smart_str(self.name), self.content_type)
 
37
 
 
38
    def _get_name(self):
 
39
        return self._name
 
40
 
 
41
    def _set_name(self, name):
 
42
        # Sanitize the file name so that it can't be dangerous.
 
43
        if name is not None:
 
44
            # Just use the basename of the file -- anything else is dangerous.
 
45
            name = os.path.basename(name)
 
46
 
 
47
            # File names longer than 255 characters can cause problems on older OSes.
 
48
            if len(name) > 255:
 
49
                name, ext = os.path.splitext(name)
 
50
                name = name[:255 - len(ext)] + ext
 
51
 
 
52
        self._name = name
 
53
 
 
54
    name = property(_get_name, _set_name)
 
55
 
 
56
    # Abstract methods; subclasses *must* define read() and probably should
 
57
    # define open/close.
 
58
    def read(self, num_bytes=None):
 
59
        raise NotImplementedError()
 
60
 
 
61
    def open(self):
 
62
        pass
 
63
 
 
64
    def close(self):
 
65
        pass
 
66
 
 
67
class TemporaryUploadedFile(UploadedFile):
 
68
    """
 
69
    A file uploaded to a temporary location (i.e. stream-to-disk).
 
70
    """
 
71
    def __init__(self, name, content_type, size, charset):
 
72
        super(TemporaryUploadedFile, self).__init__(name, content_type, size, charset)
 
73
        if settings.FILE_UPLOAD_TEMP_DIR:
 
74
            self._file = tempfile.NamedTemporaryFile(suffix='.upload', dir=settings.FILE_UPLOAD_TEMP_DIR)
 
75
        else:
 
76
            self._file = tempfile.NamedTemporaryFile(suffix='.upload')
 
77
 
 
78
    def temporary_file_path(self):
 
79
        """
 
80
        Returns the full path of this file.
 
81
        """
 
82
        return self._file.name
 
83
 
 
84
    # Most methods on this object get proxied to NamedTemporaryFile.
 
85
    # We can't directly subclass because NamedTemporaryFile is actually a
 
86
    # factory function
 
87
    def read(self, *args):          return self._file.read(*args)
 
88
    def seek(self, *args):          return self._file.seek(*args)
 
89
    def write(self, s):             return self._file.write(s)
 
90
    def tell(self, *args):          return self._file.tell(*args)
 
91
    def __iter__(self):             return iter(self._file)
 
92
    def readlines(self, size=None): return self._file.readlines(size)
 
93
    def xreadlines(self):           return self._file.xreadlines()
 
94
    def close(self):
 
95
        try:
 
96
            return self._file.close()
 
97
        except OSError, e:
 
98
            if e.errno == 2:
 
99
                # Means the file was moved or deleted before the tempfile could unlink it.
 
100
                # Still sets self._file.close_called and calls self._file.file.close()
 
101
                # before the exception
 
102
                return
 
103
            else:
 
104
                raise e
 
105
 
 
106
class InMemoryUploadedFile(UploadedFile):
 
107
    """
 
108
    A file uploaded into memory (i.e. stream-to-memory).
 
109
    """
 
110
    def __init__(self, file, field_name, name, content_type, size, charset):
 
111
        super(InMemoryUploadedFile, self).__init__(name, content_type, size, charset)
 
112
        self._file = file
 
113
        self.field_name = field_name
 
114
        self._file.seek(0)
 
115
 
 
116
    def open(self):
 
117
        self._file.seek(0)
 
118
 
 
119
    def chunks(self, chunk_size=None):
 
120
        self._file.seek(0)
 
121
        yield self.read()
 
122
 
 
123
    def multiple_chunks(self, chunk_size=None):
 
124
        # Since it's in memory, we'll never have multiple chunks.
 
125
        return False
 
126
 
 
127
    # proxy methods to StringIO
 
128
    def read(self, *args): return self._file.read(*args)
 
129
    def seek(self, *args): return self._file.seek(*args)
 
130
    def tell(self, *args): return self._file.tell(*args)
 
131
    def close(self):       return self._file.close()
 
132
 
 
133
class SimpleUploadedFile(InMemoryUploadedFile):
 
134
    """
 
135
    A simple representation of a file, which just has content, size, and a name.
 
136
    """
 
137
    def __init__(self, name, content, content_type='text/plain'):
 
138
        self._file = StringIO(content or '')
 
139
        self.name = name
 
140
        self.field_name = None
 
141
        self.size = len(content or '')
 
142
        self.content_type = content_type
 
143
        self.charset = None
 
144
        self._file.seek(0)
 
145
 
 
146
    def from_dict(cls, file_dict):
 
147
        """
 
148
        Creates a SimpleUploadedFile object from
 
149
        a dictionary object with the following keys:
 
150
           - filename
 
151
           - content-type
 
152
           - content
 
153
        """
 
154
        return cls(file_dict['filename'],
 
155
                   file_dict['content'],
 
156
                   file_dict.get('content-type', 'text/plain'))
 
157
 
 
158
    from_dict = classmethod(from_dict)