Show More
@@ -6,6 +6,7 b'' | |||||
6 |
|
6 | |||
7 |
|
7 | |||
8 | from binascii import b2a_base64, hexlify |
|
8 | from binascii import b2a_base64, hexlify | |
|
9 | import html | |||
9 | import json |
|
10 | import json | |
10 | import mimetypes |
|
11 | import mimetypes | |
11 | import os |
|
12 | import os | |
@@ -800,9 +801,20 b' class Image(DisplayObject):' | |||||
800 | _FMT_GIF: 'image/gif', |
|
801 | _FMT_GIF: 'image/gif', | |
801 | } |
|
802 | } | |
802 |
|
803 | |||
803 | def __init__(self, data=None, url=None, filename=None, format=None, |
|
804 | def __init__( | |
804 | embed=None, width=None, height=None, retina=False, |
|
805 | self, | |
805 | unconfined=False, metadata=None): |
|
806 | data=None, | |
|
807 | url=None, | |||
|
808 | filename=None, | |||
|
809 | format=None, | |||
|
810 | embed=None, | |||
|
811 | width=None, | |||
|
812 | height=None, | |||
|
813 | retina=False, | |||
|
814 | unconfined=False, | |||
|
815 | metadata=None, | |||
|
816 | alt=None, | |||
|
817 | ): | |||
806 | """Create a PNG/JPEG/GIF image object given raw data. |
|
818 | """Create a PNG/JPEG/GIF image object given raw data. | |
807 |
|
819 | |||
808 | When this object is returned by an input cell or passed to the |
|
820 | When this object is returned by an input cell or passed to the | |
@@ -847,6 +859,8 b' class Image(DisplayObject):' | |||||
847 | Set unconfined=True to disable max-width confinement of the image. |
|
859 | Set unconfined=True to disable max-width confinement of the image. | |
848 | metadata : dict |
|
860 | metadata : dict | |
849 | Specify extra metadata to attach to the image. |
|
861 | Specify extra metadata to attach to the image. | |
|
862 | alt : unicode | |||
|
863 | Alternative text for the image, for use by screen readers. | |||
850 |
|
864 | |||
851 | Examples |
|
865 | Examples | |
852 | -------- |
|
866 | -------- | |
@@ -924,6 +938,7 b' class Image(DisplayObject):' | |||||
924 | self.height = height |
|
938 | self.height = height | |
925 | self.retina = retina |
|
939 | self.retina = retina | |
926 | self.unconfined = unconfined |
|
940 | self.unconfined = unconfined | |
|
941 | self.alt = alt | |||
927 | super(Image, self).__init__(data=data, url=url, filename=filename, |
|
942 | super(Image, self).__init__(data=data, url=url, filename=filename, | |
928 | metadata=metadata) |
|
943 | metadata=metadata) | |
929 |
|
944 | |||
@@ -933,6 +948,9 b' class Image(DisplayObject):' | |||||
933 | if self.height is None and self.metadata.get('height', {}): |
|
948 | if self.height is None and self.metadata.get('height', {}): | |
934 | self.height = metadata['height'] |
|
949 | self.height = metadata['height'] | |
935 |
|
950 | |||
|
951 | if self.alt is None and self.metadata.get("alt", {}): | |||
|
952 | self.alt = metadata["alt"] | |||
|
953 | ||||
936 | if retina: |
|
954 | if retina: | |
937 | self._retina_shape() |
|
955 | self._retina_shape() | |
938 |
|
956 | |||
@@ -962,18 +980,21 b' class Image(DisplayObject):' | |||||
962 |
|
980 | |||
963 | def _repr_html_(self): |
|
981 | def _repr_html_(self): | |
964 | if not self.embed: |
|
982 | if not self.embed: | |
965 |
width = height = klass = |
|
983 | width = height = klass = alt = "" | |
966 | if self.width: |
|
984 | if self.width: | |
967 | width = ' width="%d"' % self.width |
|
985 | width = ' width="%d"' % self.width | |
968 | if self.height: |
|
986 | if self.height: | |
969 | height = ' height="%d"' % self.height |
|
987 | height = ' height="%d"' % self.height | |
970 | if self.unconfined: |
|
988 | if self.unconfined: | |
971 | klass = ' class="unconfined"' |
|
989 | klass = ' class="unconfined"' | |
972 | return u'<img src="{url}"{width}{height}{klass}/>'.format( |
|
990 | if self.alt: | |
|
991 | alt = ' alt="%s"' % html.escape(self.alt) | |||
|
992 | return '<img src="{url}"{width}{height}{klass}{alt}/>'.format( | |||
973 | url=self.url, |
|
993 | url=self.url, | |
974 | width=width, |
|
994 | width=width, | |
975 | height=height, |
|
995 | height=height, | |
976 | klass=klass, |
|
996 | klass=klass, | |
|
997 | alt=alt, | |||
977 | ) |
|
998 | ) | |
978 |
|
999 | |||
979 | def _repr_mimebundle_(self, include=None, exclude=None): |
|
1000 | def _repr_mimebundle_(self, include=None, exclude=None): | |
@@ -1006,6 +1027,8 b' class Image(DisplayObject):' | |||||
1006 | md['height'] = self.height |
|
1027 | md['height'] = self.height | |
1007 | if self.unconfined: |
|
1028 | if self.unconfined: | |
1008 | md['unconfined'] = self.unconfined |
|
1029 | md['unconfined'] = self.unconfined | |
|
1030 | if self.alt: | |||
|
1031 | md["alt"] = self.alt | |||
1009 | if md or always_both: |
|
1032 | if md or always_both: | |
1010 | return b64_data, md |
|
1033 | return b64_data, md | |
1011 | else: |
|
1034 | else: |
@@ -77,12 +77,12 b' def test_embed_svg_url():' | |||||
77 | from io import BytesIO |
|
77 | from io import BytesIO | |
78 | svg_data = b'<svg><circle x="0" y="0" r="1"/></svg>' |
|
78 | svg_data = b'<svg><circle x="0" y="0" r="1"/></svg>' | |
79 | url = 'http://test.com/circle.svg' |
|
79 | url = 'http://test.com/circle.svg' | |
80 |
|
80 | |||
81 | gzip_svg = BytesIO() |
|
81 | gzip_svg = BytesIO() | |
82 | with gzip.open(gzip_svg, 'wb') as fp: |
|
82 | with gzip.open(gzip_svg, 'wb') as fp: | |
83 | fp.write(svg_data) |
|
83 | fp.write(svg_data) | |
84 | gzip_svg = gzip_svg.getvalue() |
|
84 | gzip_svg = gzip_svg.getvalue() | |
85 |
|
85 | |||
86 | def mocked_urlopen(*args, **kwargs): |
|
86 | def mocked_urlopen(*args, **kwargs): | |
87 | class MockResponse: |
|
87 | class MockResponse: | |
88 | def __init__(self, svg): |
|
88 | def __init__(self, svg): | |
@@ -94,9 +94,9 b' def test_embed_svg_url():' | |||||
94 |
|
94 | |||
95 | if args[0] == url: |
|
95 | if args[0] == url: | |
96 | return MockResponse(svg_data) |
|
96 | return MockResponse(svg_data) | |
97 |
elif args[0] == url + |
|
97 | elif args[0] == url + "z": | |
98 | ret= MockResponse(gzip_svg) |
|
98 | ret = MockResponse(gzip_svg) | |
99 |
ret.headers[ |
|
99 | ret.headers["content-encoding"] = "gzip" | |
100 | return ret |
|
100 | return ret | |
101 | return MockResponse(None) |
|
101 | return MockResponse(None) | |
102 |
|
102 | |||
@@ -105,7 +105,7 b' def test_embed_svg_url():' | |||||
105 | nt.assert_true(svg._repr_svg_().startswith('<svg')) |
|
105 | nt.assert_true(svg._repr_svg_().startswith('<svg')) | |
106 | svg = display.SVG(url=url + 'z') |
|
106 | svg = display.SVG(url=url + 'z') | |
107 | nt.assert_true(svg._repr_svg_().startswith('<svg')) |
|
107 | nt.assert_true(svg._repr_svg_().startswith('<svg')) | |
108 |
|
108 | |||
109 | def test_retina_jpeg(): |
|
109 | def test_retina_jpeg(): | |
110 | here = os.path.dirname(__file__) |
|
110 | here = os.path.dirname(__file__) | |
111 | img = display.Image(os.path.join(here, "2x2.jpg"), retina=True) |
|
111 | img = display.Image(os.path.join(here, "2x2.jpg"), retina=True) | |
@@ -460,6 +460,31 b' def test_display_handle():' | |||||
460 | }) |
|
460 | }) | |
461 |
|
461 | |||
462 |
|
462 | |||
|
463 | def test_image_alt_tag(): | |||
|
464 | """Simple test for display.Image(args, alt=x,)""" | |||
|
465 | thisurl = "http://example.com/image.png" | |||
|
466 | img = display.Image(url=thisurl, alt="an image") | |||
|
467 | nt.assert_equal(u'<img src="%s" alt="an image"/>' % (thisurl), img._repr_html_()) | |||
|
468 | img = display.Image(url=thisurl, unconfined=True, alt="an image") | |||
|
469 | nt.assert_equal( | |||
|
470 | u'<img src="%s" class="unconfined" alt="an image"/>' % (thisurl), | |||
|
471 | img._repr_html_(), | |||
|
472 | ) | |||
|
473 | img = display.Image(url=thisurl, alt='>"& <') | |||
|
474 | nt.assert_equal( | |||
|
475 | u'<img src="%s" alt=">"& <"/>' % (thisurl), img._repr_html_() | |||
|
476 | ) | |||
|
477 | ||||
|
478 | img = display.Image(url=thisurl, metadata={"alt": "an image"}) | |||
|
479 | nt.assert_equal(img.alt, "an image") | |||
|
480 | ||||
|
481 | here = os.path.dirname(__file__) | |||
|
482 | img = display.Image(os.path.join(here, "2x2.png"), alt="an image") | |||
|
483 | nt.assert_equal(img.alt, "an image") | |||
|
484 | _, md = img._repr_png_() | |||
|
485 | nt.assert_equal(md["alt"], "an image") | |||
|
486 | ||||
|
487 | ||||
463 | @nt.raises(FileNotFoundError) |
|
488 | @nt.raises(FileNotFoundError) | |
464 | def test_image_bad_filename_raises_proper_exception(): |
|
489 | def test_image_bad_filename_raises_proper_exception(): | |
465 | display.Image("/this/file/does/not/exist/")._repr_png_() |
|
490 | display.Image("/this/file/does/not/exist/")._repr_png_() |
General Comments 0
You need to be logged in to leave comments.
Login now