#8222 closed Uncategorized (wontfix)
Storage should reset file's cursor after saving
Reported by: | Julien Phalip | Owned by: | nobody |
---|---|---|---|
Component: | File uploads/storage | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Accepted | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I had some trouble finding the cause of that problem. Basically, I was trying to save an uploaded image and then manipulate that image with PIL. But the following didn't work:
from PIL import Image storage.save('/images/image.gif', uploaded_file) # Save the original uploaded_image = Image.open(uploaded_file) ...
After debugging PIL I realised that it assumes the given file starts at position 0. Therefore, the following works:
from PIL import Image storage.save('/images/image.gif', uploaded_file) # Save the original uploaded_file.seek(0) # >> REWIND FILE << uploaded_image = Image.open(uploaded_file) ...
I think it would be good practice to automatically rewind the file after it's been saved, so that other tools can process the file without having to rewind it manually. That would feel more logical from an outside perspective.
Patch attached.
Attachments (2)
Change History (10)
by , 16 years ago
Attachment: | 8222.file.storage.rewind.diff added |
---|
comment:1 by , 16 years ago
Just a note about the tests I've written. I couldn't get temp_file.read()
to return a unicode value 'some contents'
, even if creating it explicitly: ContentFile('some contents')
.
Maybe I've missed something simple there. What do you think?
by , 16 years ago
Attachment: | 8222.storage.save.diff added |
---|
Same patch, but changed the word 'rewind'
comment:2 by , 16 years ago
Summary: | Storage should rewind files after saving → Storage should reset file's cursor after saving |
---|
'Rewind' is probably not the best word since we're dealing with direct file access :)
comment:3 by , 16 years ago
Component: | Uncategorized → File uploads/storage |
---|---|
Triage Stage: | Unreviewed → Accepted |
comment:4 by , 16 years ago
Hmmm, I'm now wondering if this ticket is in fact valid...
FileSystemStorage._save()
is supposed to close the file after it's been saved, right? In that case, it doesn't make sense to reset the cursor's position. Could Marty Alchin, or someone familiar enough with FileSystemStorage
confirm this?
I believe that the reason uploaded_file
still existed after saving was because I was testing on Windows, and that temporary uploaded files are not cleaned up properly on that platform. See ticket #8203.
If someone can confirm all that, then I guess this ticket is invalid. The right way would be to manipulate the file first, then save the manipulated version, and *lastly* save the original:
manipulated_image = Image.open(uploaded_file) ... storage.save('/images/manipulated_image.gif', manipulated_image) # Save the manipulated image and close it. storage.save('/images/image.gif', uploaded_file) # Save the original and close it.
comment:5 by , 16 years ago
One question though: should closing the file after saving be enforced to every storage system?
Currently FileSystemStorage._save()
seems to do it itself, but Storage.save()
doesn't enforce it by default.
comment:6 by , 16 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
This change causes a test failure:
====================================================================== ERROR: test_large_upload (regressiontests.file_uploads.tests.FileUploadTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/jacob/Projects/Django/upstream/tests/regressiontests/file_uploads/tests.py", line 53, in test_large_upload response = self.client.post('/file_uploads/verify/', post_data) File "/Users/jacob/Projects/Django/upstream/django/test/client.py", line 285, in post return self.request(**r) File "/Users/jacob/Projects/Django/upstream/django/core/handlers/base.py", line 86, in get_response response = callback(request, *callback_args, **callback_kwargs) File "/Users/jacob/Projects/Django/upstream/tests/regressiontests/file_uploads/views.py", line 52, in file_upload_view_verify obj.testfile.save(largefile.name, largefile) File "/Users/jacob/Projects/Django/upstream/django/db/models/fields/files.py", line 74, in save self._name = self.storage.save(name, content) File "/Users/jacob/Projects/Django/upstream/django/core/files/storage.py", line 46, in save content.seek(0) File "/Users/jacob/Projects/Django/upstream/django/core/files/uploadedfile.py", line 88, in seek def seek(self, *args): return self._file.seek(*args) ValueError: I/O operation on closed file ----------------------------------------------------------------------
This is because depending on what type of file content
is, seek()
may not be valid after the file's been saved.
So I think you're right that this is invalid; you can always call seek()
manually should you need to (or simply save the other file first, like you figured out).
comment:8 by , 12 years ago
Easy pickings: | unset |
---|---|
Severity: | → Normal |
Type: | → Uncategorized |
UI/UX: | unset |
Patch and regression tests