From 5126ce3b315d98a9744c3f1a3e3e9a744708c5ea Mon Sep 17 00:00:00 2001 From: Ryan Nelson Date: Sat, 21 Mar 2015 10:29:41 -0400 Subject: [PATCH 1/8] Allow URL strings to be passed to imread These modifications allow valid URL strings to be passed directly into imread. URL recognition is done using the standard library function urlparse. If the string contains a valid url scheme, it will be used to download and process the data using a combination of urlopen and BytesIO (StringIO in python 2). --- lib/matplotlib/image.py | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index 2428147218bb..56dca1578cb4 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -7,6 +7,9 @@ unicode_literals) import six +from six.moves.urllib.parse import urlparse +from six.moves.urllib.request import urlopen +from six import BytesIO import os import warnings @@ -1225,10 +1228,17 @@ def pilread(fname): except ImportError: return None if cbook.is_string_like(fname): - # force close the file after reading the image - with open(fname, "rb") as fh: + parsed = urlparse(fname) + # If the string is a URL, then download the data + if parsed.scheme is not '': + fh = BytesIO(urlopen(fname).read()) image = Image.open(fh) return pil_to_array(image) + else: + # force close the file after reading the image + with open(fname, "rb") as fh: + image = Image.open(fh) + return pil_to_array(image) else: image = Image.open(fname) return pil_to_array(image) @@ -1236,8 +1246,13 @@ def pilread(fname): handlers = {'png': _png.read_png, } if format is None: if cbook.is_string_like(fname): - basename, ext = os.path.splitext(fname) - ext = ext.lower()[1:] + parsed = urlparse(fname) + # If the string is a URL, assume png + if parsed.scheme is not '': + ext = 'png' + else: + basename, ext = os.path.splitext(fname) + ext = ext.lower()[1:] elif hasattr(fname, 'name'): basename, ext = os.path.splitext(fname.name) ext = ext.lower()[1:] @@ -1260,8 +1275,14 @@ def pilread(fname): # reader extension, since Python handles them quite well, but it's # tricky in C. if cbook.is_string_like(fname): - with open(fname, 'rb') as fd: + parsed = urlparse(fname) + # If fname is a URL, download the data + if parsed.scheme is not '': + fd = BytesIO(urlopen(fname).read()) return handler(fd) + else: + with open(fname, 'rb') as fd: + return handler(fd) else: return handler(fname) From c5bc3013d8060f9fed34a2237bf08f9978cfb72b Mon Sep 17 00:00:00 2001 From: Ryan Nelson Date: Tue, 14 Apr 2015 08:07:58 -0400 Subject: [PATCH 2/8] Remove file name logic from pilread function The Pillow docs state that Image.open can handle either a filename string or a file object. That simplifies the pilread function substantially. --- lib/matplotlib/image.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index 56dca1578cb4..d952932ee4d7 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -1227,21 +1227,8 @@ def pilread(fname): from PIL import Image except ImportError: return None - if cbook.is_string_like(fname): - parsed = urlparse(fname) - # If the string is a URL, then download the data - if parsed.scheme is not '': - fh = BytesIO(urlopen(fname).read()) - image = Image.open(fh) - return pil_to_array(image) - else: - # force close the file after reading the image - with open(fname, "rb") as fh: - image = Image.open(fh) - return pil_to_array(image) - else: - image = Image.open(fname) - return pil_to_array(image) + image = Image.open(fname) + return pil_to_array(image) handlers = {'png': _png.read_png, } if format is None: From ff90cf0eefd0f9fc4cd1ec0bbb736edc710796a6 Mon Sep 17 00:00:00 2001 From: Ryan Nelson Date: Thu, 16 Apr 2015 11:51:01 -0400 Subject: [PATCH 3/8] Update identity test to equality test It seems that the identity test for the parsed URL scheme was not sufficient. I changed this to an equality test, and things are now working properly. --- lib/matplotlib/image.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index d952932ee4d7..db815456598c 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -1235,7 +1235,7 @@ def pilread(fname): if cbook.is_string_like(fname): parsed = urlparse(fname) # If the string is a URL, assume png - if parsed.scheme is not '': + if parsed.scheme != '': ext = 'png' else: basename, ext = os.path.splitext(fname) @@ -1264,7 +1264,8 @@ def pilread(fname): if cbook.is_string_like(fname): parsed = urlparse(fname) # If fname is a URL, download the data - if parsed.scheme is not '': + if parsed.scheme != '': + print('Scheme: %s' % parsed.scheme) fd = BytesIO(urlopen(fname).read()) return handler(fd) else: From cce999d5620926d1ab227a15412ebd214b65b642 Mon Sep 17 00:00:00 2001 From: Ryan Nelson Date: Thu, 28 May 2015 10:49:30 -0400 Subject: [PATCH 4/8] Remove debug print function --- lib/matplotlib/image.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index db815456598c..9773fd1d9449 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -1265,7 +1265,6 @@ def pilread(fname): parsed = urlparse(fname) # If fname is a URL, download the data if parsed.scheme != '': - print('Scheme: %s' % parsed.scheme) fd = BytesIO(urlopen(fname).read()) return handler(fd) else: From 11f792522a73642d1d22f8278e615e5294f0b8af Mon Sep 17 00:00:00 2001 From: Ryan Nelson Date: Thu, 28 May 2015 11:54:04 -0400 Subject: [PATCH 5/8] Update Whats New documentation. --- doc/users/whats_new.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index f3dfbb720e89..54568d54c6a5 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -75,6 +75,13 @@ directive - ``close-figs`` - that closes any previous figure windows before creating the plots. This can help avoid some surprising duplicates of plots when using ``plot_directive``. +Support for URL string arguments to ``imread`` +---------------------------------------------- + +The ``imread`` function now accepts URL strings that point to remote PNG +files. This circumvents the generation of a HTTPResponse object directly. + + .. _whats-new-1-4: new in matplotlib-1.4 From 683004c500d548aaa6a6ac4bde5ffd9c6d3cb1c0 Mon Sep 17 00:00:00 2001 From: Ryan Nelson Date: Thu, 28 May 2015 11:54:24 -0400 Subject: [PATCH 6/8] Update imread docstring for URL strings. --- lib/matplotlib/image.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index 9773fd1d9449..f223f0db9b23 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -1204,8 +1204,9 @@ def imread(fname, format=None): """ Read an image from a file into an array. - *fname* may be a string path or a Python file-like object. If - using a file object, it must be opened in binary mode. + *fname* may be a string path, a valid URL, or a Python + file-like object. If using a file object, it must be opened in binary + mode. If *format* is provided, will try to read file of that type, otherwise the format is deduced from the filename. If nothing can @@ -1218,7 +1219,9 @@ def imread(fname, format=None): matplotlib can only read PNGs natively, but if `PIL `_ is installed, it will use it to load the image and return an array (if possible) which - can be used with :func:`~matplotlib.pyplot.imshow`. + can be used with :func:`~matplotlib.pyplot.imshow`. Note, URL strings + may not be compatible with PIL. Check the PIL documentation for more + information. """ def pilread(fname): From d44d0fe76e8ab67841ae7a724c2ca502e86051ac Mon Sep 17 00:00:00 2001 From: Ryan Nelson Date: Thu, 28 May 2015 12:03:11 -0400 Subject: [PATCH 7/8] Remove trailing whitespace. --- lib/matplotlib/image.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index f223f0db9b23..a5b5b4ab88d0 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -1219,7 +1219,7 @@ def imread(fname, format=None): matplotlib can only read PNGs natively, but if `PIL `_ is installed, it will use it to load the image and return an array (if possible) which - can be used with :func:`~matplotlib.pyplot.imshow`. Note, URL strings + can be used with :func:`~matplotlib.pyplot.imshow`. Note, URL strings may not be compatible with PIL. Check the PIL documentation for more information. """ From 3c96fd37e7146c6a3a8f479a6f5f7c493839081c Mon Sep 17 00:00:00 2001 From: Ryan Nelson Date: Thu, 28 May 2015 11:45:48 -0400 Subject: [PATCH 8/8] Add test for imread with URL string Also added the logo2.png file to the test image folder. If there is a URLError, imread will simply open the local file and print a little error. --- .../baseline_images/test_image/imread_url.png | Bin 0 -> 27238 bytes lib/matplotlib/tests/test_image.py | 9 +++++++++ 2 files changed, 9 insertions(+) create mode 100644 lib/matplotlib/tests/baseline_images/test_image/imread_url.png diff --git a/lib/matplotlib/tests/baseline_images/test_image/imread_url.png b/lib/matplotlib/tests/baseline_images/test_image/imread_url.png new file mode 100644 index 0000000000000000000000000000000000000000..dc2d80cefe31fb90012aef60dc4c2e9d928404ef GIT binary patch literal 27238 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 BL#+S+ literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/test_image.py b/lib/matplotlib/tests/test_image.py index 89338d33fdad..34f47f25ffc3 100644 --- a/lib/matplotlib/tests/test_image.py +++ b/lib/matplotlib/tests/test_image.py @@ -89,6 +89,15 @@ def test_image_python_io(): buffer.seek(0) plt.imread(buffer) +@image_comparison(baseline_images=['imread_url'], extensions=['png']) +def test_imread_url_string(): + try: + img = plt.imread('http://matplotlib.org/_static/logo2.png') + except URLError: + print('No network access. Test imread_url_string skipped.') + img = plt.imread(os.path.join(os.path.dirname(__file__), + 'baseline_images', 'test_image', 'imread_url.png')) + @knownfailureif(not HAS_PIL) def test_imread_pil_uint16(): img = plt.imread(os.path.join(os.path.dirname(__file__),