Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/core/files/uploadedfile.py: 72%
59 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1"""
2Classes representing uploaded files.
3"""
5import os
6from io import BytesIO
8from django.conf import settings
9from django.core.files import temp as tempfile
10from django.core.files.base import File
11from django.core.files.utils import validate_file_name
13__all__ = (
14 "UploadedFile",
15 "TemporaryUploadedFile",
16 "InMemoryUploadedFile",
17 "SimpleUploadedFile",
18)
21class UploadedFile(File):
22 """
23 An abstract uploaded file (``TemporaryUploadedFile`` and
24 ``InMemoryUploadedFile`` are the built-in concrete subclasses).
26 An ``UploadedFile`` object behaves somewhat like a file object and
27 represents some file data that the user submitted with a form.
28 """
30 def __init__(
31 self,
32 file=None,
33 name=None,
34 content_type=None,
35 size=None,
36 charset=None,
37 content_type_extra=None,
38 ):
39 super().__init__(file, name)
40 self.size = size
41 self.content_type = content_type
42 self.charset = charset
43 self.content_type_extra = content_type_extra
45 def __repr__(self):
46 return "<%s: %s (%s)>" % (self.__class__.__name__, self.name, self.content_type)
48 def _get_name(self):
49 return self._name
51 def _set_name(self, name):
52 # Sanitize the file name so that it can't be dangerous.
53 if name is not None: 53 ↛ 65line 53 didn't jump to line 65, because the condition on line 53 was never false
54 # Just use the basename of the file -- anything else is dangerous.
55 name = os.path.basename(name)
57 # File names longer than 255 characters can cause problems on older OSes.
58 if len(name) > 255: 58 ↛ 59line 58 didn't jump to line 59, because the condition on line 58 was never true
59 name, ext = os.path.splitext(name)
60 ext = ext[:255]
61 name = name[: 255 - len(ext)] + ext
63 name = validate_file_name(name)
65 self._name = name
67 name = property(_get_name, _set_name)
70class TemporaryUploadedFile(UploadedFile):
71 """
72 A file uploaded to a temporary location (i.e. stream-to-disk).
73 """
75 def __init__(self, name, content_type, size, charset, content_type_extra=None):
76 _, ext = os.path.splitext(name)
77 file = tempfile.NamedTemporaryFile(
78 suffix=".upload" + ext, dir=settings.FILE_UPLOAD_TEMP_DIR
79 )
80 super().__init__(file, name, content_type, size, charset, content_type_extra)
82 def temporary_file_path(self):
83 """Return the full path of this file."""
84 return self.file.name
86 def close(self):
87 try:
88 return self.file.close()
89 except FileNotFoundError:
90 # The file was moved or deleted before the tempfile could unlink
91 # it. Still sets self.file.close_called and calls
92 # self.file.file.close() before the exception.
93 pass
96class InMemoryUploadedFile(UploadedFile):
97 """
98 A file uploaded into memory (i.e. stream-to-memory).
99 """
101 def __init__(
102 self,
103 file,
104 field_name,
105 name,
106 content_type,
107 size,
108 charset,
109 content_type_extra=None,
110 ):
111 super().__init__(file, name, content_type, size, charset, content_type_extra)
112 self.field_name = field_name
114 def open(self, mode=None):
115 self.file.seek(0)
116 return self
118 def chunks(self, chunk_size=None):
119 self.file.seek(0)
120 yield self.read()
122 def multiple_chunks(self, chunk_size=None):
123 # Since it's in memory, we'll never have multiple chunks.
124 return False
127class SimpleUploadedFile(InMemoryUploadedFile):
128 """
129 A simple representation of a file, which just has content, size, and a name.
130 """
132 def __init__(self, name, content, content_type="text/plain"):
133 content = content or b""
134 super().__init__(
135 BytesIO(content), None, name, content_type, len(content), None, None
136 )
138 @classmethod
139 def from_dict(cls, file_dict):
140 """
141 Create a SimpleUploadedFile object from a dictionary with keys:
142 - filename
143 - content-type
144 - content
145 """
146 return cls(
147 file_dict["filename"],
148 file_dict["content"],
149 file_dict.get("content-type", "text/plain"),
150 )