##// END OF EJS Templates
Remove requirement for numpy module
David Österberg -
Show More
@@ -1,495 +1,496 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, 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 * String containing the filename
24 * String containing the filename
24 * Bytestring containing raw PCM data or
25 * Bytestring containing raw PCM data or
25 * URL pointing to a file on the web.
26 * URL pointing to a file on the web.
26
27
27 If the array option is used the waveform will be normalized.
28 If the array option is used the waveform will be normalized.
28
29
29 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
30 dependent.
31 dependent.
31 url : unicode
32 url : unicode
32 A URL to download the data from.
33 A URL to download the data from.
33 filename : unicode
34 filename : unicode
34 Path to a local file to load the data from.
35 Path to a local file to load the data from.
35 embed : boolean
36 embed : boolean
36 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
37 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
38 audio to playable later with no internet connection in the notebook.
39 audio to playable later with no internet connection in the notebook.
39
40
40 Default is `True`, unless the keyword argument `url` is set, then
41 Default is `True`, unless the keyword argument `url` is set, then
41 default value is `False`.
42 default value is `False`.
42 rate : integer
43 rate : integer
43 The sampling rate of the raw data.
44 The sampling rate of the raw data.
44 Only required when data parameter is being used as an array
45 Only required when data parameter is being used as an array
45 autoplay : bool
46 autoplay : bool
46 Set to True if the audio should immediately start playing.
47 Set to True if the audio should immediately start playing.
47 Default is `False`.
48 Default is `False`.
48
49
49 Examples
50 Examples
50 --------
51 --------
51
52
52 # Generate a sound
53 # Generate a sound
53 import numpy as np
54 import numpy as np
54 framerate = 44100
55 framerate = 44100
55 t = np.linspace(0,5,framerate*5)
56 t = np.linspace(0,5,framerate*5)
56 data = np.sin(2*np.pi*440*np.sin(10*t**2))
57 data = np.sin(2*np.pi*440*np.sin(10*t**2))
57 Audio(data,rate=framerate)
58 Audio(data,rate=framerate)
58
59
59 Audio("http://www.nch.com.au/acm/8k16bitpcm.wav")
60 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")
61 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)
62 Audio(url="http://www.w3schools.com/html/horse.ogg", embed=True)
62
63
63 Audio('/path/to/sound.wav')
64 Audio('/path/to/sound.wav')
64 Audio(filename='/path/to/sound.ogg')
65 Audio(filename='/path/to/sound.ogg')
65
66
66 Audio(b'RAW_WAV_DATA..)
67 Audio(b'RAW_WAV_DATA..)
67 Audio(data=b'RAW_WAV_DATA..)
68 Audio(data=b'RAW_WAV_DATA..)
68
69
69 """
70 """
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 print("Numpy is required to encode PCM from an array")
113 maxabsvalue = float(max([abs(x) for x in data]))
113 raise
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,\
284 raise ValueError,\
284 ("Cannot display a directory using FileLink. "
285 ("Cannot display a directory using FileLink. "
285 "Use FileLinks to display '%s'." % path)
286 "Use FileLinks to display '%s'." % path)
286 self.path = path
287 self.path = path
287 self.url_prefix = url_prefix
288 self.url_prefix = url_prefix
288 self.result_html_prefix = result_html_prefix
289 self.result_html_prefix = result_html_prefix
289 self.result_html_suffix = result_html_suffix
290 self.result_html_suffix = result_html_suffix
290
291
291 def _format_path(self):
292 def _format_path(self):
292 fp = ''.join([self.url_prefix,self.path])
293 fp = ''.join([self.url_prefix,self.path])
293 return ''.join([self.result_html_prefix,
294 return ''.join([self.result_html_prefix,
294 self.html_link_str % (fp, self.path),
295 self.html_link_str % (fp, self.path),
295 self.result_html_suffix])
296 self.result_html_suffix])
296
297
297 def _repr_html_(self):
298 def _repr_html_(self):
298 """return html link to file
299 """return html link to file
299 """
300 """
300 if not exists(self.path):
301 if not exists(self.path):
301 return ("Path (<tt>%s</tt>) doesn't exist. "
302 return ("Path (<tt>%s</tt>) doesn't exist. "
302 "It may still be in the process of "
303 "It may still be in the process of "
303 "being generated, or you may have the "
304 "being generated, or you may have the "
304 "incorrect path." % self.path)
305 "incorrect path." % self.path)
305
306
306 return self._format_path()
307 return self._format_path()
307
308
308 def __repr__(self):
309 def __repr__(self):
309 """return absolute path to file
310 """return absolute path to file
310 """
311 """
311 return abspath(self.path)
312 return abspath(self.path)
312
313
313 class FileLinks(FileLink):
314 class FileLinks(FileLink):
314 """Class for embedding local file links in an IPython session, based on path
315 """Class for embedding local file links in an IPython session, based on path
315
316
316 e.g. to embed links to files that were generated in the IPython notebook under my/data
317 e.g. to embed links to files that were generated in the IPython notebook under my/data
317
318
318 you would do:
319 you would do:
319
320
320 local_files = FileLinks("my/data")
321 local_files = FileLinks("my/data")
321 display(local_files)
322 display(local_files)
322
323
323 or in the HTML notebook, just
324 or in the HTML notebook, just
324
325
325 FileLinks("my/data")
326 FileLinks("my/data")
326
327
327 """
328 """
328 def __init__(self,
329 def __init__(self,
329 path,
330 path,
330 url_prefix='files/',
331 url_prefix='files/',
331 included_suffixes=None,
332 included_suffixes=None,
332 result_html_prefix='',
333 result_html_prefix='',
333 result_html_suffix='<br>',
334 result_html_suffix='<br>',
334 notebook_display_formatter=None,
335 notebook_display_formatter=None,
335 terminal_display_formatter=None):
336 terminal_display_formatter=None):
336 """
337 """
337 included_suffixes : list of filename suffixes to include when
338 included_suffixes : list of filename suffixes to include when
338 formatting output [default: include all files]
339 formatting output [default: include all files]
339
340
340 See the FileLink (baseclass of LocalDirectory) docstring for
341 See the FileLink (baseclass of LocalDirectory) docstring for
341 information on additional parameters.
342 information on additional parameters.
342
343
343 notebook_display_formatter : func used to format links for display
344 notebook_display_formatter : func used to format links for display
344 in the notebook. See discussion of formatter function below.
345 in the notebook. See discussion of formatter function below.
345
346
346 terminal_display_formatter : func used to format links for display
347 terminal_display_formatter : func used to format links for display
347 in the terminal. See discussion of formatter function below.
348 in the terminal. See discussion of formatter function below.
348
349
349
350
350 Passing custom formatter functions
351 Passing custom formatter functions
351 ----------------------------------
352 ----------------------------------
352 Formatter functions must be of the form:
353 Formatter functions must be of the form:
353 f(dirname, fnames, included_suffixes)
354 f(dirname, fnames, included_suffixes)
354 dirname : the name of a directory (a string),
355 dirname : the name of a directory (a string),
355 fnames : a list of the files in that directory
356 fnames : a list of the files in that directory
356 included_suffixes : a list of the file suffixes that should be
357 included_suffixes : a list of the file suffixes that should be
357 included in the output (passing None means
358 included in the output (passing None means
358 to include all suffixes in the output in
359 to include all suffixes in the output in
359 the built-in formatters)
360 the built-in formatters)
360
361
361 returns a list of lines that should will be print in the
362 returns a list of lines that should will be print in the
362 notebook (if passing notebook_display_formatter) or the terminal
363 notebook (if passing notebook_display_formatter) or the terminal
363 (if passing terminal_display_formatter). This function is iterated
364 (if passing terminal_display_formatter). This function is iterated
364 over for each directory in self.path. Default formatters are in
365 over for each directory in self.path. Default formatters are in
365 place, can be passed here to support alternative formatting.
366 place, can be passed here to support alternative formatting.
366
367
367 """
368 """
368 if isfile(path):
369 if isfile(path):
369 raise ValueError,\
370 raise ValueError,\
370 ("Cannot display a file using FileLinks. "
371 ("Cannot display a file using FileLinks. "
371 "Use FileLink to display '%s'." % path)
372 "Use FileLink to display '%s'." % path)
372 self.included_suffixes = included_suffixes
373 self.included_suffixes = included_suffixes
373 # remove trailing slashs for more consistent output formatting
374 # remove trailing slashs for more consistent output formatting
374 path = path.rstrip('/')
375 path = path.rstrip('/')
375
376
376 self.path = path
377 self.path = path
377 self.url_prefix = url_prefix
378 self.url_prefix = url_prefix
378 self.result_html_prefix = result_html_prefix
379 self.result_html_prefix = result_html_prefix
379 self.result_html_suffix = result_html_suffix
380 self.result_html_suffix = result_html_suffix
380
381
381 self.notebook_display_formatter = \
382 self.notebook_display_formatter = \
382 notebook_display_formatter or self._get_notebook_display_formatter()
383 notebook_display_formatter or self._get_notebook_display_formatter()
383 self.terminal_display_formatter = \
384 self.terminal_display_formatter = \
384 terminal_display_formatter or self._get_terminal_display_formatter()
385 terminal_display_formatter or self._get_terminal_display_formatter()
385
386
386 def _get_display_formatter(self,
387 def _get_display_formatter(self,
387 dirname_output_format,
388 dirname_output_format,
388 fname_output_format,
389 fname_output_format,
389 fp_format,
390 fp_format,
390 fp_cleaner=None):
391 fp_cleaner=None):
391 """ generate built-in formatter function
392 """ generate built-in formatter function
392
393
393 this is used to define both the notebook and terminal built-in
394 this is used to define both the notebook and terminal built-in
394 formatters as they only differ by some wrapper text for each entry
395 formatters as they only differ by some wrapper text for each entry
395
396
396 dirname_output_format: string to use for formatting directory
397 dirname_output_format: string to use for formatting directory
397 names, dirname will be substituted for a single "%s" which
398 names, dirname will be substituted for a single "%s" which
398 must appear in this string
399 must appear in this string
399 fname_output_format: string to use for formatting file names,
400 fname_output_format: string to use for formatting file names,
400 if a single "%s" appears in the string, fname will be substituted
401 if a single "%s" appears in the string, fname will be substituted
401 if two "%s" appear in the string, the path to fname will be
402 if two "%s" appear in the string, the path to fname will be
402 substituted for the first and fname will be substituted for the
403 substituted for the first and fname will be substituted for the
403 second
404 second
404 fp_format: string to use for formatting filepaths, must contain
405 fp_format: string to use for formatting filepaths, must contain
405 exactly two "%s" and the dirname will be subsituted for the first
406 exactly two "%s" and the dirname will be subsituted for the first
406 and fname will be substituted for the second
407 and fname will be substituted for the second
407 """
408 """
408 def f(dirname, fnames, included_suffixes=None):
409 def f(dirname, fnames, included_suffixes=None):
409 result = []
410 result = []
410 # begin by figuring out which filenames, if any,
411 # begin by figuring out which filenames, if any,
411 # are going to be displayed
412 # are going to be displayed
412 display_fnames = []
413 display_fnames = []
413 for fname in fnames:
414 for fname in fnames:
414 if (isfile(join(dirname,fname)) and
415 if (isfile(join(dirname,fname)) and
415 (included_suffixes == None or
416 (included_suffixes == None or
416 splitext(fname)[1] in included_suffixes)):
417 splitext(fname)[1] in included_suffixes)):
417 display_fnames.append(fname)
418 display_fnames.append(fname)
418
419
419 if len(display_fnames) == 0:
420 if len(display_fnames) == 0:
420 # if there are no filenames to display, don't print anything
421 # if there are no filenames to display, don't print anything
421 # (not even the directory name)
422 # (not even the directory name)
422 pass
423 pass
423 else:
424 else:
424 # otherwise print the formatted directory name followed by
425 # otherwise print the formatted directory name followed by
425 # the formatted filenames
426 # the formatted filenames
426 dirname_output_line = dirname_output_format % dirname
427 dirname_output_line = dirname_output_format % dirname
427 result.append(dirname_output_line)
428 result.append(dirname_output_line)
428 for fname in display_fnames:
429 for fname in display_fnames:
429 fp = fp_format % (dirname,fname)
430 fp = fp_format % (dirname,fname)
430 if fp_cleaner is not None:
431 if fp_cleaner is not None:
431 fp = fp_cleaner(fp)
432 fp = fp_cleaner(fp)
432 try:
433 try:
433 # output can include both a filepath and a filename...
434 # output can include both a filepath and a filename...
434 fname_output_line = fname_output_format % (fp, fname)
435 fname_output_line = fname_output_format % (fp, fname)
435 except TypeError:
436 except TypeError:
436 # ... or just a single filepath
437 # ... or just a single filepath
437 fname_output_line = fname_output_format % fname
438 fname_output_line = fname_output_format % fname
438 result.append(fname_output_line)
439 result.append(fname_output_line)
439 return result
440 return result
440 return f
441 return f
441
442
442 def _get_notebook_display_formatter(self,
443 def _get_notebook_display_formatter(self,
443 spacer="&nbsp;&nbsp;"):
444 spacer="&nbsp;&nbsp;"):
444 """ generate function to use for notebook formatting
445 """ generate function to use for notebook formatting
445 """
446 """
446 dirname_output_format = \
447 dirname_output_format = \
447 self.result_html_prefix + "%s/" + self.result_html_suffix
448 self.result_html_prefix + "%s/" + self.result_html_suffix
448 fname_output_format = \
449 fname_output_format = \
449 self.result_html_prefix + spacer + self.html_link_str + self.result_html_suffix
450 self.result_html_prefix + spacer + self.html_link_str + self.result_html_suffix
450 fp_format = self.url_prefix + '%s/%s'
451 fp_format = self.url_prefix + '%s/%s'
451 if sep == "\\":
452 if sep == "\\":
452 # Working on a platform where the path separator is "\", so
453 # Working on a platform where the path separator is "\", so
453 # must convert these to "/" for generating a URI
454 # must convert these to "/" for generating a URI
454 def fp_cleaner(fp):
455 def fp_cleaner(fp):
455 # Replace all occurences of backslash ("\") with a forward
456 # Replace all occurences of backslash ("\") with a forward
456 # slash ("/") - this is necessary on windows when a path is
457 # slash ("/") - this is necessary on windows when a path is
457 # provided as input, but we must link to a URI
458 # provided as input, but we must link to a URI
458 return fp.replace('\\','/')
459 return fp.replace('\\','/')
459 else:
460 else:
460 fp_cleaner = None
461 fp_cleaner = None
461
462
462 return self._get_display_formatter(dirname_output_format,
463 return self._get_display_formatter(dirname_output_format,
463 fname_output_format,
464 fname_output_format,
464 fp_format,
465 fp_format,
465 fp_cleaner)
466 fp_cleaner)
466
467
467 def _get_terminal_display_formatter(self,
468 def _get_terminal_display_formatter(self,
468 spacer=" "):
469 spacer=" "):
469 """ generate function to use for terminal formatting
470 """ generate function to use for terminal formatting
470 """
471 """
471 dirname_output_format = "%s/"
472 dirname_output_format = "%s/"
472 fname_output_format = spacer + "%s"
473 fname_output_format = spacer + "%s"
473 fp_format = '%s/%s'
474 fp_format = '%s/%s'
474
475
475 return self._get_display_formatter(dirname_output_format,
476 return self._get_display_formatter(dirname_output_format,
476 fname_output_format,
477 fname_output_format,
477 fp_format)
478 fp_format)
478
479
479 def _format_path(self):
480 def _format_path(self):
480 result_lines = []
481 result_lines = []
481 walked_dir = list(walk(self.path))
482 walked_dir = list(walk(self.path))
482 walked_dir.sort()
483 walked_dir.sort()
483 for dirname, subdirs, fnames in walked_dir:
484 for dirname, subdirs, fnames in walked_dir:
484 result_lines += self.notebook_display_formatter(dirname, fnames, self.included_suffixes)
485 result_lines += self.notebook_display_formatter(dirname, fnames, self.included_suffixes)
485 return '\n'.join(result_lines)
486 return '\n'.join(result_lines)
486
487
487 def __repr__(self):
488 def __repr__(self):
488 """return newline-separated absolute paths
489 """return newline-separated absolute paths
489 """
490 """
490 result_lines = []
491 result_lines = []
491 walked_dir = list(walk(self.path))
492 walked_dir = list(walk(self.path))
492 walked_dir.sort()
493 walked_dir.sort()
493 for dirname, subdirs, fnames in walked_dir:
494 for dirname, subdirs, fnames in walked_dir:
494 result_lines += self.terminal_display_formatter(dirname, fnames, self.included_suffixes)
495 result_lines += self.terminal_display_formatter(dirname, fnames, self.included_suffixes)
495 return '\n'.join(result_lines)
496 return '\n'.join(result_lines)
General Comments 0
You need to be logged in to leave comments. Login now