Format: text/x-python
⬇ Download File (15.6 KB)
   1  # Copyright (c) IPython Development Team.
   2  # Distributed under the terms of the Modified BSD License.
   3  
   4  import json
   5  import os
   6  import warnings
   7  
   8  from unittest import mock
   9  
  10  import pytest
  11  
  12  from IPython import display
  13  from IPython.core.getipython import get_ipython
  14  from IPython.utils.io import capture_output
  15  from IPython.utils.tempdir import NamedFileInTemporaryDirectory
  16  from IPython import paths as ipath
  17  from IPython.testing.tools import AssertNotPrints
  18  
  19  import IPython.testing.decorators as dec
  20  
  21  def test_image_size():
  22      """Simple test for display.Image(args, width=x,height=y)"""
  23      thisurl = 'http://www.google.fr/images/srpr/logo3w.png'
  24      img = display.Image(url=thisurl, width=200, height=200)
  25      assert '<img src="%s" width="200" height="200"/>' % (thisurl) == img._repr_html_()
  26      img = display.Image(url=thisurl, metadata={'width':200, 'height':200})
  27      assert '<img src="%s" width="200" height="200"/>' % (thisurl) == img._repr_html_()
  28      img = display.Image(url=thisurl, width=200)
  29      assert '<img src="%s" width="200"/>' % (thisurl) == img._repr_html_()
  30      img = display.Image(url=thisurl)
  31      assert '<img src="%s"/>' % (thisurl) == img._repr_html_()
  32      img = display.Image(url=thisurl, unconfined=True)
  33      assert '<img src="%s" class="unconfined"/>' % (thisurl) == img._repr_html_()
  34  
  35  
  36  def test_image_mimes():
  37      fmt = get_ipython().display_formatter.format
  38      for format in display.Image._ACCEPTABLE_EMBEDDINGS:
  39          mime = display.Image._MIMETYPES[format]
  40          img = display.Image(b'garbage', format=format)
  41          data, metadata = fmt(img)
  42          assert sorted(data) == sorted([mime, "text/plain"])
  43  
  44  
  45  def test_geojson():
  46  
  47      gj = display.GeoJSON(data={
  48              "type": "Feature",
  49              "geometry": {
  50                  "type": "Point",
  51                  "coordinates": [-81.327, 296.038]
  52              },
  53              "properties": {
  54                  "name": "Inca City"
  55              }
  56          },
  57          url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
  58          layer_options={
  59              "basemap_id": "celestia_mars-shaded-16k_global",
  60              "attribution": "Celestia/praesepe",
  61              "minZoom": 0,
  62              "maxZoom": 18,
  63          },
  64      )
  65      assert "<IPython.core.display.GeoJSON object>" == str(gj)
  66  
  67  
  68  def test_retina_png():
  69      here = os.path.dirname(__file__)
  70      img = display.Image(os.path.join(here, "2x2.png"), retina=True)
  71      assert img.height == 1
  72      assert img.width == 1
  73      data, md = img._repr_png_()
  74      assert md["width"] == 1
  75      assert md["height"] == 1
  76  
  77  
  78  def test_embed_svg_url():
  79      import gzip
  80      from io import BytesIO
  81      svg_data = b'<svg><circle x="0" y="0" r="1"/></svg>'
  82      url = 'http://test.com/circle.svg'
  83  
  84      gzip_svg = BytesIO()
  85      with gzip.open(gzip_svg, 'wb') as fp:
  86          fp.write(svg_data)
  87      gzip_svg = gzip_svg.getvalue()
  88  
  89      def mocked_urlopen(*args, **kwargs):
  90          class MockResponse:
  91              def __init__(self, svg):
  92                  self._svg_data = svg
  93                  self.headers = {'content-type': 'image/svg+xml'}
  94  
  95              def read(self):
  96                  return self._svg_data
  97  
  98          if args[0] == url:
  99              return MockResponse(svg_data)
 100          elif args[0] == url + "z":
 101              ret = MockResponse(gzip_svg)
 102              ret.headers["content-encoding"] = "gzip"
 103              return ret
 104          return MockResponse(None)
 105  
 106      with mock.patch('urllib.request.urlopen', side_effect=mocked_urlopen):
 107          svg = display.SVG(url=url)
 108          assert svg._repr_svg_().startswith("<svg") is True
 109          svg = display.SVG(url=url + "z")
 110          assert svg._repr_svg_().startswith("<svg") is True
 111  
 112  
 113  def test_retina_jpeg():
 114      here = os.path.dirname(__file__)
 115      img = display.Image(os.path.join(here, "2x2.jpg"), retina=True)
 116      assert img.height == 1
 117      assert img.width == 1
 118      data, md = img._repr_jpeg_()
 119      assert md["width"] == 1
 120      assert md["height"] == 1
 121  
 122  
 123  def test_base64image():
 124      display.Image("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BCRQnOqNu0b4AAAAKSURBVAjXY2AAAAACAAHiIbwzAAAAAElFTkSuQmCC")
 125  
 126  def test_image_filename_defaults():
 127      '''test format constraint, and validity of jpeg and png'''
 128      tpath = ipath.get_ipython_package_dir()
 129      pytest.raises(
 130          ValueError,
 131          display.Image,
 132          filename=os.path.join(tpath, "testing/tests/badformat.zip"),
 133          embed=True,
 134      )
 135      pytest.raises(ValueError, display.Image)
 136      pytest.raises(
 137          ValueError,
 138          display.Image,
 139          data="this is not an image",
 140          format="badformat",
 141          embed=True,
 142      )
 143      # check both paths to allow packages to test at build and install time
 144      imgfile = os.path.join(tpath, 'core/tests/2x2.png')
 145      img = display.Image(filename=imgfile)
 146      assert "png" == img.format
 147      assert img._repr_png_() is not None
 148      img = display.Image(
 149          filename=os.path.join(tpath, "testing/tests/logo.jpg"), embed=False
 150      )
 151      assert "jpeg" == img.format
 152      assert img._repr_jpeg_() is None
 153  
 154  def _get_inline_config():
 155      from matplotlib_inline.config import InlineBackend
 156      return InlineBackend.instance()
 157  
 158  
 159  @dec.skip_without("matplotlib")
 160  def test_set_matplotlib_close():
 161      cfg = _get_inline_config()
 162      cfg.close_figures = False
 163      with pytest.deprecated_call():
 164          display.set_matplotlib_close()
 165      assert cfg.close_figures
 166      with pytest.deprecated_call():
 167          display.set_matplotlib_close(False)
 168      assert not cfg.close_figures
 169  
 170  _fmt_mime_map = {
 171      'png': 'image/png',
 172      'jpeg': 'image/jpeg',
 173      'pdf': 'application/pdf',
 174      'retina': 'image/png',
 175      'svg': 'image/svg+xml',
 176  }
 177  
 178  @dec.skip_without('matplotlib')
 179  def test_set_matplotlib_formats():
 180      from matplotlib.figure import Figure
 181      formatters = get_ipython().display_formatter.formatters
 182      for formats in [
 183          ('png',),
 184          ('pdf', 'svg'),
 185          ('jpeg', 'retina', 'png'),
 186          (),
 187      ]:
 188          active_mimes = {_fmt_mime_map[fmt] for fmt in formats}
 189          with pytest.deprecated_call():
 190              display.set_matplotlib_formats(*formats)
 191          for mime, f in formatters.items():
 192              if mime in active_mimes:
 193                  assert Figure in f
 194              else:
 195                  assert Figure not in f
 196  
 197  
 198  @dec.skip_without("matplotlib")
 199  def test_set_matplotlib_formats_kwargs():
 200      from matplotlib.figure import Figure
 201      ip = get_ipython()
 202      cfg = _get_inline_config()
 203      cfg.print_figure_kwargs.update(dict(foo='bar'))
 204      kwargs = dict(dpi=150)
 205      with pytest.deprecated_call():
 206          display.set_matplotlib_formats("png", **kwargs)
 207      formatter = ip.display_formatter.formatters["image/png"]
 208      f = formatter.lookup_by_type(Figure)
 209      formatter_kwargs = f.keywords
 210      expected = kwargs
 211      expected["base64"] = True
 212      expected["fmt"] = "png"
 213      expected.update(cfg.print_figure_kwargs)
 214      assert formatter_kwargs == expected
 215  
 216  def test_display_available():
 217      """
 218      Test that display is available without import
 219  
 220      We don't really care if it's in builtin or anything else, but it should
 221      always be available.
 222      """
 223      ip = get_ipython()
 224      with AssertNotPrints('NameError'):
 225          ip.run_cell('display')
 226      try:
 227          ip.run_cell('del display')
 228      except NameError:
 229          pass # it's ok, it might be in builtins
 230      # even if deleted it should be back
 231      with AssertNotPrints('NameError'):
 232          ip.run_cell('display')
 233  
 234  def test_textdisplayobj_pretty_repr():
 235      p = display.Pretty("This is a simple test")
 236      assert repr(p) == "<IPython.core.display.Pretty object>"
 237      assert p.data == "This is a simple test"
 238  
 239      p._show_mem_addr = True
 240      assert repr(p) == object.__repr__(p)
 241  
 242  
 243  def test_displayobject_repr():
 244      h = display.HTML("<br />")
 245      assert repr(h) == "<IPython.core.display.HTML object>"
 246      h._show_mem_addr = True
 247      assert repr(h) == object.__repr__(h)
 248      h._show_mem_addr = False
 249      assert repr(h) == "<IPython.core.display.HTML object>"
 250  
 251      j = display.Javascript("")
 252      assert repr(j) == "<IPython.core.display.Javascript object>"
 253      j._show_mem_addr = True
 254      assert repr(j) == object.__repr__(j)
 255      j._show_mem_addr = False
 256      assert repr(j) == "<IPython.core.display.Javascript object>"
 257  
 258  @mock.patch('warnings.warn')
 259  def test_encourage_iframe_over_html(m_warn):
 260      display.HTML()
 261      m_warn.assert_not_called()
 262  
 263      display.HTML('<br />')
 264      m_warn.assert_not_called()
 265  
 266      display.HTML('<html><p>Lots of content here</p><iframe src="http://a.com"></iframe>')
 267      m_warn.assert_not_called()
 268  
 269      display.HTML('<iframe src="http://a.com"></iframe>')
 270      m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
 271  
 272      m_warn.reset_mock()
 273      display.HTML('<IFRAME SRC="http://a.com"></IFRAME>')
 274      m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
 275  
 276  def test_progress():
 277      p = display.ProgressBar(10)
 278      assert "0/10" in repr(p)
 279      p.html_width = "100%"
 280      p.progress = 5
 281      assert (
 282          p._repr_html_() == "<progress style='width:100%' max='10' value='5'></progress>"
 283      )
 284  
 285  
 286  def test_progress_iter():
 287      with capture_output(display=False) as captured:
 288          for i in display.ProgressBar(5):
 289              out = captured.stdout
 290              assert "{0}/5".format(i) in out
 291      out = captured.stdout
 292      assert "5/5" in out
 293  
 294  
 295  def test_json():
 296      d = {'a': 5}
 297      lis = [d]
 298      metadata = [
 299          {'expanded': False, 'root': 'root'},
 300          {'expanded': True,  'root': 'root'},
 301          {'expanded': False, 'root': 'custom'},
 302          {'expanded': True,  'root': 'custom'},
 303      ]
 304      json_objs = [
 305          display.JSON(d),
 306          display.JSON(d, expanded=True),
 307          display.JSON(d, root='custom'),
 308          display.JSON(d, expanded=True, root='custom'),
 309      ]
 310      for j, md in zip(json_objs, metadata):
 311          assert j._repr_json_() == (d, md)
 312  
 313      with warnings.catch_warnings(record=True) as w:
 314          warnings.simplefilter("always")
 315          j = display.JSON(json.dumps(d))
 316          assert len(w) == 1
 317          assert j._repr_json_() == (d, metadata[0])
 318  
 319      json_objs = [
 320          display.JSON(lis),
 321          display.JSON(lis, expanded=True),
 322          display.JSON(lis, root='custom'),
 323          display.JSON(lis, expanded=True, root='custom'),
 324      ]
 325      for j, md in zip(json_objs, metadata):
 326          assert j._repr_json_() == (lis, md)
 327  
 328      with warnings.catch_warnings(record=True) as w:
 329          warnings.simplefilter("always")
 330          j = display.JSON(json.dumps(lis))
 331          assert len(w) == 1
 332          assert j._repr_json_() == (lis, metadata[0])
 333  
 334  
 335  def test_video_embedding():
 336      """use a tempfile, with dummy-data, to ensure that video embedding doesn't crash"""
 337      v = display.Video("http://ignored")
 338      assert not v.embed
 339      html = v._repr_html_()
 340      assert 'src="data:' not in html
 341      assert 'src="http://ignored"' in html
 342  
 343      with pytest.raises(ValueError):
 344          v = display.Video(b'abc')
 345  
 346      with NamedFileInTemporaryDirectory('test.mp4') as f:
 347          f.write(b'abc')
 348          f.close()
 349  
 350          v = display.Video(f.name)
 351          assert not v.embed
 352          html = v._repr_html_()
 353          assert 'src="data:' not in html
 354  
 355          v = display.Video(f.name, embed=True)
 356          html = v._repr_html_()
 357          assert 'src="data:video/mp4;base64,YWJj"' in html
 358  
 359          v = display.Video(f.name, embed=True, mimetype='video/other')
 360          html = v._repr_html_()
 361          assert 'src="data:video/other;base64,YWJj"' in html
 362  
 363          v = display.Video(b'abc', embed=True, mimetype='video/mp4')
 364          html = v._repr_html_()
 365          assert 'src="data:video/mp4;base64,YWJj"' in html
 366  
 367          v = display.Video(u'YWJj', embed=True, mimetype='video/xyz')
 368          html = v._repr_html_()
 369          assert 'src="data:video/xyz;base64,YWJj"' in html
 370  
 371  def test_html_metadata():
 372      s = "<h1>Test</h1>"
 373      h = display.HTML(s, metadata={"isolated": True})
 374      assert h._repr_html_() == (s, {"isolated": True})
 375  
 376  
 377  def test_display_id():
 378      ip = get_ipython()
 379      with mock.patch.object(ip.display_pub, 'publish') as pub:
 380          handle = display.display('x')
 381          assert handle is None
 382          handle = display.display('y', display_id='secret')
 383          assert isinstance(handle, display.DisplayHandle)
 384          handle2 = display.display('z', display_id=True)
 385          assert isinstance(handle2, display.DisplayHandle)
 386      assert handle.display_id != handle2.display_id
 387  
 388      assert pub.call_count == 3
 389      args, kwargs = pub.call_args_list[0]
 390      assert args == ()
 391      assert kwargs == {
 392          'data': {
 393              'text/plain': repr('x')
 394          },
 395          'metadata': {},
 396      }
 397      args, kwargs = pub.call_args_list[1]
 398      assert args == ()
 399      assert kwargs == {
 400          'data': {
 401              'text/plain': repr('y')
 402          },
 403          'metadata': {},
 404          'transient': {
 405              'display_id': handle.display_id,
 406          },
 407      }
 408      args, kwargs = pub.call_args_list[2]
 409      assert args == ()
 410      assert kwargs == {
 411          'data': {
 412              'text/plain': repr('z')
 413          },
 414          'metadata': {},
 415          'transient': {
 416              'display_id': handle2.display_id,
 417          },
 418      }
 419  
 420  
 421  def test_update_display():
 422      ip = get_ipython()
 423      with mock.patch.object(ip.display_pub, 'publish') as pub:
 424          with pytest.raises(TypeError):
 425              display.update_display('x')
 426          display.update_display('x', display_id='1')
 427          display.update_display('y', display_id='2')
 428      args, kwargs = pub.call_args_list[0]
 429      assert args == ()
 430      assert kwargs == {
 431          'data': {
 432              'text/plain': repr('x')
 433          },
 434          'metadata': {},
 435          'transient': {
 436              'display_id': '1',
 437          },
 438          'update': True,
 439      }
 440      args, kwargs = pub.call_args_list[1]
 441      assert args == ()
 442      assert kwargs == {
 443          'data': {
 444              'text/plain': repr('y')
 445          },
 446          'metadata': {},
 447          'transient': {
 448              'display_id': '2',
 449          },
 450          'update': True,
 451      }
 452  
 453  
 454  def test_display_handle():
 455      ip = get_ipython()
 456      handle = display.DisplayHandle()
 457      assert isinstance(handle.display_id, str)
 458      handle = display.DisplayHandle("my-id")
 459      assert handle.display_id == "my-id"
 460      with mock.patch.object(ip.display_pub, "publish") as pub:
 461          handle.display("x")
 462          handle.update("y")
 463  
 464      args, kwargs = pub.call_args_list[0]
 465      assert args == ()
 466      assert kwargs == {
 467          'data': {
 468              'text/plain': repr('x')
 469          },
 470          'metadata': {},
 471          'transient': {
 472              'display_id': handle.display_id,
 473          }
 474      }
 475      args, kwargs = pub.call_args_list[1]
 476      assert args == ()
 477      assert kwargs == {
 478          'data': {
 479              'text/plain': repr('y')
 480          },
 481          'metadata': {},
 482          'transient': {
 483              'display_id': handle.display_id,
 484          },
 485          'update': True,
 486      }
 487  
 488  
 489  def test_image_alt_tag():
 490      """Simple test for display.Image(args, alt=x,)"""
 491      thisurl = "http://example.com/image.png"
 492      img = display.Image(url=thisurl, alt="an image")
 493      assert '<img src="%s" alt="an image"/>' % (thisurl) == img._repr_html_()
 494      img = display.Image(url=thisurl, unconfined=True, alt="an image")
 495      assert (
 496          '<img src="%s" class="unconfined" alt="an image"/>' % (thisurl)
 497          == img._repr_html_()
 498      )
 499      img = display.Image(url=thisurl, alt='>"& <')
 500      assert '<img src="%s" alt="&gt;&quot;&amp; &lt;"/>' % (thisurl) == img._repr_html_()
 501  
 502      img = display.Image(url=thisurl, metadata={"alt": "an image"})
 503      assert img.alt == "an image"
 504      here = os.path.dirname(__file__)
 505      img = display.Image(os.path.join(here, "2x2.png"), alt="an image")
 506      assert img.alt == "an image"
 507      _, md = img._repr_png_()
 508      assert md["alt"] == "an image"
 509  
 510  
 511  def test_image_bad_filename_raises_proper_exception():
 512      with pytest.raises(FileNotFoundError):
 513          display.Image("/this/file/does/not/exist/")._repr_png_()
 514