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