display.py
621 lines
| 22.3 KiB
| text/x-python
|
PythonLexer
Brian E. Granger
|
r4408 | """Various display related classes. | ||
Greg Caporaso
|
r8798 | Authors : MinRK, gregcaporaso, dannystaple | ||
Brian E. Granger
|
r4408 | """ | ||
Cristian Ciupitu
|
r24230 | from html import escape as html_escape | ||
Greg Caporaso
|
r8800 | from os.path import exists, isfile, splitext, abspath, join, isdir | ||
Cristian Ciupitu
|
r24227 | from os import walk, sep, fsdecode | ||
Greg Caporaso
|
r8272 | |||
Thomas Kluyver
|
r24130 | from IPython.core.display import DisplayObject, TextDisplayObject | ||
David Österberg
|
r12829 | |||
Thomas Kluyver
|
r17121 | __all__ = ['Audio', 'IFrame', 'YouTubeVideo', 'VimeoVideo', 'ScribdDocument', | ||
Thomas Kluyver
|
r24130 | 'FileLink', 'FileLinks', 'Code'] | ||
Thomas Kluyver
|
r17121 | |||
David Österberg
|
r12829 | |||
class Audio(DisplayObject): | ||||
"""Create an audio object. | ||||
When this object is returned by an input cell or passed to the | ||||
display function, it will result in Audio controls being displayed | ||||
in the frontend (only works in the notebook). | ||||
Erik Tollerud
|
r16550 | |||
David Österberg
|
r12829 | Parameters | ||
---------- | ||||
David Österberg
|
r12968 | data : numpy array, list, unicode, str or bytes | ||
Erik Tollerud
|
r16551 | Can be one of | ||
* Numpy 1d array containing the desired waveform (mono) | ||||
* Numpy 2d array containing waveforms for each channel. | ||||
Shape=(NCHAN, NSAMPLES). For the standard channel order, see | ||||
http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx | ||||
* List of float or integer representing the waveform (mono) | ||||
* String containing the filename | ||||
* Bytestring containing raw PCM data or | ||||
* URL pointing to a file on the web. | ||||
Erik Tollerud
|
r16550 | |||
Jan S. (Milania1)
|
r24871 | If the array option is used, the waveform will be normalized. | ||
Erik Tollerud
|
r16550 | |||
Jan S. (Milania1)
|
r24871 | If a filename or url is used, the format support will be browser | ||
Erik Tollerud
|
r16550 | dependent. | ||
David Österberg
|
r12829 | url : unicode | ||
A URL to download the data from. | ||||
filename : unicode | ||||
Path to a local file to load the data from. | ||||
embed : boolean | ||||
Jonas Rauber
|
r22201 | Should the audio data be embedded using a data URI (True) or should | ||
Erik Tollerud
|
r16550 | the original source be referenced. Set this to True if you want the | ||
David Österberg
|
r12834 | audio to playable later with no internet connection in the notebook. | ||
David Österberg
|
r12829 | |||
Default is `True`, unless the keyword argument `url` is set, then | ||||
default value is `False`. | ||||
rate : integer | ||||
The sampling rate of the raw data. | ||||
Only required when data parameter is being used as an array | ||||
autoplay : bool | ||||
Set to True if the audio should immediately start playing. | ||||
Default is `False`. | ||||
Examples | ||||
-------- | ||||
Thomas Kluyver
|
r13587 | :: | ||
# Generate a sound | ||||
import numpy as np | ||||
framerate = 44100 | ||||
t = np.linspace(0,5,framerate*5) | ||||
Jan S. (Milania1)
|
r24871 | data = np.sin(2*np.pi*220*t) + np.sin(2*np.pi*224*t) | ||
Thomas Kluyver
|
r13587 | Audio(data,rate=framerate) | ||
Erik Tollerud
|
r16551 | # Can also do stereo or more channels | ||
dataleft = np.sin(2*np.pi*220*t) | ||||
dataright = np.sin(2*np.pi*224*t) | ||||
Audio([dataleft, dataright],rate=framerate) | ||||
Thomas Kluyver
|
r13587 | Audio("http://www.nch.com.au/acm/8k16bitpcm.wav") # From URL | ||
Audio(url="http://www.w3schools.com/html/horse.ogg") | ||||
Audio('/path/to/sound.wav') # From file | ||||
Audio(filename='/path/to/sound.ogg') | ||||
Audio(b'RAW_WAV_DATA..) # From bytes | ||||
Audio(data=b'RAW_WAV_DATA..) | ||||
David Österberg
|
r12829 | |||
""" | ||||
Thomas Kluyver
|
r13549 | _read_flags = 'rb' | ||
David Österberg
|
r12829 | def __init__(self, data=None, filename=None, url=None, embed=None, rate=None, autoplay=False): | ||
if filename is None and url is None and data is None: | ||||
Matan Gover
|
r24969 | raise ValueError("No audio data found. Expecting filename, url, or data.") | ||
David Österberg
|
r12829 | if embed is False and url is None: | ||
raise ValueError("No url found. Expecting url when embed=False") | ||||
Erik Tollerud
|
r16550 | |||
David Österberg
|
r12829 | if url is not None and embed is not True: | ||
self.embed = False | ||||
else: | ||||
self.embed = True | ||||
self.autoplay = autoplay | ||||
super(Audio, self).__init__(data=data, url=url, filename=filename) | ||||
Erik Tollerud
|
r16550 | |||
David Österberg
|
r12829 | if self.data is not None and not isinstance(self.data, bytes): | ||
Matan Gover
|
r24970 | if rate is None: | ||
raise ValueError("rate must be specified when data is a numpy array or list of audio samples.") | ||||
Matan Gover
|
r24968 | self.data = Audio._make_wav(data, rate) | ||
Erik Tollerud
|
r16550 | |||
David Österberg
|
r12829 | def reload(self): | ||
"""Reload the raw data from file or URL.""" | ||||
David Österberg
|
r12833 | import mimetypes | ||
David Österberg
|
r12829 | if self.embed: | ||
super(Audio, self).reload() | ||||
if self.filename is not None: | ||||
self.mimetype = mimetypes.guess_type(self.filename)[0] | ||||
elif self.url is not None: | ||||
self.mimetype = mimetypes.guess_type(self.url)[0] | ||||
else: | ||||
self.mimetype = "audio/wav" | ||||
Erik Tollerud
|
r16550 | |||
Matan Gover
|
r24968 | @staticmethod | ||
def _make_wav(data, rate): | ||||
David Österberg
|
r12829 | """ Transform a numpy array to a PCM bytestring """ | ||
David Österberg
|
r12833 | import struct | ||
from io import BytesIO | ||||
import wave | ||||
Erik Tollerud
|
r16550 | |||
David Österberg
|
r12869 | try: | ||
Matan Gover
|
r24968 | scaled, nchan = Audio._validate_and_normalize_with_numpy(data) | ||
David Österberg
|
r12869 | except ImportError: | ||
Matan Gover
|
r24968 | scaled, nchan = Audio._validate_and_normalize_without_numpy(data) | ||
Erik Tollerud
|
r16550 | |||
David Österberg
|
r12829 | fp = BytesIO() | ||
waveobj = wave.open(fp,mode='wb') | ||||
Erik Tollerud
|
r16550 | waveobj.setnchannels(nchan) | ||
David Österberg
|
r12829 | waveobj.setframerate(rate) | ||
waveobj.setsampwidth(2) | ||||
waveobj.setcomptype('NONE','NONE') | ||||
waveobj.writeframes(b''.join([struct.pack('<h',x) for x in scaled])) | ||||
val = fp.getvalue() | ||||
waveobj.close() | ||||
Erik Tollerud
|
r16550 | |||
return val | ||||
Matan Gover
|
r24968 | @staticmethod | ||
def _validate_and_normalize_with_numpy(data): | ||||
import numpy as np | ||||
data = np.array(data, dtype=float) | ||||
if len(data.shape) == 1: | ||||
nchan = 1 | ||||
elif len(data.shape) == 2: | ||||
# In wave files,channels are interleaved. E.g., | ||||
# "L1R1L2R2..." for stereo. See | ||||
# http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx | ||||
# for channel ordering | ||||
nchan = data.shape[0] | ||||
data = data.T.ravel() | ||||
else: | ||||
raise ValueError('Array audio input must be a 1D or 2D array') | ||||
scaled = np.int16(data/np.max(np.abs(data))*32767).tolist() | ||||
return scaled, nchan | ||||
@staticmethod | ||||
def _validate_and_normalize_without_numpy(data): | ||||
# check that it is a "1D" list | ||||
idata = iter(data) # fails if not an iterable | ||||
try: | ||||
iter(idata.next()) | ||||
raise TypeError('Only lists of mono audio are ' | ||||
'supported if numpy is not installed') | ||||
except TypeError: | ||||
# this means it's not a nested list, which is what we want | ||||
pass | ||||
maxabsvalue = float(max([abs(x) for x in data])) | ||||
scaled = [int(x/maxabsvalue*32767) for x in data] | ||||
nchan = 1 | ||||
return scaled, nchan | ||||
David Österberg
|
r12829 | def _data_and_metadata(self): | ||
"""shortcut for returning metadata with url information, if defined""" | ||||
md = {} | ||||
if self.url: | ||||
md['url'] = self.url | ||||
if md: | ||||
return self.data, md | ||||
else: | ||||
return self.data | ||||
Erik Tollerud
|
r16550 | |||
David Österberg
|
r12829 | def _repr_html_(self): | ||
src = """ | ||||
<audio controls="controls" {autoplay}> | ||||
<source src="{src}" type="{type}" /> | ||||
Your browser does not support the audio element. | ||||
</audio> | ||||
""" | ||||
return src.format(src=self.src_attr(),type=self.mimetype, autoplay=self.autoplay_attr()) | ||||
def src_attr(self): | ||||
David Österberg
|
r12833 | import base64 | ||
David Österberg
|
r12829 | if self.embed and (self.data is not None): | ||
David Österberg
|
r12840 | data = base64=base64.b64encode(self.data).decode('ascii') | ||
David Österberg
|
r12839 | return """data:{type};base64,{base64}""".format(type=self.mimetype, | ||
base64=data) | ||||
David Österberg
|
r12829 | elif self.url is not None: | ||
return self.url | ||||
else: | ||||
return "" | ||||
def autoplay_attr(self): | ||||
if(self.autoplay): | ||||
return 'autoplay="autoplay"' | ||||
else: | ||||
return '' | ||||
Greg Caporaso
|
r8272 | |||
Eugene Van den Bulke
|
r10260 | class IFrame(object): | ||
Eugene Van den Bulke
|
r10249 | """ | ||
Eugene Van den Bulke
|
r10260 | Generic class to embed an iframe in an IPython notebook | ||
Eugene Van den Bulke
|
r10249 | """ | ||
Eugene Van den Bulke
|
r10262 | iframe = """ | ||
<iframe | ||||
width="{width}" | ||||
Cyrille Rossant
|
r18018 | height="{height}" | ||
Eugene Van den Bulke
|
r10262 | src="{src}{params}" | ||
frameborder="0" | ||||
allowfullscreen | ||||
></iframe> | ||||
""" | ||||
def __init__(self, src, width, height, **kwargs): | ||||
self.src = src | ||||
Eugene Van den Bulke
|
r10249 | self.width = width | ||
self.height = height | ||||
self.params = kwargs | ||||
def _repr_html_(self): | ||||
Eugene Van den Bulke
|
r10262 | """return the embed iframe""" | ||
Eugene Van den Bulke
|
r10249 | if self.params: | ||
Sean Vig
|
r13640 | try: | ||
from urllib.parse import urlencode # Py 3 | ||||
except ImportError: | ||||
from urllib import urlencode | ||||
Eugene Van den Bulke
|
r10249 | params = "?" + urlencode(self.params) | ||
else: | ||||
params = "" | ||||
Eugene Van den Bulke
|
r10262 | return self.iframe.format(src=self.src, | ||
width=self.width, | ||||
Eugene Van den Bulke
|
r10253 | height=self.height, | ||
params=params) | ||||
Eugene Van den Bulke
|
r10249 | |||
Eugene Van den Bulke
|
r10260 | class YouTubeVideo(IFrame): | ||
Brian E. Granger
|
r4408 | """Class for embedding a YouTube Video in an IPython session, based on its video id. | ||
Bernardo B. Marques
|
r4872 | |||
MinRK
|
r14829 | e.g. to embed the video from https://www.youtube.com/watch?v=foo , you would | ||
Thomas Kluyver
|
r13587 | do:: | ||
Bernardo B. Marques
|
r4872 | |||
Thomas Kluyver
|
r13587 | vid = YouTubeVideo("foo") | ||
display(vid) | ||||
Bernardo B. Marques
|
r4872 | |||
Thomas Kluyver
|
r13587 | To start from 30 seconds:: | ||
Eugene Van den Bulke
|
r10249 | |||
Thomas Kluyver
|
r13587 | vid = YouTubeVideo("abc", start=30) | ||
display(vid) | ||||
Eugene Van den Bulke
|
r10249 | |||
Thomas Kluyver
|
r13587 | To calculate seconds from time as hours, minutes, seconds use | ||
:class:`datetime.timedelta`:: | ||||
Eugene Van den Bulke
|
r10249 | |||
Thomas Kluyver
|
r13587 | start=int(timedelta(hours=1, minutes=46, seconds=40).total_seconds()) | ||
Danny Staple
|
r8651 | |||
Eugene Van den Bulke
|
r10249 | Other parameters can be provided as documented at | ||
Thomas Kluyver
|
r23220 | https://developers.google.com/youtube/player_parameters#Parameters | ||
Ben Kasel
|
r21862 | |||
When converting the notebook using nbconvert, a jpeg representation of the video | ||||
will be inserted in the document. | ||||
Brian E. Granger
|
r4408 | """ | ||
Bernardo B. Marques
|
r4872 | |||
Eugene Van den Bulke
|
r10262 | def __init__(self, id, width=400, height=300, **kwargs): | ||
Ben Kasel
|
r21861 | self.id=id | ||
MinRK
|
r14829 | src = "https://www.youtube.com/embed/{0}".format(id) | ||
Eugene Van den Bulke
|
r10262 | super(YouTubeVideo, self).__init__(src, width, height, **kwargs) | ||
Ben Kasel
|
r21862 | |||
Ben Kasel
|
r21861 | def _repr_jpeg_(self): | ||
Srinivas Reddy Thatiparthy
|
r23075 | # Deferred import | ||
from urllib.request import urlopen | ||||
Ben Kasel
|
r21865 | try: | ||
return urlopen("https://img.youtube.com/vi/{id}/hqdefault.jpg".format(id=self.id)).read() | ||||
except IOError: | ||||
return None | ||||
Eugene Van den Bulke
|
r10249 | |||
Eugene Van den Bulke
|
r10261 | class VimeoVideo(IFrame): | ||
Eugene Van den Bulke
|
r10249 | """ | ||
Class for embedding a Vimeo video in an IPython session, based on its video id. | ||||
""" | ||||
Eugene Van den Bulke
|
r10262 | def __init__(self, id, width=400, height=300, **kwargs): | ||
MinRK
|
r14829 | src="https://player.vimeo.com/video/{0}".format(id) | ||
Eugene Van den Bulke
|
r10262 | super(VimeoVideo, self).__init__(src, width, height, **kwargs) | ||
Eugene Van den Bulke
|
r10249 | |||
Eugene Van den Bulke
|
r10260 | class ScribdDocument(IFrame): | ||
""" | ||||
Class for embedding a Scribd document in an IPython session | ||||
Use the start_page params to specify a starting point in the document | ||||
Use the view_mode params to specify display type one off scroll | slideshow | book | ||||
e.g to Display Wes' foundational paper about PANDAS in book mode from page 3 | ||||
ScribdDocument(71048089, width=800, height=400, start_page=3, view_mode="book") | ||||
""" | ||||
Eugene Van den Bulke
|
r10262 | def __init__(self, id, width=400, height=300, **kwargs): | ||
MinRK
|
r14829 | src="https://www.scribd.com/embeds/{0}/content".format(id) | ||
Eugene Van den Bulke
|
r10262 | super(ScribdDocument, self).__init__(src, width, height, **kwargs) | ||
Brian E. Granger
|
r4408 | |||
Greg Caporaso
|
r8365 | class FileLink(object): | ||
Greg Caporaso
|
r8272 | """Class for embedding a local file link in an IPython session, based on path | ||
e.g. to embed a link that was generated in the IPython notebook as my/data.txt | ||||
Thomas Kluyver
|
r9244 | you would do:: | ||
Greg Caporaso
|
r8272 | |||
Thomas Kluyver
|
r9244 | local_file = FileLink("my/data.txt") | ||
display(local_file) | ||||
Eugene Van den Bulke
|
r10249 | |||
Thomas Kluyver
|
r9244 | or in the HTML notebook, just:: | ||
Eugene Van den Bulke
|
r10249 | |||
Thomas Kluyver
|
r9244 | FileLink("my/data.txt") | ||
Greg Caporaso
|
r8272 | """ | ||
Eugene Van den Bulke
|
r10249 | |||
Greg Caporaso
|
r8442 | html_link_str = "<a href='%s' target='_blank'>%s</a>" | ||
Eugene Van den Bulke
|
r10249 | |||
Greg Caporaso
|
r8272 | def __init__(self, | ||
path, | ||||
MinRK
|
r14894 | url_prefix='', | ||
Greg Caporaso
|
r8439 | result_html_prefix='', | ||
result_html_suffix='<br>'): | ||||
Greg Caporaso
|
r8272 | """ | ||
Thomas Kluyver
|
r9244 | Parameters | ||
---------- | ||||
path : str | ||||
path to the file or directory that should be formatted | ||||
Steven Maude
|
r23327 | url_prefix : str | ||
Thomas Kluyver
|
r9244 | prefix to be prepended to all files to form a working link [default: | ||
Steven Maude
|
r23328 | ''] | ||
Thomas Kluyver
|
r9244 | result_html_prefix : str | ||
Steven Maude
|
r23329 | text to append to beginning to link [default: ''] | ||
Eugene Van den Bulke
|
r10249 | result_html_suffix : str | ||
Thomas Kluyver
|
r9244 | text to append at the end of link [default: '<br>'] | ||
Greg Caporaso
|
r8272 | """ | ||
Greg Caporaso
|
r8835 | if isdir(path): | ||
Thomas Kluyver
|
r13349 | raise ValueError("Cannot display a directory using FileLink. " | ||
Greg Caporaso
|
r8835 | "Use FileLinks to display '%s'." % path) | ||
Cristian Ciupitu
|
r24227 | self.path = fsdecode(path) | ||
Greg Caporaso
|
r8437 | self.url_prefix = url_prefix | ||
Greg Caporaso
|
r8439 | self.result_html_prefix = result_html_prefix | ||
self.result_html_suffix = result_html_suffix | ||||
Eugene Van den Bulke
|
r10249 | |||
Greg Caporaso
|
r8272 | def _format_path(self): | ||
Cristian Ciupitu
|
r24230 | fp = ''.join([self.url_prefix, html_escape(self.path)]) | ||
Greg Caporaso
|
r8439 | return ''.join([self.result_html_prefix, | ||
Cristian Ciupitu
|
r24230 | self.html_link_str % \ | ||
(fp, html_escape(self.path, quote=False)), | ||||
Greg Caporaso
|
r8439 | self.result_html_suffix]) | ||
Eugene Van den Bulke
|
r10249 | |||
Greg Caporaso
|
r8272 | def _repr_html_(self): | ||
Greg Caporaso
|
r8442 | """return html link to file | ||
Greg Caporaso
|
r8272 | """ | ||
if not exists(self.path): | ||||
Eugene Van den Bulke
|
r10249 | return ("Path (<tt>%s</tt>) doesn't exist. " | ||
Greg Caporaso
|
r8272 | "It may still be in the process of " | ||
"being generated, or you may have the " | ||||
"incorrect path." % self.path) | ||||
Eugene Van den Bulke
|
r10249 | |||
Greg Caporaso
|
r8272 | return self._format_path() | ||
Eugene Van den Bulke
|
r10249 | |||
Greg Caporaso
|
r8442 | def __repr__(self): | ||
Greg Caporaso
|
r8443 | """return absolute path to file | ||
Greg Caporaso
|
r8442 | """ | ||
return abspath(self.path) | ||||
Greg Caporaso
|
r8272 | |||
Greg Caporaso
|
r8365 | class FileLinks(FileLink): | ||
Greg Caporaso
|
r8272 | """Class for embedding local file links in an IPython session, based on path | ||
Thomas Kluyver
|
r13587 | e.g. to embed links to files that were generated in the IPython notebook | ||
under ``my/data``, you would do:: | ||||
Greg Caporaso
|
r8272 | |||
Thomas Kluyver
|
r13587 | local_files = FileLinks("my/data") | ||
display(local_files) | ||||
Eugene Van den Bulke
|
r10249 | |||
Thomas Kluyver
|
r13587 | or in the HTML notebook, just:: | ||
Eugene Van den Bulke
|
r10249 | |||
Thomas Kluyver
|
r13587 | FileLinks("my/data") | ||
Greg Caporaso
|
r8272 | """ | ||
def __init__(self, | ||||
path, | ||||
MinRK
|
r14894 | url_prefix='', | ||
Greg Caporaso
|
r8439 | included_suffixes=None, | ||
result_html_prefix='', | ||||
Greg Caporaso
|
r8619 | result_html_suffix='<br>', | ||
notebook_display_formatter=None, | ||||
Doug Blank
|
r19166 | terminal_display_formatter=None, | ||
recursive=True): | ||||
Greg Caporaso
|
r8272 | """ | ||
Thomas Kluyver
|
r13587 | See :class:`FileLink` for the ``path``, ``url_prefix``, | ||
``result_html_prefix`` and ``result_html_suffix`` parameters. | ||||
included_suffixes : list | ||||
Filename suffixes to include when formatting output [default: include | ||||
all files] | ||||
notebook_display_formatter : function | ||||
Used to format links for display in the notebook. See discussion of | ||||
formatter functions below. | ||||
terminal_display_formatter : function | ||||
Used to format links for display in the terminal. See discussion of | ||||
formatter functions below. | ||||
Formatter functions must be of the form:: | ||||
f(dirname, fnames, included_suffixes) | ||||
dirname : str | ||||
The name of a directory | ||||
fnames : list | ||||
The files in that directory | ||||
included_suffixes : list | ||||
The file suffixes that should be included in the output (passing None | ||||
meansto include all suffixes in the output in the built-in formatters) | ||||
Doug Blank
|
r19167 | recursive : boolean | ||
Whether to recurse into subdirectories. Default is True. | ||||
Thomas Kluyver
|
r13587 | |||
The function should return a list of lines that will be printed in the | ||||
notebook (if passing notebook_display_formatter) or the terminal (if | ||||
passing terminal_display_formatter). This function is iterated over for | ||||
each directory in self.path. Default formatters are in place, can be | ||||
passed here to support alternative formatting. | ||||
Eugene Van den Bulke
|
r10249 | |||
Greg Caporaso
|
r8272 | """ | ||
Greg Caporaso
|
r8836 | if isfile(path): | ||
Thomas Kluyver
|
r13349 | raise ValueError("Cannot display a file using FileLinks. " | ||
Greg Caporaso
|
r8836 | "Use FileLink to display '%s'." % path) | ||
Greg Caporaso
|
r8439 | self.included_suffixes = included_suffixes | ||
luz.paz
|
r24132 | # remove trailing slashes for more consistent output formatting | ||
Greg Caporaso
|
r8631 | path = path.rstrip('/') | ||
Eugene Van den Bulke
|
r10249 | |||
Greg Caporaso
|
r8835 | self.path = path | ||
self.url_prefix = url_prefix | ||||
self.result_html_prefix = result_html_prefix | ||||
self.result_html_suffix = result_html_suffix | ||||
Eugene Van den Bulke
|
r10249 | |||
Greg Caporaso
|
r8624 | self.notebook_display_formatter = \ | ||
Greg Caporaso
|
r8626 | notebook_display_formatter or self._get_notebook_display_formatter() | ||
Greg Caporaso
|
r8624 | self.terminal_display_formatter = \ | ||
Greg Caporaso
|
r8626 | terminal_display_formatter or self._get_terminal_display_formatter() | ||
Eugene Van den Bulke
|
r10249 | |||
Doug Blank
|
r19166 | self.recursive = recursive | ||
Greg Caporaso
|
r8624 | def _get_display_formatter(self, | ||
dirname_output_format, | ||||
fname_output_format, | ||||
Greg Caporaso
|
r9093 | fp_format, | ||
fp_cleaner=None): | ||||
Greg Caporaso
|
r8803 | """ generate built-in formatter function | ||
Eugene Van den Bulke
|
r10249 | |||
this is used to define both the notebook and terminal built-in | ||||
Greg Caporaso
|
r8803 | formatters as they only differ by some wrapper text for each entry | ||
Eugene Van den Bulke
|
r10249 | |||
dirname_output_format: string to use for formatting directory | ||||
Greg Caporaso
|
r8631 | names, dirname will be substituted for a single "%s" which | ||
must appear in this string | ||||
fname_output_format: string to use for formatting file names, | ||||
if a single "%s" appears in the string, fname will be substituted | ||||
Eugene Van den Bulke
|
r10249 | if two "%s" appear in the string, the path to fname will be | ||
Greg Caporaso
|
r8631 | substituted for the first and fname will be substituted for the | ||
second | ||||
fp_format: string to use for formatting filepaths, must contain | ||||
exactly two "%s" and the dirname will be subsituted for the first | ||||
and fname will be substituted for the second | ||||
""" | ||||
Greg Caporaso
|
r8802 | def f(dirname, fnames, included_suffixes=None): | ||
Greg Caporaso
|
r8801 | result = [] | ||
Eugene Van den Bulke
|
r10249 | # begin by figuring out which filenames, if any, | ||
Greg Caporaso
|
r8619 | # are going to be displayed | ||
display_fnames = [] | ||||
for fname in fnames: | ||||
if (isfile(join(dirname,fname)) and | ||||
Boris Egorov
|
r18172 | (included_suffixes is None or | ||
Greg Caporaso
|
r8619 | splitext(fname)[1] in included_suffixes)): | ||
display_fnames.append(fname) | ||||
Eugene Van den Bulke
|
r10249 | |||
Greg Caporaso
|
r8619 | if len(display_fnames) == 0: | ||
Greg Caporaso
|
r8631 | # if there are no filenames to display, don't print anything | ||
# (not even the directory name) | ||||
Greg Caporaso
|
r8619 | pass | ||
else: | ||||
Eugene Van den Bulke
|
r10249 | # otherwise print the formatted directory name followed by | ||
Greg Caporaso
|
r8631 | # the formatted filenames | ||
Greg Caporaso
|
r8624 | dirname_output_line = dirname_output_format % dirname | ||
Greg Caporaso
|
r8801 | result.append(dirname_output_line) | ||
Greg Caporaso
|
r8619 | for fname in display_fnames: | ||
Greg Caporaso
|
r8624 | fp = fp_format % (dirname,fname) | ||
Greg Caporaso
|
r9305 | if fp_cleaner is not None: | ||
Greg Caporaso
|
r9093 | fp = fp_cleaner(fp) | ||
Greg Caporaso
|
r8624 | try: | ||
# output can include both a filepath and a filename... | ||||
fname_output_line = fname_output_format % (fp, fname) | ||||
except TypeError: | ||||
# ... or just a single filepath | ||||
fname_output_line = fname_output_format % fname | ||||
Greg Caporaso
|
r8801 | result.append(fname_output_line) | ||
return result | ||||
Greg Caporaso
|
r8619 | return f | ||
Greg Caporaso
|
r8624 | def _get_notebook_display_formatter(self, | ||
spacer=" "): | ||||
Greg Caporaso
|
r8802 | """ generate function to use for notebook formatting | ||
Greg Caporaso
|
r8631 | """ | ||
Greg Caporaso
|
r8624 | dirname_output_format = \ | ||
Greg Caporaso
|
r8631 | self.result_html_prefix + "%s/" + self.result_html_suffix | ||
Greg Caporaso
|
r8624 | fname_output_format = \ | ||
self.result_html_prefix + spacer + self.html_link_str + self.result_html_suffix | ||||
fp_format = self.url_prefix + '%s/%s' | ||||
Greg Caporaso
|
r9093 | if sep == "\\": | ||
Eugene Van den Bulke
|
r10249 | # Working on a platform where the path separator is "\", so | ||
Greg Caporaso
|
r9093 | # must convert these to "/" for generating a URI | ||
def fp_cleaner(fp): | ||||
luzpaz
|
r24084 | # Replace all occurrences of backslash ("\") with a forward | ||
Greg Caporaso
|
r9093 | # slash ("/") - this is necessary on windows when a path is | ||
# provided as input, but we must link to a URI | ||||
return fp.replace('\\','/') | ||||
else: | ||||
fp_cleaner = None | ||||
Eugene Van den Bulke
|
r10249 | |||
Greg Caporaso
|
r8624 | return self._get_display_formatter(dirname_output_format, | ||
fname_output_format, | ||||
Greg Caporaso
|
r9093 | fp_format, | ||
fp_cleaner) | ||||
Greg Caporaso
|
r8619 | |||
Greg Caporaso
|
r8624 | def _get_terminal_display_formatter(self, | ||
spacer=" "): | ||||
Greg Caporaso
|
r8802 | """ generate function to use for terminal formatting | ||
Greg Caporaso
|
r8631 | """ | ||
dirname_output_format = "%s/" | ||||
Greg Caporaso
|
r8624 | fname_output_format = spacer + "%s" | ||
fp_format = '%s/%s' | ||||
Eugene Van den Bulke
|
r10249 | |||
Greg Caporaso
|
r8624 | return self._get_display_formatter(dirname_output_format, | ||
fname_output_format, | ||||
fp_format) | ||||
Eugene Van den Bulke
|
r10249 | |||
Greg Caporaso
|
r8619 | def _format_path(self): | ||
result_lines = [] | ||||
Doug Blank
|
r19166 | if self.recursive: | ||
walked_dir = list(walk(self.path)) | ||||
else: | ||||
Doug Blank
|
r19367 | walked_dir = [next(walk(self.path))] | ||
Greg Caporaso
|
r8800 | walked_dir.sort() | ||
for dirname, subdirs, fnames in walked_dir: | ||||
Greg Caporaso
|
r8802 | result_lines += self.notebook_display_formatter(dirname, fnames, self.included_suffixes) | ||
Greg Caporaso
|
r8619 | return '\n'.join(result_lines) | ||
Eugene Van den Bulke
|
r10249 | |||
Greg Caporaso
|
r8443 | def __repr__(self): | ||
"""return newline-separated absolute paths | ||||
""" | ||||
Greg Caporaso
|
r8619 | result_lines = [] | ||
Doug Blank
|
r19166 | if self.recursive: | ||
walked_dir = list(walk(self.path)) | ||||
else: | ||||
Doug Blank
|
r19367 | walked_dir = [next(walk(self.path))] | ||
Greg Caporaso
|
r8800 | walked_dir.sort() | ||
for dirname, subdirs, fnames in walked_dir: | ||||
Greg Caporaso
|
r8802 | result_lines += self.terminal_display_formatter(dirname, fnames, self.included_suffixes) | ||
Greg Caporaso
|
r8798 | return '\n'.join(result_lines) | ||
Thomas Kluyver
|
r24130 | |||
class Code(TextDisplayObject): | ||||
Thomas Kluyver
|
r24131 | """Display syntax-highlighted source code. | ||
This uses Pygments to highlight the code for HTML and Latex output. | ||||
Parameters | ||||
---------- | ||||
data : str | ||||
The code as a string | ||||
url : str | ||||
A URL to fetch the code from | ||||
filename : str | ||||
A local filename to load the code from | ||||
language : str | ||||
The short name of a Pygments lexer to use for highlighting. | ||||
If not specified, it will guess the lexer based on the filename | ||||
or the code. Available lexers: http://pygments.org/docs/lexers/ | ||||
""" | ||||
Thomas Kluyver
|
r24130 | def __init__(self, data=None, url=None, filename=None, language=None): | ||
self.language = language | ||||
super().__init__(data=data, url=url, filename=filename) | ||||
def _get_lexer(self): | ||||
if self.language: | ||||
from pygments.lexers import get_lexer_by_name | ||||
return get_lexer_by_name(self.language) | ||||
elif self.filename: | ||||
from pygments.lexers import get_lexer_for_filename | ||||
return get_lexer_for_filename(self.filename) | ||||
else: | ||||
from pygments.lexers import guess_lexer | ||||
return guess_lexer(self.data) | ||||
Thomas Kluyver
|
r24134 | def __repr__(self): | ||
return self.data | ||||
Thomas Kluyver
|
r24130 | def _repr_html_(self): | ||
from pygments import highlight | ||||
from pygments.formatters import HtmlFormatter | ||||
fmt = HtmlFormatter() | ||||
style = '<style>{}</style>'.format(fmt.get_style_defs('.output_html')) | ||||
return style + highlight(self.data, self._get_lexer(), fmt) | ||||
def _repr_latex_(self): | ||||
from pygments import highlight | ||||
from pygments.formatters import LatexFormatter | ||||
return highlight(self.data, self._get_lexer(), LatexFormatter()) | ||||