##// END OF EJS Templates
remove python 2.x specific urllib2's functions
Srinivas Reddy Thatiparthy -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,1135 +1,1133 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Top-level display functions for displaying object in different formats."""
2 """Top-level display functions for displaying object in different formats."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7
7
8 try:
8 try:
9 from base64 import encodebytes as base64_encode
9 from base64 import encodebytes as base64_encode
10 except ImportError:
10 except ImportError:
11 from base64 import encodestring as base64_encode
11 from base64 import encodestring as base64_encode
12
12
13 from binascii import b2a_hex
13 from binascii import b2a_hex
14 import json
14 import json
15 import mimetypes
15 import mimetypes
16 import os
16 import os
17 import struct
17 import struct
18 import sys
18 import sys
19 import warnings
19 import warnings
20
20
21 from IPython.utils.py3compat import cast_bytes_py2, cast_unicode
21 from IPython.utils.py3compat import cast_bytes_py2, cast_unicode
22 from IPython.testing.skipdoctest import skip_doctest
22 from IPython.testing.skipdoctest import skip_doctest
23
23
24 __all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
24 __all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
25 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
25 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
26 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
26 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
27 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'JSON', 'Javascript',
27 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'JSON', 'Javascript',
28 'Image', 'clear_output', 'set_matplotlib_formats', 'set_matplotlib_close',
28 'Image', 'clear_output', 'set_matplotlib_formats', 'set_matplotlib_close',
29 'publish_display_data', 'update_display', 'DisplayHandle']
29 'publish_display_data', 'update_display', 'DisplayHandle']
30
30
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32 # utility functions
32 # utility functions
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34
34
35 def _safe_exists(path):
35 def _safe_exists(path):
36 """Check path, but don't let exceptions raise"""
36 """Check path, but don't let exceptions raise"""
37 try:
37 try:
38 return os.path.exists(path)
38 return os.path.exists(path)
39 except Exception:
39 except Exception:
40 return False
40 return False
41
41
42 def _merge(d1, d2):
42 def _merge(d1, d2):
43 """Like update, but merges sub-dicts instead of clobbering at the top level.
43 """Like update, but merges sub-dicts instead of clobbering at the top level.
44
44
45 Updates d1 in-place
45 Updates d1 in-place
46 """
46 """
47
47
48 if not isinstance(d2, dict) or not isinstance(d1, dict):
48 if not isinstance(d2, dict) or not isinstance(d1, dict):
49 return d2
49 return d2
50 for key, value in d2.items():
50 for key, value in d2.items():
51 d1[key] = _merge(d1.get(key), value)
51 d1[key] = _merge(d1.get(key), value)
52 return d1
52 return d1
53
53
54 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
54 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
55 """internal implementation of all display_foo methods
55 """internal implementation of all display_foo methods
56
56
57 Parameters
57 Parameters
58 ----------
58 ----------
59 mimetype : str
59 mimetype : str
60 The mimetype to be published (e.g. 'image/png')
60 The mimetype to be published (e.g. 'image/png')
61 objs : tuple of objects
61 objs : tuple of objects
62 The Python objects to display, or if raw=True raw text data to
62 The Python objects to display, or if raw=True raw text data to
63 display.
63 display.
64 raw : bool
64 raw : bool
65 Are the data objects raw data or Python objects that need to be
65 Are the data objects raw data or Python objects that need to be
66 formatted before display? [default: False]
66 formatted before display? [default: False]
67 metadata : dict (optional)
67 metadata : dict (optional)
68 Metadata to be associated with the specific mimetype output.
68 Metadata to be associated with the specific mimetype output.
69 """
69 """
70 if metadata:
70 if metadata:
71 metadata = {mimetype: metadata}
71 metadata = {mimetype: metadata}
72 if raw:
72 if raw:
73 # turn list of pngdata into list of { 'image/png': pngdata }
73 # turn list of pngdata into list of { 'image/png': pngdata }
74 objs = [ {mimetype: obj} for obj in objs ]
74 objs = [ {mimetype: obj} for obj in objs ]
75 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
75 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
76
76
77 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
78 # Main functions
78 # Main functions
79 #-----------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
80
80
81 # use * to indicate transient is keyword-only
81 # use * to indicate transient is keyword-only
82 def publish_display_data(data, metadata=None, source=None, *, transient=None, **kwargs):
82 def publish_display_data(data, metadata=None, source=None, *, transient=None, **kwargs):
83 """Publish data and metadata to all frontends.
83 """Publish data and metadata to all frontends.
84
84
85 See the ``display_data`` message in the messaging documentation for
85 See the ``display_data`` message in the messaging documentation for
86 more details about this message type.
86 more details about this message type.
87
87
88 The following MIME types are currently implemented:
88 The following MIME types are currently implemented:
89
89
90 * text/plain
90 * text/plain
91 * text/html
91 * text/html
92 * text/markdown
92 * text/markdown
93 * text/latex
93 * text/latex
94 * application/json
94 * application/json
95 * application/javascript
95 * application/javascript
96 * image/png
96 * image/png
97 * image/jpeg
97 * image/jpeg
98 * image/svg+xml
98 * image/svg+xml
99
99
100 Parameters
100 Parameters
101 ----------
101 ----------
102 data : dict
102 data : dict
103 A dictionary having keys that are valid MIME types (like
103 A dictionary having keys that are valid MIME types (like
104 'text/plain' or 'image/svg+xml') and values that are the data for
104 'text/plain' or 'image/svg+xml') and values that are the data for
105 that MIME type. The data itself must be a JSON'able data
105 that MIME type. The data itself must be a JSON'able data
106 structure. Minimally all data should have the 'text/plain' data,
106 structure. Minimally all data should have the 'text/plain' data,
107 which can be displayed by all frontends. If more than the plain
107 which can be displayed by all frontends. If more than the plain
108 text is given, it is up to the frontend to decide which
108 text is given, it is up to the frontend to decide which
109 representation to use.
109 representation to use.
110 metadata : dict
110 metadata : dict
111 A dictionary for metadata related to the data. This can contain
111 A dictionary for metadata related to the data. This can contain
112 arbitrary key, value pairs that frontends can use to interpret
112 arbitrary key, value pairs that frontends can use to interpret
113 the data. mime-type keys matching those in data can be used
113 the data. mime-type keys matching those in data can be used
114 to specify metadata about particular representations.
114 to specify metadata about particular representations.
115 source : str, deprecated
115 source : str, deprecated
116 Unused.
116 Unused.
117 transient : dict, keyword-only
117 transient : dict, keyword-only
118 A dictionary of transient data, such as display_id.
118 A dictionary of transient data, such as display_id.
119 """
119 """
120 from IPython.core.interactiveshell import InteractiveShell
120 from IPython.core.interactiveshell import InteractiveShell
121
121
122 display_pub = InteractiveShell.instance().display_pub
122 display_pub = InteractiveShell.instance().display_pub
123
123
124 # only pass transient if supplied,
124 # only pass transient if supplied,
125 # to avoid errors with older ipykernel.
125 # to avoid errors with older ipykernel.
126 # TODO: We could check for ipykernel version and provide a detailed upgrade message.
126 # TODO: We could check for ipykernel version and provide a detailed upgrade message.
127 if transient:
127 if transient:
128 kwargs['transient'] = transient
128 kwargs['transient'] = transient
129
129
130 display_pub.publish(
130 display_pub.publish(
131 data=data,
131 data=data,
132 metadata=metadata,
132 metadata=metadata,
133 **kwargs
133 **kwargs
134 )
134 )
135
135
136
136
137 def _new_id():
137 def _new_id():
138 """Generate a new random text id with urandom"""
138 """Generate a new random text id with urandom"""
139 return b2a_hex(os.urandom(16)).decode('ascii')
139 return b2a_hex(os.urandom(16)).decode('ascii')
140
140
141
141
142 def display(*objs, include=None, exclude=None, metadata=None, transient=None, display_id=None, **kwargs):
142 def display(*objs, include=None, exclude=None, metadata=None, transient=None, display_id=None, **kwargs):
143 """Display a Python object in all frontends.
143 """Display a Python object in all frontends.
144
144
145 By default all representations will be computed and sent to the frontends.
145 By default all representations will be computed and sent to the frontends.
146 Frontends can decide which representation is used and how.
146 Frontends can decide which representation is used and how.
147
147
148 Parameters
148 Parameters
149 ----------
149 ----------
150 objs : tuple of objects
150 objs : tuple of objects
151 The Python objects to display.
151 The Python objects to display.
152 raw : bool, optional
152 raw : bool, optional
153 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
153 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
154 or Python objects that need to be formatted before display? [default: False]
154 or Python objects that need to be formatted before display? [default: False]
155 include : list or tuple, optional
155 include : list or tuple, optional
156 A list of format type strings (MIME types) to include in the
156 A list of format type strings (MIME types) to include in the
157 format data dict. If this is set *only* the format types included
157 format data dict. If this is set *only* the format types included
158 in this list will be computed.
158 in this list will be computed.
159 exclude : list or tuple, optional
159 exclude : list or tuple, optional
160 A list of format type strings (MIME types) to exclude in the format
160 A list of format type strings (MIME types) to exclude in the format
161 data dict. If this is set all format types will be computed,
161 data dict. If this is set all format types will be computed,
162 except for those included in this argument.
162 except for those included in this argument.
163 metadata : dict, optional
163 metadata : dict, optional
164 A dictionary of metadata to associate with the output.
164 A dictionary of metadata to associate with the output.
165 mime-type keys in this dictionary will be associated with the individual
165 mime-type keys in this dictionary will be associated with the individual
166 representation formats, if they exist.
166 representation formats, if they exist.
167 transient : dict, optional
167 transient : dict, optional
168 A dictionary of transient data to associate with the output.
168 A dictionary of transient data to associate with the output.
169 Data in this dict should not be persisted to files (e.g. notebooks).
169 Data in this dict should not be persisted to files (e.g. notebooks).
170 display_id : str, optional
170 display_id : str, optional
171 Set an id for the display.
171 Set an id for the display.
172 This id can be used for updating this display area later via update_display.
172 This id can be used for updating this display area later via update_display.
173 If given as True, generate a new display_id
173 If given as True, generate a new display_id
174 kwargs: additional keyword-args, optional
174 kwargs: additional keyword-args, optional
175 Additional keyword-arguments are passed through to the display publisher.
175 Additional keyword-arguments are passed through to the display publisher.
176
176
177 Returns
177 Returns
178 -------
178 -------
179
179
180 handle: DisplayHandle
180 handle: DisplayHandle
181 Returns a handle on updatable displays, if display_id is given.
181 Returns a handle on updatable displays, if display_id is given.
182 Returns None if no display_id is given (default).
182 Returns None if no display_id is given (default).
183 """
183 """
184 raw = kwargs.pop('raw', False)
184 raw = kwargs.pop('raw', False)
185 if transient is None:
185 if transient is None:
186 transient = {}
186 transient = {}
187 if display_id:
187 if display_id:
188 if display_id == True:
188 if display_id == True:
189 display_id = _new_id()
189 display_id = _new_id()
190 transient['display_id'] = display_id
190 transient['display_id'] = display_id
191 if kwargs.get('update') and 'display_id' not in transient:
191 if kwargs.get('update') and 'display_id' not in transient:
192 raise TypeError('display_id required for update_display')
192 raise TypeError('display_id required for update_display')
193 if transient:
193 if transient:
194 kwargs['transient'] = transient
194 kwargs['transient'] = transient
195
195
196 from IPython.core.interactiveshell import InteractiveShell
196 from IPython.core.interactiveshell import InteractiveShell
197
197
198 if not raw:
198 if not raw:
199 format = InteractiveShell.instance().display_formatter.format
199 format = InteractiveShell.instance().display_formatter.format
200
200
201 for obj in objs:
201 for obj in objs:
202 if raw:
202 if raw:
203 publish_display_data(data=obj, metadata=metadata, **kwargs)
203 publish_display_data(data=obj, metadata=metadata, **kwargs)
204 else:
204 else:
205 format_dict, md_dict = format(obj, include=include, exclude=exclude)
205 format_dict, md_dict = format(obj, include=include, exclude=exclude)
206 if not format_dict:
206 if not format_dict:
207 # nothing to display (e.g. _ipython_display_ took over)
207 # nothing to display (e.g. _ipython_display_ took over)
208 continue
208 continue
209 if metadata:
209 if metadata:
210 # kwarg-specified metadata gets precedence
210 # kwarg-specified metadata gets precedence
211 _merge(md_dict, metadata)
211 _merge(md_dict, metadata)
212 publish_display_data(data=format_dict, metadata=md_dict, **kwargs)
212 publish_display_data(data=format_dict, metadata=md_dict, **kwargs)
213 if display_id:
213 if display_id:
214 return DisplayHandle(display_id)
214 return DisplayHandle(display_id)
215
215
216
216
217 # use * for keyword-only display_id arg
217 # use * for keyword-only display_id arg
218 def update_display(obj, *, display_id, **kwargs):
218 def update_display(obj, *, display_id, **kwargs):
219 """Update an existing display by id
219 """Update an existing display by id
220
220
221 Parameters
221 Parameters
222 ----------
222 ----------
223
223
224 obj:
224 obj:
225 The object with which to update the display
225 The object with which to update the display
226 display_id: keyword-only
226 display_id: keyword-only
227 The id of the display to update
227 The id of the display to update
228 """
228 """
229 kwargs['update'] = True
229 kwargs['update'] = True
230 display(obj, display_id=display_id, **kwargs)
230 display(obj, display_id=display_id, **kwargs)
231
231
232
232
233 class DisplayHandle(object):
233 class DisplayHandle(object):
234 """A handle on an updatable display
234 """A handle on an updatable display
235
235
236 Call .update(obj) to display a new object.
236 Call .update(obj) to display a new object.
237
237
238 Call .display(obj) to add a new instance of this display,
238 Call .display(obj) to add a new instance of this display,
239 and update existing instances.
239 and update existing instances.
240 """
240 """
241
241
242 def __init__(self, display_id=None):
242 def __init__(self, display_id=None):
243 if display_id is None:
243 if display_id is None:
244 display_id = _new_id()
244 display_id = _new_id()
245 self.display_id = display_id
245 self.display_id = display_id
246
246
247 def __repr__(self):
247 def __repr__(self):
248 return "<%s display_id=%s>" % (self.__class__.__name__, self.display_id)
248 return "<%s display_id=%s>" % (self.__class__.__name__, self.display_id)
249
249
250 def display(self, obj, **kwargs):
250 def display(self, obj, **kwargs):
251 """Make a new display with my id, updating existing instances.
251 """Make a new display with my id, updating existing instances.
252
252
253 Parameters
253 Parameters
254 ----------
254 ----------
255
255
256 obj:
256 obj:
257 object to display
257 object to display
258 **kwargs:
258 **kwargs:
259 additional keyword arguments passed to display
259 additional keyword arguments passed to display
260 """
260 """
261 display(obj, display_id=self.display_id, **kwargs)
261 display(obj, display_id=self.display_id, **kwargs)
262
262
263 def update(self, obj, **kwargs):
263 def update(self, obj, **kwargs):
264 """Update existing displays with my id
264 """Update existing displays with my id
265
265
266 Parameters
266 Parameters
267 ----------
267 ----------
268
268
269 obj:
269 obj:
270 object to display
270 object to display
271 **kwargs:
271 **kwargs:
272 additional keyword arguments passed to update_display
272 additional keyword arguments passed to update_display
273 """
273 """
274 update_display(obj, display_id=self.display_id, **kwargs)
274 update_display(obj, display_id=self.display_id, **kwargs)
275
275
276
276
277 def display_pretty(*objs, **kwargs):
277 def display_pretty(*objs, **kwargs):
278 """Display the pretty (default) representation of an object.
278 """Display the pretty (default) representation of an object.
279
279
280 Parameters
280 Parameters
281 ----------
281 ----------
282 objs : tuple of objects
282 objs : tuple of objects
283 The Python objects to display, or if raw=True raw text data to
283 The Python objects to display, or if raw=True raw text data to
284 display.
284 display.
285 raw : bool
285 raw : bool
286 Are the data objects raw data or Python objects that need to be
286 Are the data objects raw data or Python objects that need to be
287 formatted before display? [default: False]
287 formatted before display? [default: False]
288 metadata : dict (optional)
288 metadata : dict (optional)
289 Metadata to be associated with the specific mimetype output.
289 Metadata to be associated with the specific mimetype output.
290 """
290 """
291 _display_mimetype('text/plain', objs, **kwargs)
291 _display_mimetype('text/plain', objs, **kwargs)
292
292
293
293
294 def display_html(*objs, **kwargs):
294 def display_html(*objs, **kwargs):
295 """Display the HTML representation of an object.
295 """Display the HTML representation of an object.
296
296
297 Note: If raw=False and the object does not have a HTML
297 Note: If raw=False and the object does not have a HTML
298 representation, no HTML will be shown.
298 representation, no HTML will be shown.
299
299
300 Parameters
300 Parameters
301 ----------
301 ----------
302 objs : tuple of objects
302 objs : tuple of objects
303 The Python objects to display, or if raw=True raw HTML data to
303 The Python objects to display, or if raw=True raw HTML data to
304 display.
304 display.
305 raw : bool
305 raw : bool
306 Are the data objects raw data or Python objects that need to be
306 Are the data objects raw data or Python objects that need to be
307 formatted before display? [default: False]
307 formatted before display? [default: False]
308 metadata : dict (optional)
308 metadata : dict (optional)
309 Metadata to be associated with the specific mimetype output.
309 Metadata to be associated with the specific mimetype output.
310 """
310 """
311 _display_mimetype('text/html', objs, **kwargs)
311 _display_mimetype('text/html', objs, **kwargs)
312
312
313
313
314 def display_markdown(*objs, **kwargs):
314 def display_markdown(*objs, **kwargs):
315 """Displays the Markdown representation of an object.
315 """Displays the Markdown representation of an object.
316
316
317 Parameters
317 Parameters
318 ----------
318 ----------
319 objs : tuple of objects
319 objs : tuple of objects
320 The Python objects to display, or if raw=True raw markdown data to
320 The Python objects to display, or if raw=True raw markdown data to
321 display.
321 display.
322 raw : bool
322 raw : bool
323 Are the data objects raw data or Python objects that need to be
323 Are the data objects raw data or Python objects that need to be
324 formatted before display? [default: False]
324 formatted before display? [default: False]
325 metadata : dict (optional)
325 metadata : dict (optional)
326 Metadata to be associated with the specific mimetype output.
326 Metadata to be associated with the specific mimetype output.
327 """
327 """
328
328
329 _display_mimetype('text/markdown', objs, **kwargs)
329 _display_mimetype('text/markdown', objs, **kwargs)
330
330
331
331
332 def display_svg(*objs, **kwargs):
332 def display_svg(*objs, **kwargs):
333 """Display the SVG representation of an object.
333 """Display the SVG representation of an object.
334
334
335 Parameters
335 Parameters
336 ----------
336 ----------
337 objs : tuple of objects
337 objs : tuple of objects
338 The Python objects to display, or if raw=True raw svg data to
338 The Python objects to display, or if raw=True raw svg data to
339 display.
339 display.
340 raw : bool
340 raw : bool
341 Are the data objects raw data or Python objects that need to be
341 Are the data objects raw data or Python objects that need to be
342 formatted before display? [default: False]
342 formatted before display? [default: False]
343 metadata : dict (optional)
343 metadata : dict (optional)
344 Metadata to be associated with the specific mimetype output.
344 Metadata to be associated with the specific mimetype output.
345 """
345 """
346 _display_mimetype('image/svg+xml', objs, **kwargs)
346 _display_mimetype('image/svg+xml', objs, **kwargs)
347
347
348
348
349 def display_png(*objs, **kwargs):
349 def display_png(*objs, **kwargs):
350 """Display the PNG representation of an object.
350 """Display the PNG representation of an object.
351
351
352 Parameters
352 Parameters
353 ----------
353 ----------
354 objs : tuple of objects
354 objs : tuple of objects
355 The Python objects to display, or if raw=True raw png data to
355 The Python objects to display, or if raw=True raw png data to
356 display.
356 display.
357 raw : bool
357 raw : bool
358 Are the data objects raw data or Python objects that need to be
358 Are the data objects raw data or Python objects that need to be
359 formatted before display? [default: False]
359 formatted before display? [default: False]
360 metadata : dict (optional)
360 metadata : dict (optional)
361 Metadata to be associated with the specific mimetype output.
361 Metadata to be associated with the specific mimetype output.
362 """
362 """
363 _display_mimetype('image/png', objs, **kwargs)
363 _display_mimetype('image/png', objs, **kwargs)
364
364
365
365
366 def display_jpeg(*objs, **kwargs):
366 def display_jpeg(*objs, **kwargs):
367 """Display the JPEG representation of an object.
367 """Display the JPEG representation of an object.
368
368
369 Parameters
369 Parameters
370 ----------
370 ----------
371 objs : tuple of objects
371 objs : tuple of objects
372 The Python objects to display, or if raw=True raw JPEG data to
372 The Python objects to display, or if raw=True raw JPEG data to
373 display.
373 display.
374 raw : bool
374 raw : bool
375 Are the data objects raw data or Python objects that need to be
375 Are the data objects raw data or Python objects that need to be
376 formatted before display? [default: False]
376 formatted before display? [default: False]
377 metadata : dict (optional)
377 metadata : dict (optional)
378 Metadata to be associated with the specific mimetype output.
378 Metadata to be associated with the specific mimetype output.
379 """
379 """
380 _display_mimetype('image/jpeg', objs, **kwargs)
380 _display_mimetype('image/jpeg', objs, **kwargs)
381
381
382
382
383 def display_latex(*objs, **kwargs):
383 def display_latex(*objs, **kwargs):
384 """Display the LaTeX representation of an object.
384 """Display the LaTeX representation of an object.
385
385
386 Parameters
386 Parameters
387 ----------
387 ----------
388 objs : tuple of objects
388 objs : tuple of objects
389 The Python objects to display, or if raw=True raw latex data to
389 The Python objects to display, or if raw=True raw latex data to
390 display.
390 display.
391 raw : bool
391 raw : bool
392 Are the data objects raw data or Python objects that need to be
392 Are the data objects raw data or Python objects that need to be
393 formatted before display? [default: False]
393 formatted before display? [default: False]
394 metadata : dict (optional)
394 metadata : dict (optional)
395 Metadata to be associated with the specific mimetype output.
395 Metadata to be associated with the specific mimetype output.
396 """
396 """
397 _display_mimetype('text/latex', objs, **kwargs)
397 _display_mimetype('text/latex', objs, **kwargs)
398
398
399
399
400 def display_json(*objs, **kwargs):
400 def display_json(*objs, **kwargs):
401 """Display the JSON representation of an object.
401 """Display the JSON representation of an object.
402
402
403 Note that not many frontends support displaying JSON.
403 Note that not many frontends support displaying JSON.
404
404
405 Parameters
405 Parameters
406 ----------
406 ----------
407 objs : tuple of objects
407 objs : tuple of objects
408 The Python objects to display, or if raw=True raw json data to
408 The Python objects to display, or if raw=True raw json data to
409 display.
409 display.
410 raw : bool
410 raw : bool
411 Are the data objects raw data or Python objects that need to be
411 Are the data objects raw data or Python objects that need to be
412 formatted before display? [default: False]
412 formatted before display? [default: False]
413 metadata : dict (optional)
413 metadata : dict (optional)
414 Metadata to be associated with the specific mimetype output.
414 Metadata to be associated with the specific mimetype output.
415 """
415 """
416 _display_mimetype('application/json', objs, **kwargs)
416 _display_mimetype('application/json', objs, **kwargs)
417
417
418
418
419 def display_javascript(*objs, **kwargs):
419 def display_javascript(*objs, **kwargs):
420 """Display the Javascript representation of an object.
420 """Display the Javascript representation of an object.
421
421
422 Parameters
422 Parameters
423 ----------
423 ----------
424 objs : tuple of objects
424 objs : tuple of objects
425 The Python objects to display, or if raw=True raw javascript data to
425 The Python objects to display, or if raw=True raw javascript data to
426 display.
426 display.
427 raw : bool
427 raw : bool
428 Are the data objects raw data or Python objects that need to be
428 Are the data objects raw data or Python objects that need to be
429 formatted before display? [default: False]
429 formatted before display? [default: False]
430 metadata : dict (optional)
430 metadata : dict (optional)
431 Metadata to be associated with the specific mimetype output.
431 Metadata to be associated with the specific mimetype output.
432 """
432 """
433 _display_mimetype('application/javascript', objs, **kwargs)
433 _display_mimetype('application/javascript', objs, **kwargs)
434
434
435
435
436 def display_pdf(*objs, **kwargs):
436 def display_pdf(*objs, **kwargs):
437 """Display the PDF representation of an object.
437 """Display the PDF representation of an object.
438
438
439 Parameters
439 Parameters
440 ----------
440 ----------
441 objs : tuple of objects
441 objs : tuple of objects
442 The Python objects to display, or if raw=True raw javascript data to
442 The Python objects to display, or if raw=True raw javascript data to
443 display.
443 display.
444 raw : bool
444 raw : bool
445 Are the data objects raw data or Python objects that need to be
445 Are the data objects raw data or Python objects that need to be
446 formatted before display? [default: False]
446 formatted before display? [default: False]
447 metadata : dict (optional)
447 metadata : dict (optional)
448 Metadata to be associated with the specific mimetype output.
448 Metadata to be associated with the specific mimetype output.
449 """
449 """
450 _display_mimetype('application/pdf', objs, **kwargs)
450 _display_mimetype('application/pdf', objs, **kwargs)
451
451
452
452
453 #-----------------------------------------------------------------------------
453 #-----------------------------------------------------------------------------
454 # Smart classes
454 # Smart classes
455 #-----------------------------------------------------------------------------
455 #-----------------------------------------------------------------------------
456
456
457
457
458 class DisplayObject(object):
458 class DisplayObject(object):
459 """An object that wraps data to be displayed."""
459 """An object that wraps data to be displayed."""
460
460
461 _read_flags = 'r'
461 _read_flags = 'r'
462 _show_mem_addr = False
462 _show_mem_addr = False
463
463
464 def __init__(self, data=None, url=None, filename=None):
464 def __init__(self, data=None, url=None, filename=None):
465 """Create a display object given raw data.
465 """Create a display object given raw data.
466
466
467 When this object is returned by an expression or passed to the
467 When this object is returned by an expression or passed to the
468 display function, it will result in the data being displayed
468 display function, it will result in the data being displayed
469 in the frontend. The MIME type of the data should match the
469 in the frontend. The MIME type of the data should match the
470 subclasses used, so the Png subclass should be used for 'image/png'
470 subclasses used, so the Png subclass should be used for 'image/png'
471 data. If the data is a URL, the data will first be downloaded
471 data. If the data is a URL, the data will first be downloaded
472 and then displayed. If
472 and then displayed. If
473
473
474 Parameters
474 Parameters
475 ----------
475 ----------
476 data : unicode, str or bytes
476 data : unicode, str or bytes
477 The raw data or a URL or file to load the data from
477 The raw data or a URL or file to load the data from
478 url : unicode
478 url : unicode
479 A URL to download the data from.
479 A URL to download the data from.
480 filename : unicode
480 filename : unicode
481 Path to a local file to load the data from.
481 Path to a local file to load the data from.
482 """
482 """
483 if data is not None and isinstance(data, str):
483 if data is not None and isinstance(data, str):
484 if data.startswith('http') and url is None:
484 if data.startswith('http') and url is None:
485 url = data
485 url = data
486 filename = None
486 filename = None
487 data = None
487 data = None
488 elif _safe_exists(data) and filename is None:
488 elif _safe_exists(data) and filename is None:
489 url = None
489 url = None
490 filename = data
490 filename = data
491 data = None
491 data = None
492
492
493 self.data = data
493 self.data = data
494 self.url = url
494 self.url = url
495 self.filename = filename
495 self.filename = filename
496
496
497 self.reload()
497 self.reload()
498 self._check_data()
498 self._check_data()
499
499
500 def __repr__(self):
500 def __repr__(self):
501 if not self._show_mem_addr:
501 if not self._show_mem_addr:
502 cls = self.__class__
502 cls = self.__class__
503 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
503 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
504 else:
504 else:
505 r = super(DisplayObject, self).__repr__()
505 r = super(DisplayObject, self).__repr__()
506 return r
506 return r
507
507
508 def _check_data(self):
508 def _check_data(self):
509 """Override in subclasses if there's something to check."""
509 """Override in subclasses if there's something to check."""
510 pass
510 pass
511
511
512 def reload(self):
512 def reload(self):
513 """Reload the raw data from file or URL."""
513 """Reload the raw data from file or URL."""
514 if self.filename is not None:
514 if self.filename is not None:
515 with open(self.filename, self._read_flags) as f:
515 with open(self.filename, self._read_flags) as f:
516 self.data = f.read()
516 self.data = f.read()
517 elif self.url is not None:
517 elif self.url is not None:
518 try:
518 try:
519 try:
519 # Deferred import
520 from urllib.request import urlopen # Py3
520 from urllib.request import urlopen
521 except ImportError:
522 from urllib2 import urlopen
523 response = urlopen(self.url)
521 response = urlopen(self.url)
524 self.data = response.read()
522 self.data = response.read()
525 # extract encoding from header, if there is one:
523 # extract encoding from header, if there is one:
526 encoding = None
524 encoding = None
527 for sub in response.headers['content-type'].split(';'):
525 for sub in response.headers['content-type'].split(';'):
528 sub = sub.strip()
526 sub = sub.strip()
529 if sub.startswith('charset'):
527 if sub.startswith('charset'):
530 encoding = sub.split('=')[-1].strip()
528 encoding = sub.split('=')[-1].strip()
531 break
529 break
532 # decode data, if an encoding was specified
530 # decode data, if an encoding was specified
533 if encoding:
531 if encoding:
534 self.data = self.data.decode(encoding, 'replace')
532 self.data = self.data.decode(encoding, 'replace')
535 except:
533 except:
536 self.data = None
534 self.data = None
537
535
538 class TextDisplayObject(DisplayObject):
536 class TextDisplayObject(DisplayObject):
539 """Validate that display data is text"""
537 """Validate that display data is text"""
540 def _check_data(self):
538 def _check_data(self):
541 if self.data is not None and not isinstance(self.data, str):
539 if self.data is not None and not isinstance(self.data, str):
542 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
540 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
543
541
544 class Pretty(TextDisplayObject):
542 class Pretty(TextDisplayObject):
545
543
546 def _repr_pretty_(self):
544 def _repr_pretty_(self):
547 return self.data
545 return self.data
548
546
549
547
550 class HTML(TextDisplayObject):
548 class HTML(TextDisplayObject):
551
549
552 def _repr_html_(self):
550 def _repr_html_(self):
553 return self.data
551 return self.data
554
552
555 def __html__(self):
553 def __html__(self):
556 """
554 """
557 This method exists to inform other HTML-using modules (e.g. Markupsafe,
555 This method exists to inform other HTML-using modules (e.g. Markupsafe,
558 htmltag, etc) that this object is HTML and does not need things like
556 htmltag, etc) that this object is HTML and does not need things like
559 special characters (<>&) escaped.
557 special characters (<>&) escaped.
560 """
558 """
561 return self._repr_html_()
559 return self._repr_html_()
562
560
563
561
564 class Markdown(TextDisplayObject):
562 class Markdown(TextDisplayObject):
565
563
566 def _repr_markdown_(self):
564 def _repr_markdown_(self):
567 return self.data
565 return self.data
568
566
569
567
570 class Math(TextDisplayObject):
568 class Math(TextDisplayObject):
571
569
572 def _repr_latex_(self):
570 def _repr_latex_(self):
573 s = self.data.strip('$')
571 s = self.data.strip('$')
574 return "$$%s$$" % s
572 return "$$%s$$" % s
575
573
576
574
577 class Latex(TextDisplayObject):
575 class Latex(TextDisplayObject):
578
576
579 def _repr_latex_(self):
577 def _repr_latex_(self):
580 return self.data
578 return self.data
581
579
582
580
583 class SVG(DisplayObject):
581 class SVG(DisplayObject):
584
582
585 _read_flags = 'rb'
583 _read_flags = 'rb'
586 # wrap data in a property, which extracts the <svg> tag, discarding
584 # wrap data in a property, which extracts the <svg> tag, discarding
587 # document headers
585 # document headers
588 _data = None
586 _data = None
589
587
590 @property
588 @property
591 def data(self):
589 def data(self):
592 return self._data
590 return self._data
593
591
594 @data.setter
592 @data.setter
595 def data(self, svg):
593 def data(self, svg):
596 if svg is None:
594 if svg is None:
597 self._data = None
595 self._data = None
598 return
596 return
599 # parse into dom object
597 # parse into dom object
600 from xml.dom import minidom
598 from xml.dom import minidom
601 svg = cast_bytes_py2(svg)
599 svg = cast_bytes_py2(svg)
602 x = minidom.parseString(svg)
600 x = minidom.parseString(svg)
603 # get svg tag (should be 1)
601 # get svg tag (should be 1)
604 found_svg = x.getElementsByTagName('svg')
602 found_svg = x.getElementsByTagName('svg')
605 if found_svg:
603 if found_svg:
606 svg = found_svg[0].toxml()
604 svg = found_svg[0].toxml()
607 else:
605 else:
608 # fallback on the input, trust the user
606 # fallback on the input, trust the user
609 # but this is probably an error.
607 # but this is probably an error.
610 pass
608 pass
611 svg = cast_unicode(svg)
609 svg = cast_unicode(svg)
612 self._data = svg
610 self._data = svg
613
611
614 def _repr_svg_(self):
612 def _repr_svg_(self):
615 return self.data
613 return self.data
616
614
617
615
618 class JSON(DisplayObject):
616 class JSON(DisplayObject):
619 """JSON expects a JSON-able dict or list
617 """JSON expects a JSON-able dict or list
620
618
621 not an already-serialized JSON string.
619 not an already-serialized JSON string.
622
620
623 Scalar types (None, number, string) are not allowed, only dict or list containers.
621 Scalar types (None, number, string) are not allowed, only dict or list containers.
624 """
622 """
625 # wrap data in a property, which warns about passing already-serialized JSON
623 # wrap data in a property, which warns about passing already-serialized JSON
626 _data = None
624 _data = None
627 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None):
625 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None):
628 """Create a JSON display object given raw data.
626 """Create a JSON display object given raw data.
629
627
630 Parameters
628 Parameters
631 ----------
629 ----------
632 data : dict or list
630 data : dict or list
633 JSON data to display. Not an already-serialized JSON string.
631 JSON data to display. Not an already-serialized JSON string.
634 Scalar types (None, number, string) are not allowed, only dict
632 Scalar types (None, number, string) are not allowed, only dict
635 or list containers.
633 or list containers.
636 url : unicode
634 url : unicode
637 A URL to download the data from.
635 A URL to download the data from.
638 filename : unicode
636 filename : unicode
639 Path to a local file to load the data from.
637 Path to a local file to load the data from.
640 expanded : boolean
638 expanded : boolean
641 Metadata to control whether a JSON display component is expanded.
639 Metadata to control whether a JSON display component is expanded.
642 metadata: dict
640 metadata: dict
643 Specify extra metadata to attach to the json display object.
641 Specify extra metadata to attach to the json display object.
644 """
642 """
645 self.expanded = expanded
643 self.expanded = expanded
646 self.metadata = metadata
644 self.metadata = metadata
647 super(JSON, self).__init__(data=data, url=url, filename=filename)
645 super(JSON, self).__init__(data=data, url=url, filename=filename)
648
646
649 def _check_data(self):
647 def _check_data(self):
650 if self.data is not None and not isinstance(self.data, (dict, list)):
648 if self.data is not None and not isinstance(self.data, (dict, list)):
651 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
649 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
652
650
653 @property
651 @property
654 def data(self):
652 def data(self):
655 return self._data
653 return self._data
656
654
657 @data.setter
655 @data.setter
658 def data(self, data):
656 def data(self, data):
659 if isinstance(data, str):
657 if isinstance(data, str):
660 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
658 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
661 data = json.loads(data)
659 data = json.loads(data)
662 self._data = data
660 self._data = data
663
661
664 def _data_and_metadata(self):
662 def _data_and_metadata(self):
665 md = {'expanded': self.expanded}
663 md = {'expanded': self.expanded}
666 if self.metadata:
664 if self.metadata:
667 md.update(self.metadata)
665 md.update(self.metadata)
668 return self.data, md
666 return self.data, md
669
667
670 def _repr_json_(self):
668 def _repr_json_(self):
671 return self._data_and_metadata()
669 return self._data_and_metadata()
672
670
673 css_t = """$("head").append($("<link/>").attr({
671 css_t = """$("head").append($("<link/>").attr({
674 rel: "stylesheet",
672 rel: "stylesheet",
675 type: "text/css",
673 type: "text/css",
676 href: "%s"
674 href: "%s"
677 }));
675 }));
678 """
676 """
679
677
680 lib_t1 = """$.getScript("%s", function () {
678 lib_t1 = """$.getScript("%s", function () {
681 """
679 """
682 lib_t2 = """});
680 lib_t2 = """});
683 """
681 """
684
682
685 class Javascript(TextDisplayObject):
683 class Javascript(TextDisplayObject):
686
684
687 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
685 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
688 """Create a Javascript display object given raw data.
686 """Create a Javascript display object given raw data.
689
687
690 When this object is returned by an expression or passed to the
688 When this object is returned by an expression or passed to the
691 display function, it will result in the data being displayed
689 display function, it will result in the data being displayed
692 in the frontend. If the data is a URL, the data will first be
690 in the frontend. If the data is a URL, the data will first be
693 downloaded and then displayed.
691 downloaded and then displayed.
694
692
695 In the Notebook, the containing element will be available as `element`,
693 In the Notebook, the containing element will be available as `element`,
696 and jQuery will be available. Content appended to `element` will be
694 and jQuery will be available. Content appended to `element` will be
697 visible in the output area.
695 visible in the output area.
698
696
699 Parameters
697 Parameters
700 ----------
698 ----------
701 data : unicode, str or bytes
699 data : unicode, str or bytes
702 The Javascript source code or a URL to download it from.
700 The Javascript source code or a URL to download it from.
703 url : unicode
701 url : unicode
704 A URL to download the data from.
702 A URL to download the data from.
705 filename : unicode
703 filename : unicode
706 Path to a local file to load the data from.
704 Path to a local file to load the data from.
707 lib : list or str
705 lib : list or str
708 A sequence of Javascript library URLs to load asynchronously before
706 A sequence of Javascript library URLs to load asynchronously before
709 running the source code. The full URLs of the libraries should
707 running the source code. The full URLs of the libraries should
710 be given. A single Javascript library URL can also be given as a
708 be given. A single Javascript library URL can also be given as a
711 string.
709 string.
712 css: : list or str
710 css: : list or str
713 A sequence of css files to load before running the source code.
711 A sequence of css files to load before running the source code.
714 The full URLs of the css files should be given. A single css URL
712 The full URLs of the css files should be given. A single css URL
715 can also be given as a string.
713 can also be given as a string.
716 """
714 """
717 if isinstance(lib, str):
715 if isinstance(lib, str):
718 lib = [lib]
716 lib = [lib]
719 elif lib is None:
717 elif lib is None:
720 lib = []
718 lib = []
721 if isinstance(css, str):
719 if isinstance(css, str):
722 css = [css]
720 css = [css]
723 elif css is None:
721 elif css is None:
724 css = []
722 css = []
725 if not isinstance(lib, (list,tuple)):
723 if not isinstance(lib, (list,tuple)):
726 raise TypeError('expected sequence, got: %r' % lib)
724 raise TypeError('expected sequence, got: %r' % lib)
727 if not isinstance(css, (list,tuple)):
725 if not isinstance(css, (list,tuple)):
728 raise TypeError('expected sequence, got: %r' % css)
726 raise TypeError('expected sequence, got: %r' % css)
729 self.lib = lib
727 self.lib = lib
730 self.css = css
728 self.css = css
731 super(Javascript, self).__init__(data=data, url=url, filename=filename)
729 super(Javascript, self).__init__(data=data, url=url, filename=filename)
732
730
733 def _repr_javascript_(self):
731 def _repr_javascript_(self):
734 r = ''
732 r = ''
735 for c in self.css:
733 for c in self.css:
736 r += css_t % c
734 r += css_t % c
737 for l in self.lib:
735 for l in self.lib:
738 r += lib_t1 % l
736 r += lib_t1 % l
739 r += self.data
737 r += self.data
740 r += lib_t2*len(self.lib)
738 r += lib_t2*len(self.lib)
741 return r
739 return r
742
740
743 # constants for identifying png/jpeg data
741 # constants for identifying png/jpeg data
744 _PNG = b'\x89PNG\r\n\x1a\n'
742 _PNG = b'\x89PNG\r\n\x1a\n'
745 _JPEG = b'\xff\xd8'
743 _JPEG = b'\xff\xd8'
746
744
747 def _pngxy(data):
745 def _pngxy(data):
748 """read the (width, height) from a PNG header"""
746 """read the (width, height) from a PNG header"""
749 ihdr = data.index(b'IHDR')
747 ihdr = data.index(b'IHDR')
750 # next 8 bytes are width/height
748 # next 8 bytes are width/height
751 w4h4 = data[ihdr+4:ihdr+12]
749 w4h4 = data[ihdr+4:ihdr+12]
752 return struct.unpack('>ii', w4h4)
750 return struct.unpack('>ii', w4h4)
753
751
754 def _jpegxy(data):
752 def _jpegxy(data):
755 """read the (width, height) from a JPEG header"""
753 """read the (width, height) from a JPEG header"""
756 # adapted from http://www.64lines.com/jpeg-width-height
754 # adapted from http://www.64lines.com/jpeg-width-height
757
755
758 idx = 4
756 idx = 4
759 while True:
757 while True:
760 block_size = struct.unpack('>H', data[idx:idx+2])[0]
758 block_size = struct.unpack('>H', data[idx:idx+2])[0]
761 idx = idx + block_size
759 idx = idx + block_size
762 if data[idx:idx+2] == b'\xFF\xC0':
760 if data[idx:idx+2] == b'\xFF\xC0':
763 # found Start of Frame
761 # found Start of Frame
764 iSOF = idx
762 iSOF = idx
765 break
763 break
766 else:
764 else:
767 # read another block
765 # read another block
768 idx += 2
766 idx += 2
769
767
770 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
768 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
771 return w, h
769 return w, h
772
770
773 class Image(DisplayObject):
771 class Image(DisplayObject):
774
772
775 _read_flags = 'rb'
773 _read_flags = 'rb'
776 _FMT_JPEG = u'jpeg'
774 _FMT_JPEG = u'jpeg'
777 _FMT_PNG = u'png'
775 _FMT_PNG = u'png'
778 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
776 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
779
777
780 def __init__(self, data=None, url=None, filename=None, format=None,
778 def __init__(self, data=None, url=None, filename=None, format=None,
781 embed=None, width=None, height=None, retina=False,
779 embed=None, width=None, height=None, retina=False,
782 unconfined=False, metadata=None):
780 unconfined=False, metadata=None):
783 """Create a PNG/JPEG image object given raw data.
781 """Create a PNG/JPEG image object given raw data.
784
782
785 When this object is returned by an input cell or passed to the
783 When this object is returned by an input cell or passed to the
786 display function, it will result in the image being displayed
784 display function, it will result in the image being displayed
787 in the frontend.
785 in the frontend.
788
786
789 Parameters
787 Parameters
790 ----------
788 ----------
791 data : unicode, str or bytes
789 data : unicode, str or bytes
792 The raw image data or a URL or filename to load the data from.
790 The raw image data or a URL or filename to load the data from.
793 This always results in embedded image data.
791 This always results in embedded image data.
794 url : unicode
792 url : unicode
795 A URL to download the data from. If you specify `url=`,
793 A URL to download the data from. If you specify `url=`,
796 the image data will not be embedded unless you also specify `embed=True`.
794 the image data will not be embedded unless you also specify `embed=True`.
797 filename : unicode
795 filename : unicode
798 Path to a local file to load the data from.
796 Path to a local file to load the data from.
799 Images from a file are always embedded.
797 Images from a file are always embedded.
800 format : unicode
798 format : unicode
801 The format of the image data (png/jpeg/jpg). If a filename or URL is given
799 The format of the image data (png/jpeg/jpg). If a filename or URL is given
802 for format will be inferred from the filename extension.
800 for format will be inferred from the filename extension.
803 embed : bool
801 embed : bool
804 Should the image data be embedded using a data URI (True) or be
802 Should the image data be embedded using a data URI (True) or be
805 loaded using an <img> tag. Set this to True if you want the image
803 loaded using an <img> tag. Set this to True if you want the image
806 to be viewable later with no internet connection in the notebook.
804 to be viewable later with no internet connection in the notebook.
807
805
808 Default is `True`, unless the keyword argument `url` is set, then
806 Default is `True`, unless the keyword argument `url` is set, then
809 default value is `False`.
807 default value is `False`.
810
808
811 Note that QtConsole is not able to display images if `embed` is set to `False`
809 Note that QtConsole is not able to display images if `embed` is set to `False`
812 width : int
810 width : int
813 Width in pixels to which to constrain the image in html
811 Width in pixels to which to constrain the image in html
814 height : int
812 height : int
815 Height in pixels to which to constrain the image in html
813 Height in pixels to which to constrain the image in html
816 retina : bool
814 retina : bool
817 Automatically set the width and height to half of the measured
815 Automatically set the width and height to half of the measured
818 width and height.
816 width and height.
819 This only works for embedded images because it reads the width/height
817 This only works for embedded images because it reads the width/height
820 from image data.
818 from image data.
821 For non-embedded images, you can just set the desired display width
819 For non-embedded images, you can just set the desired display width
822 and height directly.
820 and height directly.
823 unconfined: bool
821 unconfined: bool
824 Set unconfined=True to disable max-width confinement of the image.
822 Set unconfined=True to disable max-width confinement of the image.
825 metadata: dict
823 metadata: dict
826 Specify extra metadata to attach to the image.
824 Specify extra metadata to attach to the image.
827
825
828 Examples
826 Examples
829 --------
827 --------
830 # embedded image data, works in qtconsole and notebook
828 # embedded image data, works in qtconsole and notebook
831 # when passed positionally, the first arg can be any of raw image data,
829 # when passed positionally, the first arg can be any of raw image data,
832 # a URL, or a filename from which to load image data.
830 # a URL, or a filename from which to load image data.
833 # The result is always embedding image data for inline images.
831 # The result is always embedding image data for inline images.
834 Image('http://www.google.fr/images/srpr/logo3w.png')
832 Image('http://www.google.fr/images/srpr/logo3w.png')
835 Image('/path/to/image.jpg')
833 Image('/path/to/image.jpg')
836 Image(b'RAW_PNG_DATA...')
834 Image(b'RAW_PNG_DATA...')
837
835
838 # Specifying Image(url=...) does not embed the image data,
836 # Specifying Image(url=...) does not embed the image data,
839 # it only generates `<img>` tag with a link to the source.
837 # it only generates `<img>` tag with a link to the source.
840 # This will not work in the qtconsole or offline.
838 # This will not work in the qtconsole or offline.
841 Image(url='http://www.google.fr/images/srpr/logo3w.png')
839 Image(url='http://www.google.fr/images/srpr/logo3w.png')
842
840
843 """
841 """
844 if filename is not None:
842 if filename is not None:
845 ext = self._find_ext(filename)
843 ext = self._find_ext(filename)
846 elif url is not None:
844 elif url is not None:
847 ext = self._find_ext(url)
845 ext = self._find_ext(url)
848 elif data is None:
846 elif data is None:
849 raise ValueError("No image data found. Expecting filename, url, or data.")
847 raise ValueError("No image data found. Expecting filename, url, or data.")
850 elif isinstance(data, str) and (
848 elif isinstance(data, str) and (
851 data.startswith('http') or _safe_exists(data)
849 data.startswith('http') or _safe_exists(data)
852 ):
850 ):
853 ext = self._find_ext(data)
851 ext = self._find_ext(data)
854 else:
852 else:
855 ext = None
853 ext = None
856
854
857 if format is None:
855 if format is None:
858 if ext is not None:
856 if ext is not None:
859 if ext == u'jpg' or ext == u'jpeg':
857 if ext == u'jpg' or ext == u'jpeg':
860 format = self._FMT_JPEG
858 format = self._FMT_JPEG
861 if ext == u'png':
859 if ext == u'png':
862 format = self._FMT_PNG
860 format = self._FMT_PNG
863 else:
861 else:
864 format = ext.lower()
862 format = ext.lower()
865 elif isinstance(data, bytes):
863 elif isinstance(data, bytes):
866 # infer image type from image data header,
864 # infer image type from image data header,
867 # only if format has not been specified.
865 # only if format has not been specified.
868 if data[:2] == _JPEG:
866 if data[:2] == _JPEG:
869 format = self._FMT_JPEG
867 format = self._FMT_JPEG
870
868
871 # failed to detect format, default png
869 # failed to detect format, default png
872 if format is None:
870 if format is None:
873 format = 'png'
871 format = 'png'
874
872
875 if format.lower() == 'jpg':
873 if format.lower() == 'jpg':
876 # jpg->jpeg
874 # jpg->jpeg
877 format = self._FMT_JPEG
875 format = self._FMT_JPEG
878
876
879 self.format = format.lower()
877 self.format = format.lower()
880 self.embed = embed if embed is not None else (url is None)
878 self.embed = embed if embed is not None else (url is None)
881
879
882 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
880 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
883 raise ValueError("Cannot embed the '%s' image format" % (self.format))
881 raise ValueError("Cannot embed the '%s' image format" % (self.format))
884 self.width = width
882 self.width = width
885 self.height = height
883 self.height = height
886 self.retina = retina
884 self.retina = retina
887 self.unconfined = unconfined
885 self.unconfined = unconfined
888 self.metadata = metadata
886 self.metadata = metadata
889 super(Image, self).__init__(data=data, url=url, filename=filename)
887 super(Image, self).__init__(data=data, url=url, filename=filename)
890
888
891 if retina:
889 if retina:
892 self._retina_shape()
890 self._retina_shape()
893
891
894 def _retina_shape(self):
892 def _retina_shape(self):
895 """load pixel-doubled width and height from image data"""
893 """load pixel-doubled width and height from image data"""
896 if not self.embed:
894 if not self.embed:
897 return
895 return
898 if self.format == 'png':
896 if self.format == 'png':
899 w, h = _pngxy(self.data)
897 w, h = _pngxy(self.data)
900 elif self.format == 'jpeg':
898 elif self.format == 'jpeg':
901 w, h = _jpegxy(self.data)
899 w, h = _jpegxy(self.data)
902 else:
900 else:
903 # retina only supports png
901 # retina only supports png
904 return
902 return
905 self.width = w // 2
903 self.width = w // 2
906 self.height = h // 2
904 self.height = h // 2
907
905
908 def reload(self):
906 def reload(self):
909 """Reload the raw data from file or URL."""
907 """Reload the raw data from file or URL."""
910 if self.embed:
908 if self.embed:
911 super(Image,self).reload()
909 super(Image,self).reload()
912 if self.retina:
910 if self.retina:
913 self._retina_shape()
911 self._retina_shape()
914
912
915 def _repr_html_(self):
913 def _repr_html_(self):
916 if not self.embed:
914 if not self.embed:
917 width = height = klass = ''
915 width = height = klass = ''
918 if self.width:
916 if self.width:
919 width = ' width="%d"' % self.width
917 width = ' width="%d"' % self.width
920 if self.height:
918 if self.height:
921 height = ' height="%d"' % self.height
919 height = ' height="%d"' % self.height
922 if self.unconfined:
920 if self.unconfined:
923 klass = ' class="unconfined"'
921 klass = ' class="unconfined"'
924 return u'<img src="{url}"{width}{height}{klass}/>'.format(
922 return u'<img src="{url}"{width}{height}{klass}/>'.format(
925 url=self.url,
923 url=self.url,
926 width=width,
924 width=width,
927 height=height,
925 height=height,
928 klass=klass,
926 klass=klass,
929 )
927 )
930
928
931 def _data_and_metadata(self):
929 def _data_and_metadata(self):
932 """shortcut for returning metadata with shape information, if defined"""
930 """shortcut for returning metadata with shape information, if defined"""
933 md = {}
931 md = {}
934 if self.width:
932 if self.width:
935 md['width'] = self.width
933 md['width'] = self.width
936 if self.height:
934 if self.height:
937 md['height'] = self.height
935 md['height'] = self.height
938 if self.unconfined:
936 if self.unconfined:
939 md['unconfined'] = self.unconfined
937 md['unconfined'] = self.unconfined
940 if self.metadata:
938 if self.metadata:
941 md.update(self.metadata)
939 md.update(self.metadata)
942 if md:
940 if md:
943 return self.data, md
941 return self.data, md
944 else:
942 else:
945 return self.data
943 return self.data
946
944
947 def _repr_png_(self):
945 def _repr_png_(self):
948 if self.embed and self.format == u'png':
946 if self.embed and self.format == u'png':
949 return self._data_and_metadata()
947 return self._data_and_metadata()
950
948
951 def _repr_jpeg_(self):
949 def _repr_jpeg_(self):
952 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
950 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
953 return self._data_and_metadata()
951 return self._data_and_metadata()
954
952
955 def _find_ext(self, s):
953 def _find_ext(self, s):
956 return s.split('.')[-1].lower()
954 return s.split('.')[-1].lower()
957
955
958 class Video(DisplayObject):
956 class Video(DisplayObject):
959
957
960 def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=None):
958 def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=None):
961 """Create a video object given raw data or an URL.
959 """Create a video object given raw data or an URL.
962
960
963 When this object is returned by an input cell or passed to the
961 When this object is returned by an input cell or passed to the
964 display function, it will result in the video being displayed
962 display function, it will result in the video being displayed
965 in the frontend.
963 in the frontend.
966
964
967 Parameters
965 Parameters
968 ----------
966 ----------
969 data : unicode, str or bytes
967 data : unicode, str or bytes
970 The raw video data or a URL or filename to load the data from.
968 The raw video data or a URL or filename to load the data from.
971 Raw data will require passing `embed=True`.
969 Raw data will require passing `embed=True`.
972 url : unicode
970 url : unicode
973 A URL for the video. If you specify `url=`,
971 A URL for the video. If you specify `url=`,
974 the image data will not be embedded.
972 the image data will not be embedded.
975 filename : unicode
973 filename : unicode
976 Path to a local file containing the video.
974 Path to a local file containing the video.
977 Will be interpreted as a local URL unless `embed=True`.
975 Will be interpreted as a local URL unless `embed=True`.
978 embed : bool
976 embed : bool
979 Should the video be embedded using a data URI (True) or be
977 Should the video be embedded using a data URI (True) or be
980 loaded using a <video> tag (False).
978 loaded using a <video> tag (False).
981
979
982 Since videos are large, embedding them should be avoided, if possible.
980 Since videos are large, embedding them should be avoided, if possible.
983 You must confirm embedding as your intention by passing `embed=True`.
981 You must confirm embedding as your intention by passing `embed=True`.
984
982
985 Local files can be displayed with URLs without embedding the content, via::
983 Local files can be displayed with URLs without embedding the content, via::
986
984
987 Video('./video.mp4')
985 Video('./video.mp4')
988
986
989 mimetype: unicode
987 mimetype: unicode
990 Specify the mimetype for embedded videos.
988 Specify the mimetype for embedded videos.
991 Default will be guessed from file extension, if available.
989 Default will be guessed from file extension, if available.
992
990
993 Examples
991 Examples
994 --------
992 --------
995
993
996 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
994 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
997 Video('path/to/video.mp4')
995 Video('path/to/video.mp4')
998 Video('path/to/video.mp4', embed=True)
996 Video('path/to/video.mp4', embed=True)
999 Video(b'raw-videodata', embed=True)
997 Video(b'raw-videodata', embed=True)
1000 """
998 """
1001 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
999 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1002 url = data
1000 url = data
1003 data = None
1001 data = None
1004 elif os.path.exists(data):
1002 elif os.path.exists(data):
1005 filename = data
1003 filename = data
1006 data = None
1004 data = None
1007
1005
1008 if data and not embed:
1006 if data and not embed:
1009 msg = ''.join([
1007 msg = ''.join([
1010 "To embed videos, you must pass embed=True ",
1008 "To embed videos, you must pass embed=True ",
1011 "(this may make your notebook files huge)\n",
1009 "(this may make your notebook files huge)\n",
1012 "Consider passing Video(url='...')",
1010 "Consider passing Video(url='...')",
1013 ])
1011 ])
1014 raise ValueError(msg)
1012 raise ValueError(msg)
1015
1013
1016 self.mimetype = mimetype
1014 self.mimetype = mimetype
1017 self.embed = embed
1015 self.embed = embed
1018 super(Video, self).__init__(data=data, url=url, filename=filename)
1016 super(Video, self).__init__(data=data, url=url, filename=filename)
1019
1017
1020 def _repr_html_(self):
1018 def _repr_html_(self):
1021 # External URLs and potentially local files are not embedded into the
1019 # External URLs and potentially local files are not embedded into the
1022 # notebook output.
1020 # notebook output.
1023 if not self.embed:
1021 if not self.embed:
1024 url = self.url if self.url is not None else self.filename
1022 url = self.url if self.url is not None else self.filename
1025 output = """<video src="{0}" controls>
1023 output = """<video src="{0}" controls>
1026 Your browser does not support the <code>video</code> element.
1024 Your browser does not support the <code>video</code> element.
1027 </video>""".format(url)
1025 </video>""".format(url)
1028 return output
1026 return output
1029
1027
1030 # Embedded videos are base64-encoded.
1028 # Embedded videos are base64-encoded.
1031 mimetype = self.mimetype
1029 mimetype = self.mimetype
1032 if self.filename is not None:
1030 if self.filename is not None:
1033 if not mimetype:
1031 if not mimetype:
1034 mimetype, _ = mimetypes.guess_type(self.filename)
1032 mimetype, _ = mimetypes.guess_type(self.filename)
1035
1033
1036 with open(self.filename, 'rb') as f:
1034 with open(self.filename, 'rb') as f:
1037 video = f.read()
1035 video = f.read()
1038 else:
1036 else:
1039 video = self.data
1037 video = self.data
1040 if isinstance(video, str):
1038 if isinstance(video, str):
1041 # unicode input is already b64-encoded
1039 # unicode input is already b64-encoded
1042 b64_video = video
1040 b64_video = video
1043 else:
1041 else:
1044 b64_video = base64_encode(video).decode('ascii').rstrip()
1042 b64_video = base64_encode(video).decode('ascii').rstrip()
1045
1043
1046 output = """<video controls>
1044 output = """<video controls>
1047 <source src="data:{0};base64,{1}" type="{0}">
1045 <source src="data:{0};base64,{1}" type="{0}">
1048 Your browser does not support the video tag.
1046 Your browser does not support the video tag.
1049 </video>""".format(mimetype, b64_video)
1047 </video>""".format(mimetype, b64_video)
1050 return output
1048 return output
1051
1049
1052 def reload(self):
1050 def reload(self):
1053 # TODO
1051 # TODO
1054 pass
1052 pass
1055
1053
1056 def _repr_png_(self):
1054 def _repr_png_(self):
1057 # TODO
1055 # TODO
1058 pass
1056 pass
1059 def _repr_jpeg_(self):
1057 def _repr_jpeg_(self):
1060 # TODO
1058 # TODO
1061 pass
1059 pass
1062
1060
1063 def clear_output(wait=False):
1061 def clear_output(wait=False):
1064 """Clear the output of the current cell receiving output.
1062 """Clear the output of the current cell receiving output.
1065
1063
1066 Parameters
1064 Parameters
1067 ----------
1065 ----------
1068 wait : bool [default: false]
1066 wait : bool [default: false]
1069 Wait to clear the output until new output is available to replace it."""
1067 Wait to clear the output until new output is available to replace it."""
1070 from IPython.core.interactiveshell import InteractiveShell
1068 from IPython.core.interactiveshell import InteractiveShell
1071 if InteractiveShell.initialized():
1069 if InteractiveShell.initialized():
1072 InteractiveShell.instance().display_pub.clear_output(wait)
1070 InteractiveShell.instance().display_pub.clear_output(wait)
1073 else:
1071 else:
1074 print('\033[2K\r', end='')
1072 print('\033[2K\r', end='')
1075 sys.stdout.flush()
1073 sys.stdout.flush()
1076 print('\033[2K\r', end='')
1074 print('\033[2K\r', end='')
1077 sys.stderr.flush()
1075 sys.stderr.flush()
1078
1076
1079
1077
1080 @skip_doctest
1078 @skip_doctest
1081 def set_matplotlib_formats(*formats, **kwargs):
1079 def set_matplotlib_formats(*formats, **kwargs):
1082 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
1080 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
1083
1081
1084 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1082 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1085
1083
1086 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1084 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1087
1085
1088 To set this in your config files use the following::
1086 To set this in your config files use the following::
1089
1087
1090 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1088 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1091 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1089 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1092
1090
1093 Parameters
1091 Parameters
1094 ----------
1092 ----------
1095 *formats : strs
1093 *formats : strs
1096 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1094 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1097 **kwargs :
1095 **kwargs :
1098 Keyword args will be relayed to ``figure.canvas.print_figure``.
1096 Keyword args will be relayed to ``figure.canvas.print_figure``.
1099 """
1097 """
1100 from IPython.core.interactiveshell import InteractiveShell
1098 from IPython.core.interactiveshell import InteractiveShell
1101 from IPython.core.pylabtools import select_figure_formats
1099 from IPython.core.pylabtools import select_figure_formats
1102 # build kwargs, starting with InlineBackend config
1100 # build kwargs, starting with InlineBackend config
1103 kw = {}
1101 kw = {}
1104 from ipykernel.pylab.config import InlineBackend
1102 from ipykernel.pylab.config import InlineBackend
1105 cfg = InlineBackend.instance()
1103 cfg = InlineBackend.instance()
1106 kw.update(cfg.print_figure_kwargs)
1104 kw.update(cfg.print_figure_kwargs)
1107 kw.update(**kwargs)
1105 kw.update(**kwargs)
1108 shell = InteractiveShell.instance()
1106 shell = InteractiveShell.instance()
1109 select_figure_formats(shell, formats, **kw)
1107 select_figure_formats(shell, formats, **kw)
1110
1108
1111 @skip_doctest
1109 @skip_doctest
1112 def set_matplotlib_close(close=True):
1110 def set_matplotlib_close(close=True):
1113 """Set whether the inline backend closes all figures automatically or not.
1111 """Set whether the inline backend closes all figures automatically or not.
1114
1112
1115 By default, the inline backend used in the IPython Notebook will close all
1113 By default, the inline backend used in the IPython Notebook will close all
1116 matplotlib figures automatically after each cell is run. This means that
1114 matplotlib figures automatically after each cell is run. This means that
1117 plots in different cells won't interfere. Sometimes, you may want to make
1115 plots in different cells won't interfere. Sometimes, you may want to make
1118 a plot in one cell and then refine it in later cells. This can be accomplished
1116 a plot in one cell and then refine it in later cells. This can be accomplished
1119 by::
1117 by::
1120
1118
1121 In [1]: set_matplotlib_close(False)
1119 In [1]: set_matplotlib_close(False)
1122
1120
1123 To set this in your config files use the following::
1121 To set this in your config files use the following::
1124
1122
1125 c.InlineBackend.close_figures = False
1123 c.InlineBackend.close_figures = False
1126
1124
1127 Parameters
1125 Parameters
1128 ----------
1126 ----------
1129 close : bool
1127 close : bool
1130 Should all matplotlib figures be automatically closed after each cell is
1128 Should all matplotlib figures be automatically closed after each cell is
1131 run?
1129 run?
1132 """
1130 """
1133 from ipykernel.pylab.config import InlineBackend
1131 from ipykernel.pylab.config import InlineBackend
1134 cfg = InlineBackend.instance()
1132 cfg = InlineBackend.instance()
1135 cfg.close_figures = close
1133 cfg.close_figures = close
@@ -1,174 +1,170 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """A class for managing IPython extensions."""
2 """A class for managing IPython extensions."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import os
7 import os
8 from shutil import copyfile
8 from shutil import copyfile
9 import sys
9 import sys
10 from importlib import import_module
10 from importlib import import_module
11
11
12 from traitlets.config.configurable import Configurable
12 from traitlets.config.configurable import Configurable
13 from IPython.utils.path import ensure_dir_exists
13 from IPython.utils.path import ensure_dir_exists
14 from traitlets import Instance
14 from traitlets import Instance
15
15
16 try:
16 try:
17 from importlib import reload
17 from importlib import reload
18 except ImportError :
18 except ImportError :
19 ## deprecated since 3.4
19 ## deprecated since 3.4
20 from imp import reload
20 from imp import reload
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Main class
23 # Main class
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 class ExtensionManager(Configurable):
26 class ExtensionManager(Configurable):
27 """A class to manage IPython extensions.
27 """A class to manage IPython extensions.
28
28
29 An IPython extension is an importable Python module that has
29 An IPython extension is an importable Python module that has
30 a function with the signature::
30 a function with the signature::
31
31
32 def load_ipython_extension(ipython):
32 def load_ipython_extension(ipython):
33 # Do things with ipython
33 # Do things with ipython
34
34
35 This function is called after your extension is imported and the
35 This function is called after your extension is imported and the
36 currently active :class:`InteractiveShell` instance is passed as
36 currently active :class:`InteractiveShell` instance is passed as
37 the only argument. You can do anything you want with IPython at
37 the only argument. You can do anything you want with IPython at
38 that point, including defining new magic and aliases, adding new
38 that point, including defining new magic and aliases, adding new
39 components, etc.
39 components, etc.
40
40
41 You can also optionally define an :func:`unload_ipython_extension(ipython)`
41 You can also optionally define an :func:`unload_ipython_extension(ipython)`
42 function, which will be called if the user unloads or reloads the extension.
42 function, which will be called if the user unloads or reloads the extension.
43 The extension manager will only call :func:`load_ipython_extension` again
43 The extension manager will only call :func:`load_ipython_extension` again
44 if the extension is reloaded.
44 if the extension is reloaded.
45
45
46 You can put your extension modules anywhere you want, as long as
46 You can put your extension modules anywhere you want, as long as
47 they can be imported by Python's standard import mechanism. However,
47 they can be imported by Python's standard import mechanism. However,
48 to make it easy to write extensions, you can also put your extensions
48 to make it easy to write extensions, you can also put your extensions
49 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
49 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
50 is added to ``sys.path`` automatically.
50 is added to ``sys.path`` automatically.
51 """
51 """
52
52
53 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
53 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
54
54
55 def __init__(self, shell=None, **kwargs):
55 def __init__(self, shell=None, **kwargs):
56 super(ExtensionManager, self).__init__(shell=shell, **kwargs)
56 super(ExtensionManager, self).__init__(shell=shell, **kwargs)
57 self.shell.observe(
57 self.shell.observe(
58 self._on_ipython_dir_changed, names=('ipython_dir',)
58 self._on_ipython_dir_changed, names=('ipython_dir',)
59 )
59 )
60 self.loaded = set()
60 self.loaded = set()
61
61
62 @property
62 @property
63 def ipython_extension_dir(self):
63 def ipython_extension_dir(self):
64 return os.path.join(self.shell.ipython_dir, u'extensions')
64 return os.path.join(self.shell.ipython_dir, u'extensions')
65
65
66 def _on_ipython_dir_changed(self, change):
66 def _on_ipython_dir_changed(self, change):
67 ensure_dir_exists(self.ipython_extension_dir)
67 ensure_dir_exists(self.ipython_extension_dir)
68
68
69 def load_extension(self, module_str):
69 def load_extension(self, module_str):
70 """Load an IPython extension by its module name.
70 """Load an IPython extension by its module name.
71
71
72 Returns the string "already loaded" if the extension is already loaded,
72 Returns the string "already loaded" if the extension is already loaded,
73 "no load function" if the module doesn't have a load_ipython_extension
73 "no load function" if the module doesn't have a load_ipython_extension
74 function, or None if it succeeded.
74 function, or None if it succeeded.
75 """
75 """
76 if module_str in self.loaded:
76 if module_str in self.loaded:
77 return "already loaded"
77 return "already loaded"
78
78
79 from IPython.utils.syspathcontext import prepended_to_syspath
79 from IPython.utils.syspathcontext import prepended_to_syspath
80
80
81 with self.shell.builtin_trap:
81 with self.shell.builtin_trap:
82 if module_str not in sys.modules:
82 if module_str not in sys.modules:
83 with prepended_to_syspath(self.ipython_extension_dir):
83 with prepended_to_syspath(self.ipython_extension_dir):
84 import_module(module_str)
84 import_module(module_str)
85 mod = sys.modules[module_str]
85 mod = sys.modules[module_str]
86 if self._call_load_ipython_extension(mod):
86 if self._call_load_ipython_extension(mod):
87 self.loaded.add(module_str)
87 self.loaded.add(module_str)
88 else:
88 else:
89 return "no load function"
89 return "no load function"
90
90
91 def unload_extension(self, module_str):
91 def unload_extension(self, module_str):
92 """Unload an IPython extension by its module name.
92 """Unload an IPython extension by its module name.
93
93
94 This function looks up the extension's name in ``sys.modules`` and
94 This function looks up the extension's name in ``sys.modules`` and
95 simply calls ``mod.unload_ipython_extension(self)``.
95 simply calls ``mod.unload_ipython_extension(self)``.
96
96
97 Returns the string "no unload function" if the extension doesn't define
97 Returns the string "no unload function" if the extension doesn't define
98 a function to unload itself, "not loaded" if the extension isn't loaded,
98 a function to unload itself, "not loaded" if the extension isn't loaded,
99 otherwise None.
99 otherwise None.
100 """
100 """
101 if module_str not in self.loaded:
101 if module_str not in self.loaded:
102 return "not loaded"
102 return "not loaded"
103
103
104 if module_str in sys.modules:
104 if module_str in sys.modules:
105 mod = sys.modules[module_str]
105 mod = sys.modules[module_str]
106 if self._call_unload_ipython_extension(mod):
106 if self._call_unload_ipython_extension(mod):
107 self.loaded.discard(module_str)
107 self.loaded.discard(module_str)
108 else:
108 else:
109 return "no unload function"
109 return "no unload function"
110
110
111 def reload_extension(self, module_str):
111 def reload_extension(self, module_str):
112 """Reload an IPython extension by calling reload.
112 """Reload an IPython extension by calling reload.
113
113
114 If the module has not been loaded before,
114 If the module has not been loaded before,
115 :meth:`InteractiveShell.load_extension` is called. Otherwise
115 :meth:`InteractiveShell.load_extension` is called. Otherwise
116 :func:`reload` is called and then the :func:`load_ipython_extension`
116 :func:`reload` is called and then the :func:`load_ipython_extension`
117 function of the module, if it exists is called.
117 function of the module, if it exists is called.
118 """
118 """
119 from IPython.utils.syspathcontext import prepended_to_syspath
119 from IPython.utils.syspathcontext import prepended_to_syspath
120
120
121 if (module_str in self.loaded) and (module_str in sys.modules):
121 if (module_str in self.loaded) and (module_str in sys.modules):
122 self.unload_extension(module_str)
122 self.unload_extension(module_str)
123 mod = sys.modules[module_str]
123 mod = sys.modules[module_str]
124 with prepended_to_syspath(self.ipython_extension_dir):
124 with prepended_to_syspath(self.ipython_extension_dir):
125 reload(mod)
125 reload(mod)
126 if self._call_load_ipython_extension(mod):
126 if self._call_load_ipython_extension(mod):
127 self.loaded.add(module_str)
127 self.loaded.add(module_str)
128 else:
128 else:
129 self.load_extension(module_str)
129 self.load_extension(module_str)
130
130
131 def _call_load_ipython_extension(self, mod):
131 def _call_load_ipython_extension(self, mod):
132 if hasattr(mod, 'load_ipython_extension'):
132 if hasattr(mod, 'load_ipython_extension'):
133 mod.load_ipython_extension(self.shell)
133 mod.load_ipython_extension(self.shell)
134 return True
134 return True
135
135
136 def _call_unload_ipython_extension(self, mod):
136 def _call_unload_ipython_extension(self, mod):
137 if hasattr(mod, 'unload_ipython_extension'):
137 if hasattr(mod, 'unload_ipython_extension'):
138 mod.unload_ipython_extension(self.shell)
138 mod.unload_ipython_extension(self.shell)
139 return True
139 return True
140
140
141 def install_extension(self, url, filename=None):
141 def install_extension(self, url, filename=None):
142 """Download and install an IPython extension.
142 """Download and install an IPython extension.
143
143
144 If filename is given, the file will be so named (inside the extension
144 If filename is given, the file will be so named (inside the extension
145 directory). Otherwise, the name from the URL will be used. The file must
145 directory). Otherwise, the name from the URL will be used. The file must
146 have a .py or .zip extension; otherwise, a ValueError will be raised.
146 have a .py or .zip extension; otherwise, a ValueError will be raised.
147
147
148 Returns the full path to the installed file.
148 Returns the full path to the installed file.
149 """
149 """
150 # Ensure the extension directory exists
150 # Ensure the extension directory exists
151 ensure_dir_exists(self.ipython_extension_dir)
151 ensure_dir_exists(self.ipython_extension_dir)
152
152
153 if os.path.isfile(url):
153 if os.path.isfile(url):
154 src_filename = os.path.basename(url)
154 src_filename = os.path.basename(url)
155 copy = copyfile
155 copy = copyfile
156 else:
156 else:
157 # Deferred imports
157 # Deferred imports
158 try:
158 from urllib.parse import urlparse
159 from urllib.parse import urlparse # Py3
159 from urllib.request import urlretrieve
160 from urllib.request import urlretrieve
161 except ImportError:
162 from urlparse import urlparse
163 from urllib import urlretrieve
164 src_filename = urlparse(url).path.split('/')[-1]
160 src_filename = urlparse(url).path.split('/')[-1]
165 copy = urlretrieve
161 copy = urlretrieve
166
162
167 if filename is None:
163 if filename is None:
168 filename = src_filename
164 filename = src_filename
169 if os.path.splitext(filename)[1] not in ('.py', '.zip'):
165 if os.path.splitext(filename)[1] not in ('.py', '.zip'):
170 raise ValueError("The file must have a .py or .zip extension", filename)
166 raise ValueError("The file must have a .py or .zip extension", filename)
171
167
172 filename = os.path.join(self.ipython_extension_dir, filename)
168 filename = os.path.join(self.ipython_extension_dir, filename)
173 copy(url, filename)
169 copy(url, filename)
174 return filename
170 return filename
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,558 +1,557 b''
1 """Various display related classes.
1 """Various display related classes.
2
2
3 Authors : MinRK, gregcaporaso, dannystaple
3 Authors : MinRK, gregcaporaso, dannystaple
4 """
4 """
5 from os.path import exists, isfile, splitext, abspath, join, isdir
5 from os.path import exists, isfile, splitext, abspath, join, isdir
6 from os import walk, sep
6 from os import walk, sep
7
7
8 from IPython.core.display import DisplayObject
8 from IPython.core.display import DisplayObject
9
9
10 __all__ = ['Audio', 'IFrame', 'YouTubeVideo', 'VimeoVideo', 'ScribdDocument',
10 __all__ = ['Audio', 'IFrame', 'YouTubeVideo', 'VimeoVideo', 'ScribdDocument',
11 'FileLink', 'FileLinks']
11 'FileLink', 'FileLinks']
12
12
13
13
14 class Audio(DisplayObject):
14 class Audio(DisplayObject):
15 """Create an audio object.
15 """Create an audio object.
16
16
17 When this object is returned by an input cell or passed to the
17 When this object is returned by an input cell or passed to the
18 display function, it will result in Audio controls being displayed
18 display function, it will result in Audio controls being displayed
19 in the frontend (only works in the notebook).
19 in the frontend (only works in the notebook).
20
20
21 Parameters
21 Parameters
22 ----------
22 ----------
23 data : numpy array, list, unicode, str or bytes
23 data : numpy array, list, unicode, str or bytes
24 Can be one of
24 Can be one of
25
25
26 * Numpy 1d array containing the desired waveform (mono)
26 * Numpy 1d array containing the desired waveform (mono)
27 * Numpy 2d array containing waveforms for each channel.
27 * Numpy 2d array containing waveforms for each channel.
28 Shape=(NCHAN, NSAMPLES). For the standard channel order, see
28 Shape=(NCHAN, NSAMPLES). For the standard channel order, see
29 http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
29 http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
30 * List of float or integer representing the waveform (mono)
30 * List of float or integer representing the waveform (mono)
31 * String containing the filename
31 * String containing the filename
32 * Bytestring containing raw PCM data or
32 * Bytestring containing raw PCM data or
33 * URL pointing to a file on the web.
33 * URL pointing to a file on the web.
34
34
35 If the array option is used the waveform will be normalized.
35 If the array option is used the waveform will be normalized.
36
36
37 If a filename or url is used the format support will be browser
37 If a filename or url is used the format support will be browser
38 dependent.
38 dependent.
39 url : unicode
39 url : unicode
40 A URL to download the data from.
40 A URL to download the data from.
41 filename : unicode
41 filename : unicode
42 Path to a local file to load the data from.
42 Path to a local file to load the data from.
43 embed : boolean
43 embed : boolean
44 Should the audio data be embedded using a data URI (True) or should
44 Should the audio data be embedded using a data URI (True) or should
45 the original source be referenced. Set this to True if you want the
45 the original source be referenced. Set this to True if you want the
46 audio to playable later with no internet connection in the notebook.
46 audio to playable later with no internet connection in the notebook.
47
47
48 Default is `True`, unless the keyword argument `url` is set, then
48 Default is `True`, unless the keyword argument `url` is set, then
49 default value is `False`.
49 default value is `False`.
50 rate : integer
50 rate : integer
51 The sampling rate of the raw data.
51 The sampling rate of the raw data.
52 Only required when data parameter is being used as an array
52 Only required when data parameter is being used as an array
53 autoplay : bool
53 autoplay : bool
54 Set to True if the audio should immediately start playing.
54 Set to True if the audio should immediately start playing.
55 Default is `False`.
55 Default is `False`.
56
56
57 Examples
57 Examples
58 --------
58 --------
59 ::
59 ::
60
60
61 # Generate a sound
61 # Generate a sound
62 import numpy as np
62 import numpy as np
63 framerate = 44100
63 framerate = 44100
64 t = np.linspace(0,5,framerate*5)
64 t = np.linspace(0,5,framerate*5)
65 data = np.sin(2*np.pi*220*t) + np.sin(2*np.pi*224*t))
65 data = np.sin(2*np.pi*220*t) + np.sin(2*np.pi*224*t))
66 Audio(data,rate=framerate)
66 Audio(data,rate=framerate)
67
67
68 # Can also do stereo or more channels
68 # Can also do stereo or more channels
69 dataleft = np.sin(2*np.pi*220*t)
69 dataleft = np.sin(2*np.pi*220*t)
70 dataright = np.sin(2*np.pi*224*t)
70 dataright = np.sin(2*np.pi*224*t)
71 Audio([dataleft, dataright],rate=framerate)
71 Audio([dataleft, dataright],rate=framerate)
72
72
73 Audio("http://www.nch.com.au/acm/8k16bitpcm.wav") # From URL
73 Audio("http://www.nch.com.au/acm/8k16bitpcm.wav") # From URL
74 Audio(url="http://www.w3schools.com/html/horse.ogg")
74 Audio(url="http://www.w3schools.com/html/horse.ogg")
75
75
76 Audio('/path/to/sound.wav') # From file
76 Audio('/path/to/sound.wav') # From file
77 Audio(filename='/path/to/sound.ogg')
77 Audio(filename='/path/to/sound.ogg')
78
78
79 Audio(b'RAW_WAV_DATA..) # From bytes
79 Audio(b'RAW_WAV_DATA..) # From bytes
80 Audio(data=b'RAW_WAV_DATA..)
80 Audio(data=b'RAW_WAV_DATA..)
81
81
82 """
82 """
83 _read_flags = 'rb'
83 _read_flags = 'rb'
84
84
85 def __init__(self, data=None, filename=None, url=None, embed=None, rate=None, autoplay=False):
85 def __init__(self, data=None, filename=None, url=None, embed=None, rate=None, autoplay=False):
86 if filename is None and url is None and data is None:
86 if filename is None and url is None and data is None:
87 raise ValueError("No image data found. Expecting filename, url, or data.")
87 raise ValueError("No image data found. Expecting filename, url, or data.")
88 if embed is False and url is None:
88 if embed is False and url is None:
89 raise ValueError("No url found. Expecting url when embed=False")
89 raise ValueError("No url found. Expecting url when embed=False")
90
90
91 if url is not None and embed is not True:
91 if url is not None and embed is not True:
92 self.embed = False
92 self.embed = False
93 else:
93 else:
94 self.embed = True
94 self.embed = True
95 self.autoplay = autoplay
95 self.autoplay = autoplay
96 super(Audio, self).__init__(data=data, url=url, filename=filename)
96 super(Audio, self).__init__(data=data, url=url, filename=filename)
97
97
98 if self.data is not None and not isinstance(self.data, bytes):
98 if self.data is not None and not isinstance(self.data, bytes):
99 self.data = self._make_wav(data,rate)
99 self.data = self._make_wav(data,rate)
100
100
101 def reload(self):
101 def reload(self):
102 """Reload the raw data from file or URL."""
102 """Reload the raw data from file or URL."""
103 import mimetypes
103 import mimetypes
104 if self.embed:
104 if self.embed:
105 super(Audio, self).reload()
105 super(Audio, self).reload()
106
106
107 if self.filename is not None:
107 if self.filename is not None:
108 self.mimetype = mimetypes.guess_type(self.filename)[0]
108 self.mimetype = mimetypes.guess_type(self.filename)[0]
109 elif self.url is not None:
109 elif self.url is not None:
110 self.mimetype = mimetypes.guess_type(self.url)[0]
110 self.mimetype = mimetypes.guess_type(self.url)[0]
111 else:
111 else:
112 self.mimetype = "audio/wav"
112 self.mimetype = "audio/wav"
113
113
114 def _make_wav(self, data, rate):
114 def _make_wav(self, data, rate):
115 """ Transform a numpy array to a PCM bytestring """
115 """ Transform a numpy array to a PCM bytestring """
116 import struct
116 import struct
117 from io import BytesIO
117 from io import BytesIO
118 import wave
118 import wave
119
119
120 try:
120 try:
121 import numpy as np
121 import numpy as np
122
122
123 data = np.array(data, dtype=float)
123 data = np.array(data, dtype=float)
124 if len(data.shape) == 1:
124 if len(data.shape) == 1:
125 nchan = 1
125 nchan = 1
126 elif len(data.shape) == 2:
126 elif len(data.shape) == 2:
127 # In wave files,channels are interleaved. E.g.,
127 # In wave files,channels are interleaved. E.g.,
128 # "L1R1L2R2..." for stereo. See
128 # "L1R1L2R2..." for stereo. See
129 # http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
129 # http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
130 # for channel ordering
130 # for channel ordering
131 nchan = data.shape[0]
131 nchan = data.shape[0]
132 data = data.T.ravel()
132 data = data.T.ravel()
133 else:
133 else:
134 raise ValueError('Array audio input must be a 1D or 2D array')
134 raise ValueError('Array audio input must be a 1D or 2D array')
135 scaled = np.int16(data/np.max(np.abs(data))*32767).tolist()
135 scaled = np.int16(data/np.max(np.abs(data))*32767).tolist()
136 except ImportError:
136 except ImportError:
137 # check that it is a "1D" list
137 # check that it is a "1D" list
138 idata = iter(data) # fails if not an iterable
138 idata = iter(data) # fails if not an iterable
139 try:
139 try:
140 iter(idata.next())
140 iter(idata.next())
141 raise TypeError('Only lists of mono audio are '
141 raise TypeError('Only lists of mono audio are '
142 'supported if numpy is not installed')
142 'supported if numpy is not installed')
143 except TypeError:
143 except TypeError:
144 # this means it's not a nested list, which is what we want
144 # this means it's not a nested list, which is what we want
145 pass
145 pass
146 maxabsvalue = float(max([abs(x) for x in data]))
146 maxabsvalue = float(max([abs(x) for x in data]))
147 scaled = [int(x/maxabsvalue*32767) for x in data]
147 scaled = [int(x/maxabsvalue*32767) for x in data]
148 nchan = 1
148 nchan = 1
149
149
150 fp = BytesIO()
150 fp = BytesIO()
151 waveobj = wave.open(fp,mode='wb')
151 waveobj = wave.open(fp,mode='wb')
152 waveobj.setnchannels(nchan)
152 waveobj.setnchannels(nchan)
153 waveobj.setframerate(rate)
153 waveobj.setframerate(rate)
154 waveobj.setsampwidth(2)
154 waveobj.setsampwidth(2)
155 waveobj.setcomptype('NONE','NONE')
155 waveobj.setcomptype('NONE','NONE')
156 waveobj.writeframes(b''.join([struct.pack('<h',x) for x in scaled]))
156 waveobj.writeframes(b''.join([struct.pack('<h',x) for x in scaled]))
157 val = fp.getvalue()
157 val = fp.getvalue()
158 waveobj.close()
158 waveobj.close()
159
159
160 return val
160 return val
161
161
162 def _data_and_metadata(self):
162 def _data_and_metadata(self):
163 """shortcut for returning metadata with url information, if defined"""
163 """shortcut for returning metadata with url information, if defined"""
164 md = {}
164 md = {}
165 if self.url:
165 if self.url:
166 md['url'] = self.url
166 md['url'] = self.url
167 if md:
167 if md:
168 return self.data, md
168 return self.data, md
169 else:
169 else:
170 return self.data
170 return self.data
171
171
172 def _repr_html_(self):
172 def _repr_html_(self):
173 src = """
173 src = """
174 <audio controls="controls" {autoplay}>
174 <audio controls="controls" {autoplay}>
175 <source src="{src}" type="{type}" />
175 <source src="{src}" type="{type}" />
176 Your browser does not support the audio element.
176 Your browser does not support the audio element.
177 </audio>
177 </audio>
178 """
178 """
179 return src.format(src=self.src_attr(),type=self.mimetype, autoplay=self.autoplay_attr())
179 return src.format(src=self.src_attr(),type=self.mimetype, autoplay=self.autoplay_attr())
180
180
181 def src_attr(self):
181 def src_attr(self):
182 import base64
182 import base64
183 if self.embed and (self.data is not None):
183 if self.embed and (self.data is not None):
184 data = base64=base64.b64encode(self.data).decode('ascii')
184 data = base64=base64.b64encode(self.data).decode('ascii')
185 return """data:{type};base64,{base64}""".format(type=self.mimetype,
185 return """data:{type};base64,{base64}""".format(type=self.mimetype,
186 base64=data)
186 base64=data)
187 elif self.url is not None:
187 elif self.url is not None:
188 return self.url
188 return self.url
189 else:
189 else:
190 return ""
190 return ""
191
191
192 def autoplay_attr(self):
192 def autoplay_attr(self):
193 if(self.autoplay):
193 if(self.autoplay):
194 return 'autoplay="autoplay"'
194 return 'autoplay="autoplay"'
195 else:
195 else:
196 return ''
196 return ''
197
197
198 class IFrame(object):
198 class IFrame(object):
199 """
199 """
200 Generic class to embed an iframe in an IPython notebook
200 Generic class to embed an iframe in an IPython notebook
201 """
201 """
202
202
203 iframe = """
203 iframe = """
204 <iframe
204 <iframe
205 width="{width}"
205 width="{width}"
206 height="{height}"
206 height="{height}"
207 src="{src}{params}"
207 src="{src}{params}"
208 frameborder="0"
208 frameborder="0"
209 allowfullscreen
209 allowfullscreen
210 ></iframe>
210 ></iframe>
211 """
211 """
212
212
213 def __init__(self, src, width, height, **kwargs):
213 def __init__(self, src, width, height, **kwargs):
214 self.src = src
214 self.src = src
215 self.width = width
215 self.width = width
216 self.height = height
216 self.height = height
217 self.params = kwargs
217 self.params = kwargs
218
218
219 def _repr_html_(self):
219 def _repr_html_(self):
220 """return the embed iframe"""
220 """return the embed iframe"""
221 if self.params:
221 if self.params:
222 try:
222 try:
223 from urllib.parse import urlencode # Py 3
223 from urllib.parse import urlencode # Py 3
224 except ImportError:
224 except ImportError:
225 from urllib import urlencode
225 from urllib import urlencode
226 params = "?" + urlencode(self.params)
226 params = "?" + urlencode(self.params)
227 else:
227 else:
228 params = ""
228 params = ""
229 return self.iframe.format(src=self.src,
229 return self.iframe.format(src=self.src,
230 width=self.width,
230 width=self.width,
231 height=self.height,
231 height=self.height,
232 params=params)
232 params=params)
233
233
234 class YouTubeVideo(IFrame):
234 class YouTubeVideo(IFrame):
235 """Class for embedding a YouTube Video in an IPython session, based on its video id.
235 """Class for embedding a YouTube Video in an IPython session, based on its video id.
236
236
237 e.g. to embed the video from https://www.youtube.com/watch?v=foo , you would
237 e.g. to embed the video from https://www.youtube.com/watch?v=foo , you would
238 do::
238 do::
239
239
240 vid = YouTubeVideo("foo")
240 vid = YouTubeVideo("foo")
241 display(vid)
241 display(vid)
242
242
243 To start from 30 seconds::
243 To start from 30 seconds::
244
244
245 vid = YouTubeVideo("abc", start=30)
245 vid = YouTubeVideo("abc", start=30)
246 display(vid)
246 display(vid)
247
247
248 To calculate seconds from time as hours, minutes, seconds use
248 To calculate seconds from time as hours, minutes, seconds use
249 :class:`datetime.timedelta`::
249 :class:`datetime.timedelta`::
250
250
251 start=int(timedelta(hours=1, minutes=46, seconds=40).total_seconds())
251 start=int(timedelta(hours=1, minutes=46, seconds=40).total_seconds())
252
252
253 Other parameters can be provided as documented at
253 Other parameters can be provided as documented at
254 https://developers.google.com/youtube/player_parameters#parameter-subheader
254 https://developers.google.com/youtube/player_parameters#parameter-subheader
255
255
256 When converting the notebook using nbconvert, a jpeg representation of the video
256 When converting the notebook using nbconvert, a jpeg representation of the video
257 will be inserted in the document.
257 will be inserted in the document.
258 """
258 """
259
259
260 def __init__(self, id, width=400, height=300, **kwargs):
260 def __init__(self, id, width=400, height=300, **kwargs):
261 self.id=id
261 self.id=id
262 src = "https://www.youtube.com/embed/{0}".format(id)
262 src = "https://www.youtube.com/embed/{0}".format(id)
263 super(YouTubeVideo, self).__init__(src, width, height, **kwargs)
263 super(YouTubeVideo, self).__init__(src, width, height, **kwargs)
264
264
265 def _repr_jpeg_(self):
265 def _repr_jpeg_(self):
266 try:
266 # Deferred import
267 from urllib.request import urlopen # Py3
267 from urllib.request import urlopen
268 except ImportError:
268
269 from urllib2 import urlopen
270 try:
269 try:
271 return urlopen("https://img.youtube.com/vi/{id}/hqdefault.jpg".format(id=self.id)).read()
270 return urlopen("https://img.youtube.com/vi/{id}/hqdefault.jpg".format(id=self.id)).read()
272 except IOError:
271 except IOError:
273 return None
272 return None
274
273
275 class VimeoVideo(IFrame):
274 class VimeoVideo(IFrame):
276 """
275 """
277 Class for embedding a Vimeo video in an IPython session, based on its video id.
276 Class for embedding a Vimeo video in an IPython session, based on its video id.
278 """
277 """
279
278
280 def __init__(self, id, width=400, height=300, **kwargs):
279 def __init__(self, id, width=400, height=300, **kwargs):
281 src="https://player.vimeo.com/video/{0}".format(id)
280 src="https://player.vimeo.com/video/{0}".format(id)
282 super(VimeoVideo, self).__init__(src, width, height, **kwargs)
281 super(VimeoVideo, self).__init__(src, width, height, **kwargs)
283
282
284 class ScribdDocument(IFrame):
283 class ScribdDocument(IFrame):
285 """
284 """
286 Class for embedding a Scribd document in an IPython session
285 Class for embedding a Scribd document in an IPython session
287
286
288 Use the start_page params to specify a starting point in the document
287 Use the start_page params to specify a starting point in the document
289 Use the view_mode params to specify display type one off scroll | slideshow | book
288 Use the view_mode params to specify display type one off scroll | slideshow | book
290
289
291 e.g to Display Wes' foundational paper about PANDAS in book mode from page 3
290 e.g to Display Wes' foundational paper about PANDAS in book mode from page 3
292
291
293 ScribdDocument(71048089, width=800, height=400, start_page=3, view_mode="book")
292 ScribdDocument(71048089, width=800, height=400, start_page=3, view_mode="book")
294 """
293 """
295
294
296 def __init__(self, id, width=400, height=300, **kwargs):
295 def __init__(self, id, width=400, height=300, **kwargs):
297 src="https://www.scribd.com/embeds/{0}/content".format(id)
296 src="https://www.scribd.com/embeds/{0}/content".format(id)
298 super(ScribdDocument, self).__init__(src, width, height, **kwargs)
297 super(ScribdDocument, self).__init__(src, width, height, **kwargs)
299
298
300 class FileLink(object):
299 class FileLink(object):
301 """Class for embedding a local file link in an IPython session, based on path
300 """Class for embedding a local file link in an IPython session, based on path
302
301
303 e.g. to embed a link that was generated in the IPython notebook as my/data.txt
302 e.g. to embed a link that was generated in the IPython notebook as my/data.txt
304
303
305 you would do::
304 you would do::
306
305
307 local_file = FileLink("my/data.txt")
306 local_file = FileLink("my/data.txt")
308 display(local_file)
307 display(local_file)
309
308
310 or in the HTML notebook, just::
309 or in the HTML notebook, just::
311
310
312 FileLink("my/data.txt")
311 FileLink("my/data.txt")
313 """
312 """
314
313
315 html_link_str = "<a href='%s' target='_blank'>%s</a>"
314 html_link_str = "<a href='%s' target='_blank'>%s</a>"
316
315
317 def __init__(self,
316 def __init__(self,
318 path,
317 path,
319 url_prefix='',
318 url_prefix='',
320 result_html_prefix='',
319 result_html_prefix='',
321 result_html_suffix='<br>'):
320 result_html_suffix='<br>'):
322 """
321 """
323 Parameters
322 Parameters
324 ----------
323 ----------
325 path : str
324 path : str
326 path to the file or directory that should be formatted
325 path to the file or directory that should be formatted
327 directory_prefix : str
326 directory_prefix : str
328 prefix to be prepended to all files to form a working link [default:
327 prefix to be prepended to all files to form a working link [default:
329 'files']
328 'files']
330 result_html_prefix : str
329 result_html_prefix : str
331 text to append to beginning to link [default: none]
330 text to append to beginning to link [default: none]
332 result_html_suffix : str
331 result_html_suffix : str
333 text to append at the end of link [default: '<br>']
332 text to append at the end of link [default: '<br>']
334 """
333 """
335 if isdir(path):
334 if isdir(path):
336 raise ValueError("Cannot display a directory using FileLink. "
335 raise ValueError("Cannot display a directory using FileLink. "
337 "Use FileLinks to display '%s'." % path)
336 "Use FileLinks to display '%s'." % path)
338 self.path = path
337 self.path = path
339 self.url_prefix = url_prefix
338 self.url_prefix = url_prefix
340 self.result_html_prefix = result_html_prefix
339 self.result_html_prefix = result_html_prefix
341 self.result_html_suffix = result_html_suffix
340 self.result_html_suffix = result_html_suffix
342
341
343 def _format_path(self):
342 def _format_path(self):
344 fp = ''.join([self.url_prefix,self.path])
343 fp = ''.join([self.url_prefix,self.path])
345 return ''.join([self.result_html_prefix,
344 return ''.join([self.result_html_prefix,
346 self.html_link_str % (fp, self.path),
345 self.html_link_str % (fp, self.path),
347 self.result_html_suffix])
346 self.result_html_suffix])
348
347
349 def _repr_html_(self):
348 def _repr_html_(self):
350 """return html link to file
349 """return html link to file
351 """
350 """
352 if not exists(self.path):
351 if not exists(self.path):
353 return ("Path (<tt>%s</tt>) doesn't exist. "
352 return ("Path (<tt>%s</tt>) doesn't exist. "
354 "It may still be in the process of "
353 "It may still be in the process of "
355 "being generated, or you may have the "
354 "being generated, or you may have the "
356 "incorrect path." % self.path)
355 "incorrect path." % self.path)
357
356
358 return self._format_path()
357 return self._format_path()
359
358
360 def __repr__(self):
359 def __repr__(self):
361 """return absolute path to file
360 """return absolute path to file
362 """
361 """
363 return abspath(self.path)
362 return abspath(self.path)
364
363
365 class FileLinks(FileLink):
364 class FileLinks(FileLink):
366 """Class for embedding local file links in an IPython session, based on path
365 """Class for embedding local file links in an IPython session, based on path
367
366
368 e.g. to embed links to files that were generated in the IPython notebook
367 e.g. to embed links to files that were generated in the IPython notebook
369 under ``my/data``, you would do::
368 under ``my/data``, you would do::
370
369
371 local_files = FileLinks("my/data")
370 local_files = FileLinks("my/data")
372 display(local_files)
371 display(local_files)
373
372
374 or in the HTML notebook, just::
373 or in the HTML notebook, just::
375
374
376 FileLinks("my/data")
375 FileLinks("my/data")
377 """
376 """
378 def __init__(self,
377 def __init__(self,
379 path,
378 path,
380 url_prefix='',
379 url_prefix='',
381 included_suffixes=None,
380 included_suffixes=None,
382 result_html_prefix='',
381 result_html_prefix='',
383 result_html_suffix='<br>',
382 result_html_suffix='<br>',
384 notebook_display_formatter=None,
383 notebook_display_formatter=None,
385 terminal_display_formatter=None,
384 terminal_display_formatter=None,
386 recursive=True):
385 recursive=True):
387 """
386 """
388 See :class:`FileLink` for the ``path``, ``url_prefix``,
387 See :class:`FileLink` for the ``path``, ``url_prefix``,
389 ``result_html_prefix`` and ``result_html_suffix`` parameters.
388 ``result_html_prefix`` and ``result_html_suffix`` parameters.
390
389
391 included_suffixes : list
390 included_suffixes : list
392 Filename suffixes to include when formatting output [default: include
391 Filename suffixes to include when formatting output [default: include
393 all files]
392 all files]
394
393
395 notebook_display_formatter : function
394 notebook_display_formatter : function
396 Used to format links for display in the notebook. See discussion of
395 Used to format links for display in the notebook. See discussion of
397 formatter functions below.
396 formatter functions below.
398
397
399 terminal_display_formatter : function
398 terminal_display_formatter : function
400 Used to format links for display in the terminal. See discussion of
399 Used to format links for display in the terminal. See discussion of
401 formatter functions below.
400 formatter functions below.
402
401
403 Formatter functions must be of the form::
402 Formatter functions must be of the form::
404
403
405 f(dirname, fnames, included_suffixes)
404 f(dirname, fnames, included_suffixes)
406
405
407 dirname : str
406 dirname : str
408 The name of a directory
407 The name of a directory
409 fnames : list
408 fnames : list
410 The files in that directory
409 The files in that directory
411 included_suffixes : list
410 included_suffixes : list
412 The file suffixes that should be included in the output (passing None
411 The file suffixes that should be included in the output (passing None
413 meansto include all suffixes in the output in the built-in formatters)
412 meansto include all suffixes in the output in the built-in formatters)
414 recursive : boolean
413 recursive : boolean
415 Whether to recurse into subdirectories. Default is True.
414 Whether to recurse into subdirectories. Default is True.
416
415
417 The function should return a list of lines that will be printed in the
416 The function should return a list of lines that will be printed in the
418 notebook (if passing notebook_display_formatter) or the terminal (if
417 notebook (if passing notebook_display_formatter) or the terminal (if
419 passing terminal_display_formatter). This function is iterated over for
418 passing terminal_display_formatter). This function is iterated over for
420 each directory in self.path. Default formatters are in place, can be
419 each directory in self.path. Default formatters are in place, can be
421 passed here to support alternative formatting.
420 passed here to support alternative formatting.
422
421
423 """
422 """
424 if isfile(path):
423 if isfile(path):
425 raise ValueError("Cannot display a file using FileLinks. "
424 raise ValueError("Cannot display a file using FileLinks. "
426 "Use FileLink to display '%s'." % path)
425 "Use FileLink to display '%s'." % path)
427 self.included_suffixes = included_suffixes
426 self.included_suffixes = included_suffixes
428 # remove trailing slashs for more consistent output formatting
427 # remove trailing slashs for more consistent output formatting
429 path = path.rstrip('/')
428 path = path.rstrip('/')
430
429
431 self.path = path
430 self.path = path
432 self.url_prefix = url_prefix
431 self.url_prefix = url_prefix
433 self.result_html_prefix = result_html_prefix
432 self.result_html_prefix = result_html_prefix
434 self.result_html_suffix = result_html_suffix
433 self.result_html_suffix = result_html_suffix
435
434
436 self.notebook_display_formatter = \
435 self.notebook_display_formatter = \
437 notebook_display_formatter or self._get_notebook_display_formatter()
436 notebook_display_formatter or self._get_notebook_display_formatter()
438 self.terminal_display_formatter = \
437 self.terminal_display_formatter = \
439 terminal_display_formatter or self._get_terminal_display_formatter()
438 terminal_display_formatter or self._get_terminal_display_formatter()
440
439
441 self.recursive = recursive
440 self.recursive = recursive
442
441
443 def _get_display_formatter(self,
442 def _get_display_formatter(self,
444 dirname_output_format,
443 dirname_output_format,
445 fname_output_format,
444 fname_output_format,
446 fp_format,
445 fp_format,
447 fp_cleaner=None):
446 fp_cleaner=None):
448 """ generate built-in formatter function
447 """ generate built-in formatter function
449
448
450 this is used to define both the notebook and terminal built-in
449 this is used to define both the notebook and terminal built-in
451 formatters as they only differ by some wrapper text for each entry
450 formatters as they only differ by some wrapper text for each entry
452
451
453 dirname_output_format: string to use for formatting directory
452 dirname_output_format: string to use for formatting directory
454 names, dirname will be substituted for a single "%s" which
453 names, dirname will be substituted for a single "%s" which
455 must appear in this string
454 must appear in this string
456 fname_output_format: string to use for formatting file names,
455 fname_output_format: string to use for formatting file names,
457 if a single "%s" appears in the string, fname will be substituted
456 if a single "%s" appears in the string, fname will be substituted
458 if two "%s" appear in the string, the path to fname will be
457 if two "%s" appear in the string, the path to fname will be
459 substituted for the first and fname will be substituted for the
458 substituted for the first and fname will be substituted for the
460 second
459 second
461 fp_format: string to use for formatting filepaths, must contain
460 fp_format: string to use for formatting filepaths, must contain
462 exactly two "%s" and the dirname will be subsituted for the first
461 exactly two "%s" and the dirname will be subsituted for the first
463 and fname will be substituted for the second
462 and fname will be substituted for the second
464 """
463 """
465 def f(dirname, fnames, included_suffixes=None):
464 def f(dirname, fnames, included_suffixes=None):
466 result = []
465 result = []
467 # begin by figuring out which filenames, if any,
466 # begin by figuring out which filenames, if any,
468 # are going to be displayed
467 # are going to be displayed
469 display_fnames = []
468 display_fnames = []
470 for fname in fnames:
469 for fname in fnames:
471 if (isfile(join(dirname,fname)) and
470 if (isfile(join(dirname,fname)) and
472 (included_suffixes is None or
471 (included_suffixes is None or
473 splitext(fname)[1] in included_suffixes)):
472 splitext(fname)[1] in included_suffixes)):
474 display_fnames.append(fname)
473 display_fnames.append(fname)
475
474
476 if len(display_fnames) == 0:
475 if len(display_fnames) == 0:
477 # if there are no filenames to display, don't print anything
476 # if there are no filenames to display, don't print anything
478 # (not even the directory name)
477 # (not even the directory name)
479 pass
478 pass
480 else:
479 else:
481 # otherwise print the formatted directory name followed by
480 # otherwise print the formatted directory name followed by
482 # the formatted filenames
481 # the formatted filenames
483 dirname_output_line = dirname_output_format % dirname
482 dirname_output_line = dirname_output_format % dirname
484 result.append(dirname_output_line)
483 result.append(dirname_output_line)
485 for fname in display_fnames:
484 for fname in display_fnames:
486 fp = fp_format % (dirname,fname)
485 fp = fp_format % (dirname,fname)
487 if fp_cleaner is not None:
486 if fp_cleaner is not None:
488 fp = fp_cleaner(fp)
487 fp = fp_cleaner(fp)
489 try:
488 try:
490 # output can include both a filepath and a filename...
489 # output can include both a filepath and a filename...
491 fname_output_line = fname_output_format % (fp, fname)
490 fname_output_line = fname_output_format % (fp, fname)
492 except TypeError:
491 except TypeError:
493 # ... or just a single filepath
492 # ... or just a single filepath
494 fname_output_line = fname_output_format % fname
493 fname_output_line = fname_output_format % fname
495 result.append(fname_output_line)
494 result.append(fname_output_line)
496 return result
495 return result
497 return f
496 return f
498
497
499 def _get_notebook_display_formatter(self,
498 def _get_notebook_display_formatter(self,
500 spacer="&nbsp;&nbsp;"):
499 spacer="&nbsp;&nbsp;"):
501 """ generate function to use for notebook formatting
500 """ generate function to use for notebook formatting
502 """
501 """
503 dirname_output_format = \
502 dirname_output_format = \
504 self.result_html_prefix + "%s/" + self.result_html_suffix
503 self.result_html_prefix + "%s/" + self.result_html_suffix
505 fname_output_format = \
504 fname_output_format = \
506 self.result_html_prefix + spacer + self.html_link_str + self.result_html_suffix
505 self.result_html_prefix + spacer + self.html_link_str + self.result_html_suffix
507 fp_format = self.url_prefix + '%s/%s'
506 fp_format = self.url_prefix + '%s/%s'
508 if sep == "\\":
507 if sep == "\\":
509 # Working on a platform where the path separator is "\", so
508 # Working on a platform where the path separator is "\", so
510 # must convert these to "/" for generating a URI
509 # must convert these to "/" for generating a URI
511 def fp_cleaner(fp):
510 def fp_cleaner(fp):
512 # Replace all occurences of backslash ("\") with a forward
511 # Replace all occurences of backslash ("\") with a forward
513 # slash ("/") - this is necessary on windows when a path is
512 # slash ("/") - this is necessary on windows when a path is
514 # provided as input, but we must link to a URI
513 # provided as input, but we must link to a URI
515 return fp.replace('\\','/')
514 return fp.replace('\\','/')
516 else:
515 else:
517 fp_cleaner = None
516 fp_cleaner = None
518
517
519 return self._get_display_formatter(dirname_output_format,
518 return self._get_display_formatter(dirname_output_format,
520 fname_output_format,
519 fname_output_format,
521 fp_format,
520 fp_format,
522 fp_cleaner)
521 fp_cleaner)
523
522
524 def _get_terminal_display_formatter(self,
523 def _get_terminal_display_formatter(self,
525 spacer=" "):
524 spacer=" "):
526 """ generate function to use for terminal formatting
525 """ generate function to use for terminal formatting
527 """
526 """
528 dirname_output_format = "%s/"
527 dirname_output_format = "%s/"
529 fname_output_format = spacer + "%s"
528 fname_output_format = spacer + "%s"
530 fp_format = '%s/%s'
529 fp_format = '%s/%s'
531
530
532 return self._get_display_formatter(dirname_output_format,
531 return self._get_display_formatter(dirname_output_format,
533 fname_output_format,
532 fname_output_format,
534 fp_format)
533 fp_format)
535
534
536 def _format_path(self):
535 def _format_path(self):
537 result_lines = []
536 result_lines = []
538 if self.recursive:
537 if self.recursive:
539 walked_dir = list(walk(self.path))
538 walked_dir = list(walk(self.path))
540 else:
539 else:
541 walked_dir = [next(walk(self.path))]
540 walked_dir = [next(walk(self.path))]
542 walked_dir.sort()
541 walked_dir.sort()
543 for dirname, subdirs, fnames in walked_dir:
542 for dirname, subdirs, fnames in walked_dir:
544 result_lines += self.notebook_display_formatter(dirname, fnames, self.included_suffixes)
543 result_lines += self.notebook_display_formatter(dirname, fnames, self.included_suffixes)
545 return '\n'.join(result_lines)
544 return '\n'.join(result_lines)
546
545
547 def __repr__(self):
546 def __repr__(self):
548 """return newline-separated absolute paths
547 """return newline-separated absolute paths
549 """
548 """
550 result_lines = []
549 result_lines = []
551 if self.recursive:
550 if self.recursive:
552 walked_dir = list(walk(self.path))
551 walked_dir = list(walk(self.path))
553 else:
552 else:
554 walked_dir = [next(walk(self.path))]
553 walked_dir = [next(walk(self.path))]
555 walked_dir.sort()
554 walked_dir.sort()
556 for dirname, subdirs, fnames in walked_dir:
555 for dirname, subdirs, fnames in walked_dir:
557 result_lines += self.terminal_display_formatter(dirname, fnames, self.included_suffixes)
556 result_lines += self.terminal_display_formatter(dirname, fnames, self.included_suffixes)
558 return '\n'.join(result_lines)
557 return '\n'.join(result_lines)
General Comments 0
You need to be logged in to leave comments. Login now