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