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