Opened 8 years ago

Closed 8 years ago

Last modified 6 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

Change History (10)

comment:1 Changed 8 years ago by Mihai Damian

Resolution: worksforme
Status: newclosed

Couldn't replicate your problem in a similar scenario

comment:2 Changed 8 years ago by jacob_od

Resolution: worksforme
Status: closedreopened

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 8 years ago by jacob_od

milestone: 1.0 betapost-1.0

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

comment:4 Changed 8 years ago by Julien Phalip

Component: ToolsFile uploads/storage

comment:5 Changed 8 years ago by (none)

milestone: post-1.0

Milestone post-1.0 deleted

comment:6 Changed 8 years ago by Jacob

Summary: UploadedFile doesn't act like a file objectUploadedFile missing readline method
Triage Stage: UnreviewedAccepted

comment:7 Changed 8 years ago by Ville Säävuori

Cc: ville@… added

comment:8 Changed 8 years ago by Jacob

Resolution: fixed
Status: reopenedclosed

Fixed in [10717].

comment:10 Changed 6 years ago by Jay Hargis

Note: See TracTickets for help on using tickets.
Back to Top