No-seek implementation of HttpResponse Image.open

This is an alternative implementation for `Image.open()`
to support opening of images from HttpResponse objects. It
uses `.seekable()` to determine whether the file supports
seeking (with failover for this attribute not being supported
e.g. in `urllib2` response objects).

The prefix is chopped off as normal and pre-pended back onto
the bytes fed into the `io.IOBytes` object. This avoids loading
the image object totally (duplicating it in memory) until
we are sure we have a factory for the file.

Add AttributeError exception catch; add io.IOBytes wrapper only once

Add callable .seek test for Python2.x
This commit is contained in:
Martin Fitzpatrick 2015-03-30 21:53:09 +02:00
parent 174d9ac083
commit dc23e64d6e

View File

@ -2250,9 +2250,11 @@ def open(fp, mode="r"):
filename = ""
try:
fp.seek(0)
except (AttributeError, io.UnsupportedOperation):
fp = io.BytesIO(fp.read())
requires_iobytes_wrapper = not fp.seekable()
except AttributeError:
# Not a subclass of io.IOBase; probably Python 2.7 file (or urllib object)
# Check we have a seek fn on the object
requires_iobytes_wrapper = not callable( getattr(fp, "seek", None) )
prefix = fp.read(16)
@ -2262,6 +2264,9 @@ def open(fp, mode="r"):
try:
factory, accept = OPEN[i]
if not accept or accept(prefix):
if requires_iobytes_wrapper:
fp = io.BytesIO(prefix + fp.read())
requires_iobytes_wrapper = False # Wrapping once is enough
fp.seek(0)
im = factory(fp, filename)
_decompression_bomb_check(im.size)
@ -2277,6 +2282,9 @@ def open(fp, mode="r"):
try:
factory, accept = OPEN[i]
if not accept or accept(prefix):
if requires_iobytes_wrapper:
fp = io.BytesIO(prefix + fp.read())
requires_iobytes_wrapper = False # Wrapping once is enough
fp.seek(0)
im = factory(fp, filename)
_decompression_bomb_check(im.size)