| 
									
										
										
										
											2018-01-05 16:57:38 +00:00
										 |  |  | """Various display related classes.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Authors : MinRK, gregcaporaso, dannystaple | 
					
						
							|  |  |  | """
 | 
					
						
							| 
									
										
										
										
											2018-10-16 14:33:16 +01:00
										 |  |  | from html import escape as html_escape | 
					
						
							| 
									
										
										
										
											2018-01-05 16:57:38 +00:00
										 |  |  | from os.path import exists, isfile, splitext, abspath, join, isdir | 
					
						
							| 
									
										
										
										
											2018-10-16 14:33:16 +01:00
										 |  |  | from os import walk, sep, fsdecode | 
					
						
							| 
									
										
										
										
											2018-01-05 16:57:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-16 14:33:16 +01:00
										 |  |  | from yap_ipython.core.display import DisplayObject, TextDisplayObject | 
					
						
							| 
									
										
										
										
											2018-01-05 16:57:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | __all__ = ['Audio', 'IFrame', 'YouTubeVideo', 'VimeoVideo', 'ScribdDocument', | 
					
						
							| 
									
										
										
										
											2018-10-16 14:33:16 +01:00
										 |  |  |            'FileLink', 'FileLinks', 'Code'] | 
					
						
							| 
									
										
										
										
											2018-01-05 16:57:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Parameters | 
					
						
							|  |  |  |     ---------- | 
					
						
							|  |  |  |     data : numpy array, list, unicode, str or bytes | 
					
						
							|  |  |  |         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. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         If the array option is used the waveform will be normalized. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         If a filename or url is used the format support will be browser | 
					
						
							|  |  |  |         dependent. | 
					
						
							|  |  |  |     url : unicode | 
					
						
							|  |  |  |         A URL to download the data from. | 
					
						
							|  |  |  |     filename : unicode | 
					
						
							|  |  |  |         Path to a local file to load the data from. | 
					
						
							|  |  |  |     embed : boolean | 
					
						
							|  |  |  |         Should the audio data be embedded using a data URI (True) or should | 
					
						
							|  |  |  |         the original source be referenced. Set this to True if you want the | 
					
						
							|  |  |  |         audio to playable later with no internet connection in the notebook. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         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 | 
					
						
							|  |  |  |     -------- | 
					
						
							|  |  |  |     :: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Generate a sound | 
					
						
							|  |  |  |         import numpy as np | 
					
						
							|  |  |  |         framerate = 44100 | 
					
						
							|  |  |  |         t = np.linspace(0,5,framerate*5) | 
					
						
							|  |  |  |         data = np.sin(2*np.pi*220*t) + np.sin(2*np.pi*224*t)) | 
					
						
							|  |  |  |         Audio(data,rate=framerate) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # 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) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         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..) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     _read_flags = 'rb' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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: | 
					
						
							|  |  |  |             raise ValueError("No image data found. Expecting filename, url, or data.") | 
					
						
							|  |  |  |         if embed is False and url is None: | 
					
						
							|  |  |  |             raise ValueError("No url found. Expecting url when embed=False") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         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) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if self.data is not None and not isinstance(self.data, bytes): | 
					
						
							|  |  |  |             self.data = self._make_wav(data,rate) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def reload(self): | 
					
						
							|  |  |  |         """Reload the raw data from file or URL.""" | 
					
						
							|  |  |  |         import mimetypes | 
					
						
							|  |  |  |         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" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _make_wav(self, data, rate): | 
					
						
							|  |  |  |         """ Transform a numpy array to a PCM bytestring """ | 
					
						
							|  |  |  |         import struct | 
					
						
							|  |  |  |         from io import BytesIO | 
					
						
							|  |  |  |         import wave | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             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() | 
					
						
							|  |  |  |         except ImportError: | 
					
						
							|  |  |  |             # 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 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fp = BytesIO() | 
					
						
							|  |  |  |         waveobj = wave.open(fp,mode='wb') | 
					
						
							|  |  |  |         waveobj.setnchannels(nchan) | 
					
						
							|  |  |  |         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() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return val | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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): | 
					
						
							|  |  |  |         import base64 | 
					
						
							|  |  |  |         if self.embed and (self.data is not None): | 
					
						
							|  |  |  |             data = base64=base64.b64encode(self.data).decode('ascii') | 
					
						
							|  |  |  |             return """data:{type};base64,{base64}""".format(type=self.mimetype, | 
					
						
							|  |  |  |                                                             base64=data) | 
					
						
							|  |  |  |         elif self.url is not None: | 
					
						
							|  |  |  |             return self.url | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return "" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def autoplay_attr(self): | 
					
						
							|  |  |  |         if(self.autoplay): | 
					
						
							|  |  |  |             return 'autoplay="autoplay"' | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return '' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class IFrame(object): | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2018-10-16 14:33:16 +01:00
										 |  |  |     Generic class to embed an iframe in an IPython notebook | 
					
						
							| 
									
										
										
										
											2018-01-05 16:57:38 +00:00
										 |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     iframe = """
 | 
					
						
							|  |  |  |         <iframe | 
					
						
							|  |  |  |             width="{width}" | 
					
						
							|  |  |  |             height="{height}" | 
					
						
							|  |  |  |             src="{src}{params}" | 
					
						
							|  |  |  |             frameborder="0" | 
					
						
							|  |  |  |             allowfullscreen | 
					
						
							|  |  |  |         ></iframe> | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, src, width, height, **kwargs): | 
					
						
							|  |  |  |         self.src = src | 
					
						
							|  |  |  |         self.width = width | 
					
						
							|  |  |  |         self.height = height | 
					
						
							|  |  |  |         self.params = kwargs | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _repr_html_(self): | 
					
						
							|  |  |  |         """return the embed iframe""" | 
					
						
							|  |  |  |         if self.params: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 from urllib.parse import urlencode # Py 3 | 
					
						
							|  |  |  |             except ImportError: | 
					
						
							|  |  |  |                 from urllib import urlencode | 
					
						
							|  |  |  |             params = "?" + urlencode(self.params) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             params = "" | 
					
						
							|  |  |  |         return self.iframe.format(src=self.src, | 
					
						
							|  |  |  |                                   width=self.width, | 
					
						
							|  |  |  |                                   height=self.height, | 
					
						
							|  |  |  |                                   params=params) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class YouTubeVideo(IFrame): | 
					
						
							| 
									
										
										
										
											2018-10-16 14:33:16 +01:00
										 |  |  |     """Class for embedding a YouTube Video in an IPython session, based on its video id.
 | 
					
						
							| 
									
										
										
										
											2018-01-05 16:57:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     e.g. to embed the video from https://www.youtube.com/watch?v=foo , you would | 
					
						
							|  |  |  |     do:: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         vid = YouTubeVideo("foo") | 
					
						
							|  |  |  |         display(vid) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     To start from 30 seconds:: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         vid = YouTubeVideo("abc", start=30) | 
					
						
							|  |  |  |         display(vid) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     To calculate seconds from time as hours, minutes, seconds use | 
					
						
							|  |  |  |     :class:`datetime.timedelta`:: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         start=int(timedelta(hours=1, minutes=46, seconds=40).total_seconds()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Other parameters can be provided as documented at | 
					
						
							|  |  |  |     https://developers.google.com/youtube/player_parameters#Parameters | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     When converting the notebook using nbconvert, a jpeg representation of the video | 
					
						
							|  |  |  |     will be inserted in the document. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, id, width=400, height=300, **kwargs): | 
					
						
							|  |  |  |         self.id=id | 
					
						
							|  |  |  |         src = "https://www.youtube.com/embed/{0}".format(id) | 
					
						
							|  |  |  |         super(YouTubeVideo, self).__init__(src, width, height, **kwargs) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def _repr_jpeg_(self): | 
					
						
							|  |  |  |         # Deferred import | 
					
						
							|  |  |  |         from urllib.request import urlopen | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             return urlopen("https://img.youtube.com/vi/{id}/hqdefault.jpg".format(id=self.id)).read() | 
					
						
							|  |  |  |         except IOError: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class VimeoVideo(IFrame): | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2018-10-16 14:33:16 +01:00
										 |  |  |     Class for embedding a Vimeo video in an IPython session, based on its video id. | 
					
						
							| 
									
										
										
										
											2018-01-05 16:57:38 +00:00
										 |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, id, width=400, height=300, **kwargs): | 
					
						
							|  |  |  |         src="https://player.vimeo.com/video/{0}".format(id) | 
					
						
							|  |  |  |         super(VimeoVideo, self).__init__(src, width, height, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ScribdDocument(IFrame): | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2018-10-16 14:33:16 +01:00
										 |  |  |     Class for embedding a Scribd document in an IPython session | 
					
						
							| 
									
										
										
										
											2018-01-05 16:57:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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") | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, id, width=400, height=300, **kwargs): | 
					
						
							|  |  |  |         src="https://www.scribd.com/embeds/{0}/content".format(id) | 
					
						
							|  |  |  |         super(ScribdDocument, self).__init__(src, width, height, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class FileLink(object): | 
					
						
							| 
									
										
										
										
											2018-10-16 14:33:16 +01:00
										 |  |  |     """Class for embedding a local file link in an IPython session, based on path
 | 
					
						
							| 
									
										
										
										
											2018-01-05 16:57:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-16 14:33:16 +01:00
										 |  |  |     e.g. to embed a link that was generated in the IPython notebook as my/data.txt | 
					
						
							| 
									
										
										
										
											2018-01-05 16:57:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     you would do:: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         local_file = FileLink("my/data.txt") | 
					
						
							|  |  |  |         display(local_file) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     or in the HTML notebook, just:: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         FileLink("my/data.txt") | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     html_link_str = "<a href='%s' target='_blank'>%s</a>" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, | 
					
						
							|  |  |  |                  path, | 
					
						
							|  |  |  |                  url_prefix='', | 
					
						
							|  |  |  |                  result_html_prefix='', | 
					
						
							|  |  |  |                  result_html_suffix='<br>'): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Parameters | 
					
						
							|  |  |  |         ---------- | 
					
						
							|  |  |  |         path : str | 
					
						
							|  |  |  |             path to the file or directory that should be formatted | 
					
						
							|  |  |  |         url_prefix : str | 
					
						
							|  |  |  |             prefix to be prepended to all files to form a working link [default: | 
					
						
							|  |  |  |             ''] | 
					
						
							|  |  |  |         result_html_prefix : str | 
					
						
							|  |  |  |             text to append to beginning to link [default: ''] | 
					
						
							|  |  |  |         result_html_suffix : str | 
					
						
							|  |  |  |             text to append at the end of link [default: '<br>'] | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if isdir(path): | 
					
						
							|  |  |  |             raise ValueError("Cannot display a directory using FileLink. " | 
					
						
							|  |  |  |               "Use FileLinks to display '%s'." % path) | 
					
						
							| 
									
										
										
										
											2018-10-16 14:33:16 +01:00
										 |  |  |         self.path = fsdecode(path) | 
					
						
							| 
									
										
										
										
											2018-01-05 16:57:38 +00:00
										 |  |  |         self.url_prefix = url_prefix | 
					
						
							|  |  |  |         self.result_html_prefix = result_html_prefix | 
					
						
							|  |  |  |         self.result_html_suffix = result_html_suffix | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _format_path(self): | 
					
						
							| 
									
										
										
										
											2018-10-16 14:33:16 +01:00
										 |  |  |         fp = ''.join([self.url_prefix, html_escape(self.path)]) | 
					
						
							| 
									
										
										
										
											2018-01-05 16:57:38 +00:00
										 |  |  |         return ''.join([self.result_html_prefix, | 
					
						
							| 
									
										
										
										
											2018-10-16 14:33:16 +01:00
										 |  |  |                         self.html_link_str % \ | 
					
						
							|  |  |  |                             (fp, html_escape(self.path, quote=False)), | 
					
						
							| 
									
										
										
										
											2018-01-05 16:57:38 +00:00
										 |  |  |                         self.result_html_suffix]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _repr_html_(self): | 
					
						
							|  |  |  |         """return html link to file
 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if not exists(self.path): | 
					
						
							|  |  |  |             return ("Path (<tt>%s</tt>) doesn't exist. " | 
					
						
							|  |  |  |                     "It may still be in the process of " | 
					
						
							|  |  |  |                     "being generated, or you may have the " | 
					
						
							|  |  |  |                     "incorrect path." % self.path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return self._format_path() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         """return absolute path to file
 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         return abspath(self.path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class FileLinks(FileLink): | 
					
						
							| 
									
										
										
										
											2018-10-16 14:33:16 +01:00
										 |  |  |     """Class for embedding local file links in an IPython session, based on path
 | 
					
						
							| 
									
										
										
										
											2018-01-05 16:57:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-16 14:33:16 +01:00
										 |  |  |     e.g. to embed links to files that were generated in the IPython notebook | 
					
						
							| 
									
										
										
										
											2018-01-05 16:57:38 +00:00
										 |  |  |     under ``my/data``, you would do:: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         local_files = FileLinks("my/data") | 
					
						
							|  |  |  |         display(local_files) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     or in the HTML notebook, just:: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         FileLinks("my/data") | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     def __init__(self, | 
					
						
							|  |  |  |                  path, | 
					
						
							|  |  |  |                  url_prefix='', | 
					
						
							|  |  |  |                  included_suffixes=None, | 
					
						
							|  |  |  |                  result_html_prefix='', | 
					
						
							|  |  |  |                  result_html_suffix='<br>', | 
					
						
							|  |  |  |                  notebook_display_formatter=None, | 
					
						
							|  |  |  |                  terminal_display_formatter=None, | 
					
						
							|  |  |  |                  recursive=True): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         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) | 
					
						
							|  |  |  |         recursive : boolean | 
					
						
							|  |  |  |           Whether to recurse into subdirectories. Default is True. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         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. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if isfile(path): | 
					
						
							|  |  |  |             raise ValueError("Cannot display a file using FileLinks. " | 
					
						
							|  |  |  |               "Use FileLink to display '%s'." % path) | 
					
						
							|  |  |  |         self.included_suffixes = included_suffixes | 
					
						
							| 
									
										
										
										
											2018-10-16 14:33:16 +01:00
										 |  |  |         # remove trailing slashes for more consistent output formatting | 
					
						
							| 
									
										
										
										
											2018-01-05 16:57:38 +00:00
										 |  |  |         path = path.rstrip('/') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.path = path | 
					
						
							|  |  |  |         self.url_prefix = url_prefix | 
					
						
							|  |  |  |         self.result_html_prefix = result_html_prefix | 
					
						
							|  |  |  |         self.result_html_suffix = result_html_suffix | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.notebook_display_formatter = \ | 
					
						
							|  |  |  |              notebook_display_formatter or self._get_notebook_display_formatter() | 
					
						
							|  |  |  |         self.terminal_display_formatter = \ | 
					
						
							|  |  |  |              terminal_display_formatter or self._get_terminal_display_formatter() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.recursive = recursive | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _get_display_formatter(self, | 
					
						
							|  |  |  |                                dirname_output_format, | 
					
						
							|  |  |  |                                fname_output_format, | 
					
						
							|  |  |  |                                fp_format, | 
					
						
							|  |  |  |                                fp_cleaner=None): | 
					
						
							|  |  |  |         """ generate built-in formatter function
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            this is used to define both the notebook and terminal built-in | 
					
						
							|  |  |  |             formatters as they only differ by some wrapper text for each entry | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            dirname_output_format: string to use for formatting directory | 
					
						
							|  |  |  |             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 | 
					
						
							|  |  |  |             if two "%s" appear in the string, the path to fname will be | 
					
						
							|  |  |  |              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 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         def f(dirname, fnames, included_suffixes=None): | 
					
						
							|  |  |  |             result = [] | 
					
						
							|  |  |  |             # begin by figuring out which filenames, if any, | 
					
						
							|  |  |  |             # are going to be displayed | 
					
						
							|  |  |  |             display_fnames = [] | 
					
						
							|  |  |  |             for fname in fnames: | 
					
						
							|  |  |  |                 if (isfile(join(dirname,fname)) and | 
					
						
							|  |  |  |                        (included_suffixes is None or | 
					
						
							|  |  |  |                         splitext(fname)[1] in included_suffixes)): | 
					
						
							|  |  |  |                       display_fnames.append(fname) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if len(display_fnames) == 0: | 
					
						
							|  |  |  |                 # if there are no filenames to display, don't print anything | 
					
						
							|  |  |  |                 # (not even the directory name) | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 # otherwise print the formatted directory name followed by | 
					
						
							|  |  |  |                 # the formatted filenames | 
					
						
							|  |  |  |                 dirname_output_line = dirname_output_format % dirname | 
					
						
							|  |  |  |                 result.append(dirname_output_line) | 
					
						
							|  |  |  |                 for fname in display_fnames: | 
					
						
							|  |  |  |                     fp = fp_format % (dirname,fname) | 
					
						
							|  |  |  |                     if fp_cleaner is not None: | 
					
						
							|  |  |  |                         fp = fp_cleaner(fp) | 
					
						
							|  |  |  |                     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 | 
					
						
							|  |  |  |                     result.append(fname_output_line) | 
					
						
							|  |  |  |             return result | 
					
						
							|  |  |  |         return f | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _get_notebook_display_formatter(self, | 
					
						
							|  |  |  |                                         spacer="  "): | 
					
						
							|  |  |  |         """ generate function to use for notebook formatting
 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         dirname_output_format = \ | 
					
						
							|  |  |  |          self.result_html_prefix + "%s/" + self.result_html_suffix | 
					
						
							|  |  |  |         fname_output_format = \ | 
					
						
							|  |  |  |          self.result_html_prefix + spacer + self.html_link_str + self.result_html_suffix | 
					
						
							|  |  |  |         fp_format = self.url_prefix + '%s/%s' | 
					
						
							|  |  |  |         if sep == "\\": | 
					
						
							|  |  |  |             # Working on a platform where the path separator is "\", so | 
					
						
							|  |  |  |             # must convert these to "/" for generating a URI | 
					
						
							|  |  |  |             def fp_cleaner(fp): | 
					
						
							|  |  |  |                 # Replace all occurrences of backslash ("\") with a forward | 
					
						
							|  |  |  |                 # 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 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return self._get_display_formatter(dirname_output_format, | 
					
						
							|  |  |  |                                            fname_output_format, | 
					
						
							|  |  |  |                                            fp_format, | 
					
						
							|  |  |  |                                            fp_cleaner) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _get_terminal_display_formatter(self, | 
					
						
							|  |  |  |                                         spacer="  "): | 
					
						
							|  |  |  |         """ generate function to use for terminal formatting
 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         dirname_output_format = "%s/" | 
					
						
							|  |  |  |         fname_output_format = spacer + "%s" | 
					
						
							|  |  |  |         fp_format = '%s/%s' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return self._get_display_formatter(dirname_output_format, | 
					
						
							|  |  |  |                                            fname_output_format, | 
					
						
							|  |  |  |                                            fp_format) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _format_path(self): | 
					
						
							|  |  |  |         result_lines = [] | 
					
						
							|  |  |  |         if self.recursive: | 
					
						
							|  |  |  |             walked_dir = list(walk(self.path)) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             walked_dir = [next(walk(self.path))] | 
					
						
							|  |  |  |         walked_dir.sort() | 
					
						
							|  |  |  |         for dirname, subdirs, fnames in walked_dir: | 
					
						
							|  |  |  |             result_lines += self.notebook_display_formatter(dirname, fnames, self.included_suffixes) | 
					
						
							|  |  |  |         return '\n'.join(result_lines) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         """return newline-separated absolute paths
 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         result_lines = [] | 
					
						
							|  |  |  |         if self.recursive: | 
					
						
							|  |  |  |             walked_dir = list(walk(self.path)) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             walked_dir = [next(walk(self.path))] | 
					
						
							|  |  |  |         walked_dir.sort() | 
					
						
							|  |  |  |         for dirname, subdirs, fnames in walked_dir: | 
					
						
							|  |  |  |             result_lines += self.terminal_display_formatter(dirname, fnames, self.included_suffixes) | 
					
						
							|  |  |  |         return '\n'.join(result_lines) | 
					
						
							| 
									
										
										
										
											2018-10-16 14:33:16 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Code(TextDisplayObject): | 
					
						
							|  |  |  |     """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/ | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     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) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         return self.data | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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()) |