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 |
|
|
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 |
|
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