Code

Opened 6 years ago

Closed 5 years ago

Last modified 3 years ago

#7712 closed (fixed)

UploadedFile missing readline method

Reported by: artagnon Owned by: nobody
Component: File uploads/storage Version: master
Severity: Keywords: upload uploadedfile
Cc: ville@… Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

I encountered this while trying to use an uploaded image (using a form with ImageField) with PIL. The relevant code is as below:

import PIL

def Avatar_file_handler(personInstance, avatarImage):
    """Writes the avatarImage to personInstance after necessary processing
    avatarImage is an UploadedFile object"""

    im = PIL.Image.open(avatarImage)
    # *** Error on this line!

The pdb trace is as follows:

-> im = Image.open(avatarImage)
(Pdb)  Image.open(avatarImage)
*** AttributeError: 'InMemoryUploadedFile' object has no attribute 'readline'
(Pdb) s
--Call--
> /usr/lib/python2.5/site-packages/PIL/Image.py(1880)open()
-> def open(fp, mode="r"):
(Pdb) n
> /usr/lib/python2.5/site-packages/PIL/Image.py(1883)open()
-> if mode != "r":
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1886)open()
-> if isStringType(fp):
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1891)open()
-> filename = ""
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1893)open()
-> prefix = fp.read(16)
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1895)open()
-> preinit()
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1897)open()
-> for i in ID:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1898)open()
-> try:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1899)open()
-> factory, accept = OPEN[i]
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1900)open()
-> if not accept or accept(prefix):
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1897)open()
-> for i in ID:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1898)open()
-> try:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1899)open()
-> factory, accept = OPEN[i]
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1900)open()
-> if not accept or accept(prefix):
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1897)open()
-> for i in ID:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1898)open()
-> try:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1899)open()
-> factory, accept = OPEN[i]
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1900)open()
-> if not accept or accept(prefix):
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1897)open()
-> for i in ID:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1898)open()
-> try:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1899)open()
-> factory, accept = OPEN[i]
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1900)open()
-> if not accept or accept(prefix):
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1897)open()
-> for i in ID:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1898)open()
-> try:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1899)open()
-> factory, accept = OPEN[i]
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1900)open()
-> if not accept or accept(prefix):
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1897)open()
-> for i in ID:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1898)open()
-> try:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1899)open()
-> factory, accept = OPEN[i]
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1900)open()
-> if not accept or accept(prefix):
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1897)open()
-> for i in ID:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1898)open()
-> try:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1899)open()
-> factory, accept = OPEN[i]
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1900)open()
-> if not accept or accept(prefix):
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1897)open()
-> for i in ID:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1898)open()
-> try:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1899)open()
-> factory, accept = OPEN[i]
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1900)open()
-> if not accept or accept(prefix):
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1897)open()
-> for i in ID:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1898)open()
-> try:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1899)open()
-> factory, accept = OPEN[i]
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1900)open()
-> if not accept or accept(prefix):
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1897)open()
-> for i in ID:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1898)open()
-> try:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1899)open()
-> factory, accept = OPEN[i]
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1900)open()
-> if not accept or accept(prefix):
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1897)open()
-> for i in ID:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1898)open()
-> try:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1899)open()
-> factory, accept = OPEN[i]
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1900)open()
-> if not accept or accept(prefix):
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1897)open()
-> for i in ID:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1898)open()
-> try:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1899)open()
-> factory, accept = OPEN[i]
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1900)open()
-> if not accept or accept(prefix):
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1897)open()
-> for i in ID:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1898)open()
-> try:
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1899)open()
-> factory, accept = OPEN[i]
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1900)open()
-> if not accept or accept(prefix):
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1901)open()
-> fp.seek(0)
(Pdb) 
> /usr/lib/python2.5/site-packages/PIL/Image.py(1902)open()
-> return factory(fp, filename)
(Pdb) 
SyntaxError: SyntaxEr...A file',)
> /usr/lib/python2.5/site-packages/PIL/Image.py(1902)open()
-> return factory(fp, filename)
(Pdb) print factory(fp, filename)
*** SyntaxError: invalid IPTC/NAA file

Attachments (0)

Change History (10)

comment:1 Changed 6 years ago by MihaiD

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to worksforme
  • Status changed from new to closed

Couldn't replicate your problem in a similar scenario

comment:2 Changed 6 years ago by jacob_od

  • Resolution worksforme deleted
  • Status changed from closed to reopened

More info on this one. This happens because the PIL image plugin ImtImagePlugin.py will use the File method readline, IF the first 100 bytes contain a newline "\n". This also will only happen if this imageplugin is tried before the correct image is loaded. In Image.py:init() an os.listdir() is called and it loops through all imageplugins until it finds the right one. Since os.listdir() returns the directories content in arbitrary order you may or may not see this bug. PIL loads the different plugins until it finds the right one so for instance it will load BMPPlugin and say no this image is not a BMP, then it loads JPG and tries and on and on until it finds the correct image type.... so if you happen to be unlucky and the machine loads ImtImagePlugin.py before it hits your actual image type AND your image contains newlines within the first 100 bytes (I believe the image we have that does this is a TIFF created with Microsoft Paint), then it will try to execute a readline on the image and you see the error. I guess the solution to this would have to be make the Request.FILES more file like and implement all file methods.

Currently this can be worked around by going like this

file = StringIO.StringIO(request.FILESugpFile?.read())
image = Image.open(file)

BTW, I TOTALLY <3 DJANGO U GUYZ R THE BEST AND GIVE ME A BILLION WOODIES A DAY! THANKS!!!!

comment:3 Changed 6 years ago by jacob_od

  • milestone changed from 1.0 beta to post-1.0

file = StringIO.StringIO(request.FILES[filename].read()); image = Image.open(file)

comment:4 Changed 6 years ago by julien

  • Component changed from Tools to File uploads/storage

comment:5 Changed 5 years ago by anonymous

  • milestone post-1.0 deleted

Milestone post-1.0 deleted

comment:6 Changed 5 years ago by jacob

  • Summary changed from UploadedFile doesn't act like a file object to UploadedFile missing readline method
  • Triage Stage changed from Unreviewed to Accepted

comment:7 Changed 5 years ago by Uninen

  • Cc ville@… added

comment:8 Changed 5 years ago by jacob

  • Resolution set to fixed
  • Status changed from reopened to closed

Fixed in [10717].

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.