##// END OF EJS Templates
Backport PR #12232: ensure SVG(url=...) is set correctly
Matthias Bussonnier -
Show More
@@ -615,9 +615,12 b' class DisplayObject(object):'
615 filename = data
615 filename = data
616 data = None
616 data = None
617
617
618 self.data = data
619 self.url = url
618 self.url = url
620 self.filename = filename
619 self.filename = filename
620 # because of @data.setter methods in
621 # subclasses ensure url and filename are set
622 # before assigning to self.data
623 self.data = data
621
624
622 if metadata is not None:
625 if metadata is not None:
623 self.metadata = metadata
626 self.metadata = metadata
@@ -652,23 +655,36 b' class DisplayObject(object):'
652 with open(self.filename, self._read_flags) as f:
655 with open(self.filename, self._read_flags) as f:
653 self.data = f.read()
656 self.data = f.read()
654 elif self.url is not None:
657 elif self.url is not None:
655 try:
658 # Deferred import
656 # Deferred import
659 from urllib.request import urlopen
657 from urllib.request import urlopen
660 response = urlopen(self.url)
658 response = urlopen(self.url)
661 data = response.read()
659 self.data = response.read()
662 # extract encoding from header, if there is one:
660 # extract encoding from header, if there is one:
663 encoding = None
661 encoding = None
664 if 'content-type' in response.headers:
662 for sub in response.headers['content-type'].split(';'):
665 for sub in response.headers['content-type'].split(';'):
663 sub = sub.strip()
666 sub = sub.strip()
664 if sub.startswith('charset'):
667 if sub.startswith('charset'):
665 encoding = sub.split('=')[-1].strip()
668 encoding = sub.split('=')[-1].strip()
666 break
669 break
667 # decode data, if an encoding was specified
670 if 'content-encoding' in response.headers:
668 if encoding:
671 # TODO: do deflate?
669 self.data = self.data.decode(encoding, 'replace')
672 if 'gzip' in response.headers['content-encoding']:
670 except:
673 import gzip
671 self.data = None
674 from io import BytesIO
675 with gzip.open(BytesIO(data), 'rt', encoding=encoding) as fp:
676 encoding = None
677 data = fp.read()
678
679 # decode data, if an encoding was specified
680 # We only touch self.data once since
681 # subclasses such as SVG have @data.setter methods
682 # that transform self.data into ... well svg.
683 if encoding:
684 self.data = data.decode(encoding, 'replace')
685 else:
686 self.data = data
687
672
688
673 class TextDisplayObject(DisplayObject):
689 class TextDisplayObject(DisplayObject):
674 """Validate that display data is text"""
690 """Validate that display data is text"""
@@ -736,6 +752,11 b' class Latex(TextDisplayObject):'
736
752
737
753
738 class SVG(DisplayObject):
754 class SVG(DisplayObject):
755 """Embed an SVG into the display.
756
757 Note if you just want to view a svg image via a URL use `:class:Image` with
758 a url=URL keyword argument.
759 """
739
760
740 _read_flags = 'rb'
761 _read_flags = 'rb'
741 # wrap data in a property, which extracts the <svg> tag, discarding
762 # wrap data in a property, which extracts the <svg> tag, discarding
@@ -879,7 +900,7 b' class JSON(DisplayObject):'
879 data = str(data)
900 data = str(data)
880
901
881 if isinstance(data, str):
902 if isinstance(data, str):
882 if getattr(self, 'filename', None) is None:
903 if self.filename is None and self.url is None:
883 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
904 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
884 data = json.loads(data)
905 data = json.loads(data)
885 self._data = data
906 self._data = data
@@ -72,6 +72,45 b' def test_retina_png():'
72 nt.assert_equal(md['width'], 1)
72 nt.assert_equal(md['width'], 1)
73 nt.assert_equal(md['height'], 1)
73 nt.assert_equal(md['height'], 1)
74
74
75 def test_embed_svg_url():
76 import gzip
77 from io import BytesIO
78 svg_data = b'<svg><circle x="0" y="0" r="1"/></svg>'
79 url = 'http://test.com/circle.svg'
80
81 gzip_svg = BytesIO()
82 with gzip.open(gzip_svg, 'wb') as fp:
83 fp.write(svg_data)
84 gzip_svg = gzip_svg.getvalue()
85
86 def mocked_urlopen(*args, **kwargs):
87 class MockResponse:
88 def __init__(self, svg):
89 self._svg_data = svg
90 self.headers = {'content-type': 'image/svg+xml'}
91
92 def read(self):
93 return self._svg_data
94
95 if args[0] == url:
96 return MockResponse(svg_data)
97 elif args[0] == url + 'z':
98 ret= MockResponse(gzip_svg)
99 ret.headers['content-encoding']= 'gzip'
100 return ret
101 return MockResponse(None)
102
103 with mock.patch('urllib.request.urlopen', side_effect=mocked_urlopen):
104 svg = display.SVG(url=url)
105 nt.assert_true(svg._repr_svg_().startswith('<svg'))
106 svg = display.SVG(url=url + 'z')
107 nt.assert_true(svg._repr_svg_().startswith('<svg'))
108
109 # do it for real: 6.1kB of data
110 url = "https://upload.wikimedia.org/wikipedia/commons/3/30/Vector-based_example.svg"
111 svg = display.SVG(url=url)
112 nt.assert_true(svg._repr_svg_().startswith('<svg'))
113
75 def test_retina_jpeg():
114 def test_retina_jpeg():
76 here = os.path.dirname(__file__)
115 here = os.path.dirname(__file__)
77 img = display.Image(os.path.join(here, "2x2.jpg"), retina=True)
116 img = display.Image(os.path.join(here, "2x2.jpg"), retina=True)
General Comments 0
You need to be logged in to leave comments. Login now