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