#30252 closed Cleanup/optimization (fixed)
ImageField's to_python() stores reference to closed Image object
Reported by: | Felix Dreissig | Owned by: | Hasan Ramezani |
---|---|---|---|
Component: | Documentation | 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
In django.forms.fields.ImageField's to_python()
method, an uploaded image is validated by open()
ing a PIL.Image object from it and calling verify()
on that. Afterwards, the Image object is saved to an image
attribute of the uploaded file (i.e. an InMemoryUploadedFile). According to a comment in the source, this happens so that "subclasses can reuse it for their own validation".
Pillow closes an Image after verify()
ing and the docs state that it cannot be used after calling verify
on it:
If you need to load the image after using this method, you must reopen the image file.
For me, this resulted in the following error when trying to explicitly call save()
on the Image, but similar effects will probably happen for any operation:
File ".../lib/python3.6/site-packages/PIL/Image.py", line 1960, in save self.load() File ".../lib/python3.6/site-packages/PIL/ImageFile.py", line 165, in load seek = self.fp.seek AttributeError: 'NoneType' object has no attribute 'seek'
This could be related to #13750, but I don't think so.
Attachments (2)
Change History (16)
comment:1 by , 6 years ago
comment:2 by , 6 years ago
Thanks for your quick response.
I could probably come up with a test case, but it will take some time. How would you like it? As a GitHub pull request (which would introduce a failing test until a fix is commited), or as a patch in this ticket?
A fix I could think of would be re-open()
ing the Image after verification and storing that object to the image
attribute. Or removing the attribute completely (since it appears useless in its current state), but that would break an (undocumented) API.
comment:3 by , 6 years ago
Resolution: | → needsinfo |
---|---|
Status: | new → closed |
An attachment or comment in this ticket is fine. Closing ticket as "needinfo" until we have the steps to reproduce and can better evaluate the issue.
by , 6 years ago
Attachment: | 0001-Refs-30252-Added-test-demonstrating-the-issue.patch added |
---|
Patch containing a test demonstrating the issue
by , 6 years ago
Attachment: | 0002-Fixed-30252-Reopen-uploaded-image-after-verify.patch added |
---|
Patch containing a possible fix
comment:4 by , 6 years ago
Resolution: | needsinfo |
---|---|
Status: | closed → new |
Please find two patches (in git format-patch
format) now attached to this issue:
- A test demonstrating the issue.
- A possible fix. I still think a (possibly better) alternative would be removing the attribute and let users call
open()
themselves if they need to, but one could consider that a breaking change.
comment:5 by , 6 years ago
Component: | File uploads/storage → Forms |
---|
The original commit is 8b7347220f3d86b46f5f87270c6cdcb9960895fd. As you can see there, the non-image data attributes like format
, height
, and width
are available without reopening the image. Does your purposed change affect performance? An alternative could be to clarify that subclasses need to reopen the image to access certain methods.
follow-up: 8 comment:6 by , 6 years ago
Hi Felix.
I'm inclined to see both this and #13750 as documentation issues... Let's just be clearer about the behaviour.
Just for your proposal: if we reopen the file, where are we closing it again?
comment:7 by , 6 years ago
Component: | Forms → Documentation |
---|---|
Triage Stage: | Unreviewed → Accepted |
Type: | Bug → Cleanup/optimization |
Hi Felix,
I'm going to accept this as a Documentation fix for now: there's no reason at all why we couldn't clarify the behaviour here.
I'm happy to consider the code change as a possibility if we can show that it's desirable and not problematic.
Thanks.
comment:8 by , 6 years ago
Replying to Tim Graham:
The original commit is 8b7347220f3d86b46f5f87270c6cdcb9960895fd. As you can see there, the non-image data attributes like
format
,height
, andwidth
are available without reopening the image.
Yes. If I recall my analysis correctly, basically all attributes are accessible, while no methods are.
Does your purposed change affect performance?
Since open()
is a lazy operation in Pillow (image data is not loaded until accessed), I assume the performance impact would be negligible. I haven't run any measurements, though.
Replying to Carlton Gibson:
Just for your proposal: if we reopen the file, where are we closing it again?
Fair point. Images themselves don't have to be closed in Pillow, but underlying file pointers do. So this should only be relevant if we have a temporary file path (no in-memory image data).
According to the Pillow docs on file handling, file pointers for single-frame images are automatically closed after load()
has been called. However, as stated above, loading might not always happen. On top of that, multi-frame images are probably always problematic.
comment:9 by , 5 years ago
Has patch: | set |
---|---|
Owner: | changed from | to
Status: | new → assigned |
comment:10 by , 5 years ago
Patch needs improvement: | set |
---|---|
Version: | 2.1 → master |
comment:11 by , 5 years ago
Patch needs improvement: | unset |
---|
Can you offer a test for Django's test suite that demonstrates the issue? Do you have a fix in mind?