##// END OF EJS Templates
Merge pull request #13133 from yuji96/youtube-allow-autoplay...
Blazej Michalik -
r26781:100ff058 merge
parent child Browse files
Show More
@@ -0,0 +1,37 b''
1 Enable to add extra attributes to iframe
2 ========================================
3
4 You can add any extra attributes to the ``<iframe>`` tag
5 since the argument ``extras`` has been added to the ``IFrame`` class.
6 for example::
7
8 In [1]: from IPython.display import IFrame
9
10 In [2]: print(IFrame(src="src", width=300, height=300, extras=["hello", "world"])._repr_html_())
11
12 <iframe
13 width="300"
14 height="300"
15 src="src"
16 frameborder="0"
17 allowfullscreen
18 hello world
19 ></iframe>
20
21 Using it, you can autoplay ``YouTubeVideo`` by adding ``'allow="autoplay"'``,
22 even in browsers that disable it by default, such as Google Chrome.
23 And, you can write it more briefly by using the argument ``allow_autoplay``.
24 ::
25
26 In [1]: from IPython.display import YouTubeVideo
27
28 In [2]: print(YouTubeVideo("video-id", allow_autoplay=True)._repr_html_())
29
30 <iframe
31 width="400"
32 height="300"
33 src="https://www.youtube.com/embed/video-id?autoplay=1"
34 frameborder="0"
35 allowfullscreen
36 allow="autoplay"
37 ></iframe>
@@ -1,660 +1,672 b''
1 1 """Various display related classes.
2 2
3 3 Authors : MinRK, gregcaporaso, dannystaple
4 4 """
5 5 from html import escape as html_escape
6 6 from os.path import exists, isfile, splitext, abspath, join, isdir
7 7 from os import walk, sep, fsdecode
8 8
9 9 from IPython.core.display import DisplayObject, TextDisplayObject
10 10
11 from typing import Tuple
11 from typing import Tuple, Iterable
12 12
13 13 __all__ = ['Audio', 'IFrame', 'YouTubeVideo', 'VimeoVideo', 'ScribdDocument',
14 14 'FileLink', 'FileLinks', 'Code']
15 15
16 16
17 17 class Audio(DisplayObject):
18 18 """Create an audio object.
19 19
20 20 When this object is returned by an input cell or passed to the
21 21 display function, it will result in Audio controls being displayed
22 22 in the frontend (only works in the notebook).
23 23
24 24 Parameters
25 25 ----------
26 26 data : numpy array, list, unicode, str or bytes
27 27 Can be one of
28 28
29 29 * Numpy 1d array containing the desired waveform (mono)
30 30 * Numpy 2d array containing waveforms for each channel.
31 31 Shape=(NCHAN, NSAMPLES). For the standard channel order, see
32 32 http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
33 33 * List of float or integer representing the waveform (mono)
34 34 * String containing the filename
35 35 * Bytestring containing raw PCM data or
36 36 * URL pointing to a file on the web.
37 37
38 38 If the array option is used, the waveform will be normalized.
39 39
40 40 If a filename or url is used, the format support will be browser
41 41 dependent.
42 42 url : unicode
43 43 A URL to download the data from.
44 44 filename : unicode
45 45 Path to a local file to load the data from.
46 46 embed : boolean
47 47 Should the audio data be embedded using a data URI (True) or should
48 48 the original source be referenced. Set this to True if you want the
49 49 audio to playable later with no internet connection in the notebook.
50 50
51 51 Default is `True`, unless the keyword argument `url` is set, then
52 52 default value is `False`.
53 53 rate : integer
54 54 The sampling rate of the raw data.
55 55 Only required when data parameter is being used as an array
56 56 autoplay : bool
57 57 Set to True if the audio should immediately start playing.
58 58 Default is `False`.
59 59 normalize : bool
60 60 Whether audio should be normalized (rescaled) to the maximum possible
61 61 range. Default is `True`. When set to `False`, `data` must be between
62 62 -1 and 1 (inclusive), otherwise an error is raised.
63 63 Applies only when `data` is a list or array of samples; other types of
64 64 audio are never normalized.
65 65
66 66 Examples
67 67 --------
68 68
69 69 Generate a sound
70 70
71 71 >>> import numpy as np
72 72 ... framerate = 44100
73 73 ... t = np.linspace(0,5,framerate*5)
74 74 ... data = np.sin(2*np.pi*220*t) + np.sin(2*np.pi*224*t)
75 75 ... Audio(data, rate=framerate)
76 76
77 77 Can also do stereo or more channels
78 78
79 79 >>> dataleft = np.sin(2*np.pi*220*t)
80 80 ... dataright = np.sin(2*np.pi*224*t)
81 81 ... Audio([dataleft, dataright], rate=framerate)
82 82
83 83 From URL:
84 84
85 85 >>> Audio("http://www.nch.com.au/acm/8k16bitpcm.wav")
86 86 >>> Audio(url="http://www.w3schools.com/html/horse.ogg")
87 87
88 88 From a File:
89 89
90 90 >>> Audio('/path/to/sound.wav')
91 91 >>> Audio(filename='/path/to/sound.ogg')
92 92
93 93 From Bytes:
94 94
95 95 >>> Audio(b'RAW_WAV_DATA..')
96 96 >>> Audio(data=b'RAW_WAV_DATA..')
97 97
98 98 See Also
99 99 --------
100 100 ipywidgets.Audio
101 101
102 102 AUdio widget with more more flexibility and options.
103 103
104 104 """
105 105 _read_flags = 'rb'
106 106
107 107 def __init__(self, data=None, filename=None, url=None, embed=None, rate=None, autoplay=False, normalize=True, *,
108 108 element_id=None):
109 109 if filename is None and url is None and data is None:
110 110 raise ValueError("No audio data found. Expecting filename, url, or data.")
111 111 if embed is False and url is None:
112 112 raise ValueError("No url found. Expecting url when embed=False")
113 113
114 114 if url is not None and embed is not True:
115 115 self.embed = False
116 116 else:
117 117 self.embed = True
118 118 self.autoplay = autoplay
119 119 self.element_id = element_id
120 120 super(Audio, self).__init__(data=data, url=url, filename=filename)
121 121
122 122 if self.data is not None and not isinstance(self.data, bytes):
123 123 if rate is None:
124 124 raise ValueError("rate must be specified when data is a numpy array or list of audio samples.")
125 125 self.data = Audio._make_wav(data, rate, normalize)
126 126
127 127 def reload(self):
128 128 """Reload the raw data from file or URL."""
129 129 import mimetypes
130 130 if self.embed:
131 131 super(Audio, self).reload()
132 132
133 133 if self.filename is not None:
134 134 self.mimetype = mimetypes.guess_type(self.filename)[0]
135 135 elif self.url is not None:
136 136 self.mimetype = mimetypes.guess_type(self.url)[0]
137 137 else:
138 138 self.mimetype = "audio/wav"
139 139
140 140 @staticmethod
141 141 def _make_wav(data, rate, normalize):
142 142 """ Transform a numpy array to a PCM bytestring """
143 143 from io import BytesIO
144 144 import wave
145 145
146 146 try:
147 147 scaled, nchan = Audio._validate_and_normalize_with_numpy(data, normalize)
148 148 except ImportError:
149 149 scaled, nchan = Audio._validate_and_normalize_without_numpy(data, normalize)
150 150
151 151 fp = BytesIO()
152 152 waveobj = wave.open(fp,mode='wb')
153 153 waveobj.setnchannels(nchan)
154 154 waveobj.setframerate(rate)
155 155 waveobj.setsampwidth(2)
156 156 waveobj.setcomptype('NONE','NONE')
157 157 waveobj.writeframes(scaled)
158 158 val = fp.getvalue()
159 159 waveobj.close()
160 160
161 161 return val
162 162
163 163 @staticmethod
164 164 def _validate_and_normalize_with_numpy(data, normalize) -> Tuple[bytes, int]:
165 165 import numpy as np
166 166
167 167 data = np.array(data, dtype=float)
168 168 if len(data.shape) == 1:
169 169 nchan = 1
170 170 elif len(data.shape) == 2:
171 171 # In wave files,channels are interleaved. E.g.,
172 172 # "L1R1L2R2..." for stereo. See
173 173 # http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
174 174 # for channel ordering
175 175 nchan = data.shape[0]
176 176 data = data.T.ravel()
177 177 else:
178 178 raise ValueError('Array audio input must be a 1D or 2D array')
179 179
180 180 max_abs_value = np.max(np.abs(data))
181 181 normalization_factor = Audio._get_normalization_factor(max_abs_value, normalize)
182 182 scaled = data / normalization_factor * 32767
183 183 return scaled.astype("<h").tobytes(), nchan
184 184
185 185 @staticmethod
186 186 def _validate_and_normalize_without_numpy(data, normalize):
187 187 import array
188 188 import sys
189 189
190 190 data = array.array('f', data)
191 191
192 192 try:
193 193 max_abs_value = float(max([abs(x) for x in data]))
194 194 except TypeError as e:
195 195 raise TypeError('Only lists of mono audio are '
196 196 'supported if numpy is not installed') from e
197 197
198 198 normalization_factor = Audio._get_normalization_factor(max_abs_value, normalize)
199 199 scaled = array.array('h', [int(x / normalization_factor * 32767) for x in data])
200 200 if sys.byteorder == 'big':
201 201 scaled.byteswap()
202 202 nchan = 1
203 203 return scaled.tobytes(), nchan
204 204
205 205 @staticmethod
206 206 def _get_normalization_factor(max_abs_value, normalize):
207 207 if not normalize and max_abs_value > 1:
208 208 raise ValueError('Audio data must be between -1 and 1 when normalize=False.')
209 209 return max_abs_value if normalize else 1
210 210
211 211 def _data_and_metadata(self):
212 212 """shortcut for returning metadata with url information, if defined"""
213 213 md = {}
214 214 if self.url:
215 215 md['url'] = self.url
216 216 if md:
217 217 return self.data, md
218 218 else:
219 219 return self.data
220 220
221 221 def _repr_html_(self):
222 222 src = """
223 223 <audio {element_id} controls="controls" {autoplay}>
224 224 <source src="{src}" type="{type}" />
225 225 Your browser does not support the audio element.
226 226 </audio>
227 227 """
228 228 return src.format(src=self.src_attr(), type=self.mimetype, autoplay=self.autoplay_attr(),
229 229 element_id=self.element_id_attr())
230 230
231 231 def src_attr(self):
232 232 import base64
233 233 if self.embed and (self.data is not None):
234 234 data = base64=base64.b64encode(self.data).decode('ascii')
235 235 return """data:{type};base64,{base64}""".format(type=self.mimetype,
236 236 base64=data)
237 237 elif self.url is not None:
238 238 return self.url
239 239 else:
240 240 return ""
241 241
242 242 def autoplay_attr(self):
243 243 if(self.autoplay):
244 244 return 'autoplay="autoplay"'
245 245 else:
246 246 return ''
247 247
248 248 def element_id_attr(self):
249 249 if (self.element_id):
250 250 return 'id="{element_id}"'.format(element_id=self.element_id)
251 251 else:
252 252 return ''
253 253
254 254 class IFrame(object):
255 255 """
256 256 Generic class to embed an iframe in an IPython notebook
257 257 """
258 258
259 259 iframe = """
260 260 <iframe
261 261 width="{width}"
262 262 height="{height}"
263 263 src="{src}{params}"
264 264 frameborder="0"
265 265 allowfullscreen
266 {extras}
266 267 ></iframe>
267 268 """
268 269
269 def __init__(self, src, width, height, **kwargs):
270 def __init__(self, src, width, height, extras: Iterable[str] = None, **kwargs):
271 if extras is None:
272 extras = []
273
270 274 self.src = src
271 275 self.width = width
272 276 self.height = height
277 self.extras = extras
273 278 self.params = kwargs
274 279
275 280 def _repr_html_(self):
276 281 """return the embed iframe"""
277 282 if self.params:
278 283 from urllib.parse import urlencode
279 284 params = "?" + urlencode(self.params)
280 285 else:
281 286 params = ""
282 return self.iframe.format(src=self.src,
283 width=self.width,
284 height=self.height,
285 params=params)
287 return self.iframe.format(
288 src=self.src,
289 width=self.width,
290 height=self.height,
291 params=params,
292 extras=" ".join(self.extras),
293 )
294
286 295
287 296 class YouTubeVideo(IFrame):
288 297 """Class for embedding a YouTube Video in an IPython session, based on its video id.
289 298
290 299 e.g. to embed the video from https://www.youtube.com/watch?v=foo , you would
291 300 do::
292 301
293 302 vid = YouTubeVideo("foo")
294 303 display(vid)
295 304
296 305 To start from 30 seconds::
297 306
298 307 vid = YouTubeVideo("abc", start=30)
299 308 display(vid)
300 309
301 310 To calculate seconds from time as hours, minutes, seconds use
302 311 :class:`datetime.timedelta`::
303 312
304 313 start=int(timedelta(hours=1, minutes=46, seconds=40).total_seconds())
305 314
306 315 Other parameters can be provided as documented at
307 316 https://developers.google.com/youtube/player_parameters#Parameters
308 317
309 318 When converting the notebook using nbconvert, a jpeg representation of the video
310 319 will be inserted in the document.
311 320 """
312 321
313 def __init__(self, id, width=400, height=300, **kwargs):
322 def __init__(self, id, width=400, height=300, allow_autoplay=False, **kwargs):
314 323 self.id=id
315 324 src = "https://www.youtube.com/embed/{0}".format(id)
325 if allow_autoplay:
326 extras = list(kwargs.get("extras", [])) + ['allow="autoplay"']
327 kwargs.update(autoplay=1, extras=extras)
316 328 super(YouTubeVideo, self).__init__(src, width, height, **kwargs)
317
329
318 330 def _repr_jpeg_(self):
319 331 # Deferred import
320 332 from urllib.request import urlopen
321 333
322 334 try:
323 335 return urlopen("https://img.youtube.com/vi/{id}/hqdefault.jpg".format(id=self.id)).read()
324 336 except IOError:
325 337 return None
326 338
327 339 class VimeoVideo(IFrame):
328 340 """
329 341 Class for embedding a Vimeo video in an IPython session, based on its video id.
330 342 """
331 343
332 344 def __init__(self, id, width=400, height=300, **kwargs):
333 345 src="https://player.vimeo.com/video/{0}".format(id)
334 346 super(VimeoVideo, self).__init__(src, width, height, **kwargs)
335 347
336 348 class ScribdDocument(IFrame):
337 349 """
338 350 Class for embedding a Scribd document in an IPython session
339 351
340 352 Use the start_page params to specify a starting point in the document
341 353 Use the view_mode params to specify display type one off scroll | slideshow | book
342 354
343 355 e.g to Display Wes' foundational paper about PANDAS in book mode from page 3
344 356
345 357 ScribdDocument(71048089, width=800, height=400, start_page=3, view_mode="book")
346 358 """
347 359
348 360 def __init__(self, id, width=400, height=300, **kwargs):
349 361 src="https://www.scribd.com/embeds/{0}/content".format(id)
350 362 super(ScribdDocument, self).__init__(src, width, height, **kwargs)
351 363
352 364 class FileLink(object):
353 365 """Class for embedding a local file link in an IPython session, based on path
354 366
355 367 e.g. to embed a link that was generated in the IPython notebook as my/data.txt
356 368
357 369 you would do::
358 370
359 371 local_file = FileLink("my/data.txt")
360 372 display(local_file)
361 373
362 374 or in the HTML notebook, just::
363 375
364 376 FileLink("my/data.txt")
365 377 """
366 378
367 379 html_link_str = "<a href='%s' target='_blank'>%s</a>"
368 380
369 381 def __init__(self,
370 382 path,
371 383 url_prefix='',
372 384 result_html_prefix='',
373 385 result_html_suffix='<br>'):
374 386 """
375 387 Parameters
376 388 ----------
377 389 path : str
378 390 path to the file or directory that should be formatted
379 391 url_prefix : str
380 392 prefix to be prepended to all files to form a working link [default:
381 393 '']
382 394 result_html_prefix : str
383 395 text to append to beginning to link [default: '']
384 396 result_html_suffix : str
385 397 text to append at the end of link [default: '<br>']
386 398 """
387 399 if isdir(path):
388 400 raise ValueError("Cannot display a directory using FileLink. "
389 401 "Use FileLinks to display '%s'." % path)
390 402 self.path = fsdecode(path)
391 403 self.url_prefix = url_prefix
392 404 self.result_html_prefix = result_html_prefix
393 405 self.result_html_suffix = result_html_suffix
394 406
395 407 def _format_path(self):
396 408 fp = ''.join([self.url_prefix, html_escape(self.path)])
397 409 return ''.join([self.result_html_prefix,
398 410 self.html_link_str % \
399 411 (fp, html_escape(self.path, quote=False)),
400 412 self.result_html_suffix])
401 413
402 414 def _repr_html_(self):
403 415 """return html link to file
404 416 """
405 417 if not exists(self.path):
406 418 return ("Path (<tt>%s</tt>) doesn't exist. "
407 419 "It may still be in the process of "
408 420 "being generated, or you may have the "
409 421 "incorrect path." % self.path)
410 422
411 423 return self._format_path()
412 424
413 425 def __repr__(self):
414 426 """return absolute path to file
415 427 """
416 428 return abspath(self.path)
417 429
418 430 class FileLinks(FileLink):
419 431 """Class for embedding local file links in an IPython session, based on path
420 432
421 433 e.g. to embed links to files that were generated in the IPython notebook
422 434 under ``my/data``, you would do::
423 435
424 436 local_files = FileLinks("my/data")
425 437 display(local_files)
426 438
427 439 or in the HTML notebook, just::
428 440
429 441 FileLinks("my/data")
430 442 """
431 443 def __init__(self,
432 444 path,
433 445 url_prefix='',
434 446 included_suffixes=None,
435 447 result_html_prefix='',
436 448 result_html_suffix='<br>',
437 449 notebook_display_formatter=None,
438 450 terminal_display_formatter=None,
439 451 recursive=True):
440 452 """
441 453 See :class:`FileLink` for the ``path``, ``url_prefix``,
442 454 ``result_html_prefix`` and ``result_html_suffix`` parameters.
443 455
444 456 included_suffixes : list
445 457 Filename suffixes to include when formatting output [default: include
446 458 all files]
447 459
448 460 notebook_display_formatter : function
449 461 Used to format links for display in the notebook. See discussion of
450 462 formatter functions below.
451 463
452 464 terminal_display_formatter : function
453 465 Used to format links for display in the terminal. See discussion of
454 466 formatter functions below.
455 467
456 468 Formatter functions must be of the form::
457 469
458 470 f(dirname, fnames, included_suffixes)
459 471
460 472 dirname : str
461 473 The name of a directory
462 474 fnames : list
463 475 The files in that directory
464 476 included_suffixes : list
465 477 The file suffixes that should be included in the output (passing None
466 478 meansto include all suffixes in the output in the built-in formatters)
467 479 recursive : boolean
468 480 Whether to recurse into subdirectories. Default is True.
469 481
470 482 The function should return a list of lines that will be printed in the
471 483 notebook (if passing notebook_display_formatter) or the terminal (if
472 484 passing terminal_display_formatter). This function is iterated over for
473 485 each directory in self.path. Default formatters are in place, can be
474 486 passed here to support alternative formatting.
475 487
476 488 """
477 489 if isfile(path):
478 490 raise ValueError("Cannot display a file using FileLinks. "
479 491 "Use FileLink to display '%s'." % path)
480 492 self.included_suffixes = included_suffixes
481 493 # remove trailing slashes for more consistent output formatting
482 494 path = path.rstrip('/')
483 495
484 496 self.path = path
485 497 self.url_prefix = url_prefix
486 498 self.result_html_prefix = result_html_prefix
487 499 self.result_html_suffix = result_html_suffix
488 500
489 501 self.notebook_display_formatter = \
490 502 notebook_display_formatter or self._get_notebook_display_formatter()
491 503 self.terminal_display_formatter = \
492 504 terminal_display_formatter or self._get_terminal_display_formatter()
493 505
494 506 self.recursive = recursive
495 507
496 508 def _get_display_formatter(self,
497 509 dirname_output_format,
498 510 fname_output_format,
499 511 fp_format,
500 512 fp_cleaner=None):
501 513 """ generate built-in formatter function
502 514
503 515 this is used to define both the notebook and terminal built-in
504 516 formatters as they only differ by some wrapper text for each entry
505 517
506 518 dirname_output_format: string to use for formatting directory
507 519 names, dirname will be substituted for a single "%s" which
508 520 must appear in this string
509 521 fname_output_format: string to use for formatting file names,
510 522 if a single "%s" appears in the string, fname will be substituted
511 523 if two "%s" appear in the string, the path to fname will be
512 524 substituted for the first and fname will be substituted for the
513 525 second
514 526 fp_format: string to use for formatting filepaths, must contain
515 527 exactly two "%s" and the dirname will be substituted for the first
516 528 and fname will be substituted for the second
517 529 """
518 530 def f(dirname, fnames, included_suffixes=None):
519 531 result = []
520 532 # begin by figuring out which filenames, if any,
521 533 # are going to be displayed
522 534 display_fnames = []
523 535 for fname in fnames:
524 536 if (isfile(join(dirname,fname)) and
525 537 (included_suffixes is None or
526 538 splitext(fname)[1] in included_suffixes)):
527 539 display_fnames.append(fname)
528 540
529 541 if len(display_fnames) == 0:
530 542 # if there are no filenames to display, don't print anything
531 543 # (not even the directory name)
532 544 pass
533 545 else:
534 546 # otherwise print the formatted directory name followed by
535 547 # the formatted filenames
536 548 dirname_output_line = dirname_output_format % dirname
537 549 result.append(dirname_output_line)
538 550 for fname in display_fnames:
539 551 fp = fp_format % (dirname,fname)
540 552 if fp_cleaner is not None:
541 553 fp = fp_cleaner(fp)
542 554 try:
543 555 # output can include both a filepath and a filename...
544 556 fname_output_line = fname_output_format % (fp, fname)
545 557 except TypeError:
546 558 # ... or just a single filepath
547 559 fname_output_line = fname_output_format % fname
548 560 result.append(fname_output_line)
549 561 return result
550 562 return f
551 563
552 564 def _get_notebook_display_formatter(self,
553 565 spacer="&nbsp;&nbsp;"):
554 566 """ generate function to use for notebook formatting
555 567 """
556 568 dirname_output_format = \
557 569 self.result_html_prefix + "%s/" + self.result_html_suffix
558 570 fname_output_format = \
559 571 self.result_html_prefix + spacer + self.html_link_str + self.result_html_suffix
560 572 fp_format = self.url_prefix + '%s/%s'
561 573 if sep == "\\":
562 574 # Working on a platform where the path separator is "\", so
563 575 # must convert these to "/" for generating a URI
564 576 def fp_cleaner(fp):
565 577 # Replace all occurrences of backslash ("\") with a forward
566 578 # slash ("/") - this is necessary on windows when a path is
567 579 # provided as input, but we must link to a URI
568 580 return fp.replace('\\','/')
569 581 else:
570 582 fp_cleaner = None
571 583
572 584 return self._get_display_formatter(dirname_output_format,
573 585 fname_output_format,
574 586 fp_format,
575 587 fp_cleaner)
576 588
577 589 def _get_terminal_display_formatter(self,
578 590 spacer=" "):
579 591 """ generate function to use for terminal formatting
580 592 """
581 593 dirname_output_format = "%s/"
582 594 fname_output_format = spacer + "%s"
583 595 fp_format = '%s/%s'
584 596
585 597 return self._get_display_formatter(dirname_output_format,
586 598 fname_output_format,
587 599 fp_format)
588 600
589 601 def _format_path(self):
590 602 result_lines = []
591 603 if self.recursive:
592 604 walked_dir = list(walk(self.path))
593 605 else:
594 606 walked_dir = [next(walk(self.path))]
595 607 walked_dir.sort()
596 608 for dirname, subdirs, fnames in walked_dir:
597 609 result_lines += self.notebook_display_formatter(dirname, fnames, self.included_suffixes)
598 610 return '\n'.join(result_lines)
599 611
600 612 def __repr__(self):
601 613 """return newline-separated absolute paths
602 614 """
603 615 result_lines = []
604 616 if self.recursive:
605 617 walked_dir = list(walk(self.path))
606 618 else:
607 619 walked_dir = [next(walk(self.path))]
608 620 walked_dir.sort()
609 621 for dirname, subdirs, fnames in walked_dir:
610 622 result_lines += self.terminal_display_formatter(dirname, fnames, self.included_suffixes)
611 623 return '\n'.join(result_lines)
612 624
613 625
614 626 class Code(TextDisplayObject):
615 627 """Display syntax-highlighted source code.
616 628
617 629 This uses Pygments to highlight the code for HTML and Latex output.
618 630
619 631 Parameters
620 632 ----------
621 633 data : str
622 634 The code as a string
623 635 url : str
624 636 A URL to fetch the code from
625 637 filename : str
626 638 A local filename to load the code from
627 639 language : str
628 640 The short name of a Pygments lexer to use for highlighting.
629 641 If not specified, it will guess the lexer based on the filename
630 642 or the code. Available lexers: http://pygments.org/docs/lexers/
631 643 """
632 644 def __init__(self, data=None, url=None, filename=None, language=None):
633 645 self.language = language
634 646 super().__init__(data=data, url=url, filename=filename)
635 647
636 648 def _get_lexer(self):
637 649 if self.language:
638 650 from pygments.lexers import get_lexer_by_name
639 651 return get_lexer_by_name(self.language)
640 652 elif self.filename:
641 653 from pygments.lexers import get_lexer_for_filename
642 654 return get_lexer_for_filename(self.filename)
643 655 else:
644 656 from pygments.lexers import guess_lexer
645 657 return guess_lexer(self.data)
646 658
647 659 def __repr__(self):
648 660 return self.data
649 661
650 662 def _repr_html_(self):
651 663 from pygments import highlight
652 664 from pygments.formatters import HtmlFormatter
653 665 fmt = HtmlFormatter()
654 666 style = '<style>{}</style>'.format(fmt.get_style_defs('.output_html'))
655 667 return style + highlight(self.data, self._get_lexer(), fmt)
656 668
657 669 def _repr_latex_(self):
658 670 from pygments import highlight
659 671 from pygments.formatters import LatexFormatter
660 672 return highlight(self.data, self._get_lexer(), LatexFormatter())
General Comments 0
You need to be logged in to leave comments. Login now