##// END OF EJS Templates
Remove unused imports in IPython.lib
Thomas Kluyver -
Show More
@@ -1,529 +1,528 b''
1 1 # coding: utf-8
2 2 """
3 3 Inputhook management for GUI event loop integration.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 try:
18 18 import ctypes
19 19 except ImportError:
20 20 ctypes = None
21 21 import os
22 22 import sys
23 23 from distutils.version import LooseVersion as V
24 24
25 25 from IPython.utils.warn import warn
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Constants
29 29 #-----------------------------------------------------------------------------
30 30
31 31 # Constants for identifying the GUI toolkits.
32 32 GUI_WX = 'wx'
33 33 GUI_QT = 'qt'
34 34 GUI_QT4 = 'qt4'
35 35 GUI_GTK = 'gtk'
36 36 GUI_TK = 'tk'
37 37 GUI_OSX = 'osx'
38 38 GUI_GLUT = 'glut'
39 39 GUI_PYGLET = 'pyglet'
40 40 GUI_GTK3 = 'gtk3'
41 41 GUI_NONE = 'none' # i.e. disable
42 42
43 43 #-----------------------------------------------------------------------------
44 44 # Utilities
45 45 #-----------------------------------------------------------------------------
46 46
47 47 def _stdin_ready_posix():
48 48 """Return True if there's something to read on stdin (posix version)."""
49 49 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
50 50 return bool(infds)
51 51
52 52 def _stdin_ready_nt():
53 53 """Return True if there's something to read on stdin (nt version)."""
54 54 return msvcrt.kbhit()
55 55
56 56 def _stdin_ready_other():
57 57 """Return True, assuming there's something to read on stdin."""
58 58 return True #
59 59
60 60
61 61 def _ignore_CTRL_C_posix():
62 62 """Ignore CTRL+C (SIGINT)."""
63 63 signal.signal(signal.SIGINT, signal.SIG_IGN)
64 64
65 65 def _allow_CTRL_C_posix():
66 66 """Take CTRL+C into account (SIGINT)."""
67 67 signal.signal(signal.SIGINT, signal.default_int_handler)
68 68
69 69 def _ignore_CTRL_C_other():
70 70 """Ignore CTRL+C (not implemented)."""
71 71 pass
72 72
73 73 def _allow_CTRL_C_other():
74 74 """Take CTRL+C into account (not implemented)."""
75 75 pass
76 76
77 77 if os.name == 'posix':
78 78 import select
79 79 import signal
80 80 stdin_ready = _stdin_ready_posix
81 81 ignore_CTRL_C = _ignore_CTRL_C_posix
82 82 allow_CTRL_C = _allow_CTRL_C_posix
83 83 elif os.name == 'nt':
84 84 import msvcrt
85 85 stdin_ready = _stdin_ready_nt
86 86 ignore_CTRL_C = _ignore_CTRL_C_other
87 87 allow_CTRL_C = _allow_CTRL_C_other
88 88 else:
89 89 stdin_ready = _stdin_ready_other
90 90 ignore_CTRL_C = _ignore_CTRL_C_other
91 91 allow_CTRL_C = _allow_CTRL_C_other
92 92
93 93
94 94 #-----------------------------------------------------------------------------
95 95 # Main InputHookManager class
96 96 #-----------------------------------------------------------------------------
97 97
98 98
99 99 class InputHookManager(object):
100 100 """Manage PyOS_InputHook for different GUI toolkits.
101 101
102 102 This class installs various hooks under ``PyOSInputHook`` to handle
103 103 GUI event loop integration.
104 104 """
105 105
106 106 def __init__(self):
107 107 if ctypes is None:
108 108 warn("IPython GUI event loop requires ctypes, %gui will not be available")
109 109 return
110 110 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
111 111 self._apps = {}
112 112 self._reset()
113 113
114 114 def _reset(self):
115 115 self._callback_pyfunctype = None
116 116 self._callback = None
117 117 self._installed = False
118 118 self._current_gui = None
119 119
120 120 def get_pyos_inputhook(self):
121 121 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
122 122 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
123 123
124 124 def get_pyos_inputhook_as_func(self):
125 125 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
126 126 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
127 127
128 128 def set_inputhook(self, callback):
129 129 """Set PyOS_InputHook to callback and return the previous one."""
130 130 # On platforms with 'readline' support, it's all too likely to
131 131 # have a KeyboardInterrupt signal delivered *even before* an
132 132 # initial ``try:`` clause in the callback can be executed, so
133 133 # we need to disable CTRL+C in this situation.
134 134 ignore_CTRL_C()
135 135 self._callback = callback
136 136 self._callback_pyfunctype = self.PYFUNC(callback)
137 137 pyos_inputhook_ptr = self.get_pyos_inputhook()
138 138 original = self.get_pyos_inputhook_as_func()
139 139 pyos_inputhook_ptr.value = \
140 140 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
141 141 self._installed = True
142 142 return original
143 143
144 144 def clear_inputhook(self, app=None):
145 145 """Set PyOS_InputHook to NULL and return the previous one.
146 146
147 147 Parameters
148 148 ----------
149 149 app : optional, ignored
150 150 This parameter is allowed only so that clear_inputhook() can be
151 151 called with a similar interface as all the ``enable_*`` methods. But
152 152 the actual value of the parameter is ignored. This uniform interface
153 153 makes it easier to have user-level entry points in the main IPython
154 154 app like :meth:`enable_gui`."""
155 155 pyos_inputhook_ptr = self.get_pyos_inputhook()
156 156 original = self.get_pyos_inputhook_as_func()
157 157 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
158 158 allow_CTRL_C()
159 159 self._reset()
160 160 return original
161 161
162 162 def clear_app_refs(self, gui=None):
163 163 """Clear IPython's internal reference to an application instance.
164 164
165 165 Whenever we create an app for a user on qt4 or wx, we hold a
166 166 reference to the app. This is needed because in some cases bad things
167 167 can happen if a user doesn't hold a reference themselves. This
168 168 method is provided to clear the references we are holding.
169 169
170 170 Parameters
171 171 ----------
172 172 gui : None or str
173 173 If None, clear all app references. If ('wx', 'qt4') clear
174 174 the app for that toolkit. References are not held for gtk or tk
175 175 as those toolkits don't have the notion of an app.
176 176 """
177 177 if gui is None:
178 178 self._apps = {}
179 179 elif gui in self._apps:
180 180 del self._apps[gui]
181 181
182 182 def enable_wx(self, app=None):
183 183 """Enable event loop integration with wxPython.
184 184
185 185 Parameters
186 186 ----------
187 187 app : WX Application, optional.
188 188 Running application to use. If not given, we probe WX for an
189 189 existing application object, and create a new one if none is found.
190 190
191 191 Notes
192 192 -----
193 193 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
194 194 the wxPython to integrate with terminal based applications like
195 195 IPython.
196 196
197 197 If ``app`` is not given we probe for an existing one, and return it if
198 198 found. If no existing app is found, we create an :class:`wx.App` as
199 199 follows::
200 200
201 201 import wx
202 202 app = wx.App(redirect=False, clearSigInt=False)
203 203 """
204 204 import wx
205 205
206 206 wx_version = V(wx.__version__).version
207 207
208 208 if wx_version < [2, 8]:
209 209 raise ValueError("requires wxPython >= 2.8, but you have %s" % wx.__version__)
210 210
211 211 from IPython.lib.inputhookwx import inputhook_wx
212 212 self.set_inputhook(inputhook_wx)
213 213 self._current_gui = GUI_WX
214 214 import wx
215 215 if app is None:
216 216 app = wx.GetApp()
217 217 if app is None:
218 218 app = wx.App(redirect=False, clearSigInt=False)
219 219 app._in_event_loop = True
220 220 self._apps[GUI_WX] = app
221 221 return app
222 222
223 223 def disable_wx(self):
224 224 """Disable event loop integration with wxPython.
225 225
226 226 This merely sets PyOS_InputHook to NULL.
227 227 """
228 228 if GUI_WX in self._apps:
229 229 self._apps[GUI_WX]._in_event_loop = False
230 230 self.clear_inputhook()
231 231
232 232 def enable_qt4(self, app=None):
233 233 """Enable event loop integration with PyQt4.
234 234
235 235 Parameters
236 236 ----------
237 237 app : Qt Application, optional.
238 238 Running application to use. If not given, we probe Qt for an
239 239 existing application object, and create a new one if none is found.
240 240
241 241 Notes
242 242 -----
243 243 This methods sets the PyOS_InputHook for PyQt4, which allows
244 244 the PyQt4 to integrate with terminal based applications like
245 245 IPython.
246 246
247 247 If ``app`` is not given we probe for an existing one, and return it if
248 248 found. If no existing app is found, we create an :class:`QApplication`
249 249 as follows::
250 250
251 251 from PyQt4 import QtCore
252 252 app = QtGui.QApplication(sys.argv)
253 253 """
254 254 from IPython.lib.inputhookqt4 import create_inputhook_qt4
255 255 app, inputhook_qt4 = create_inputhook_qt4(self, app)
256 256 self.set_inputhook(inputhook_qt4)
257 257
258 258 self._current_gui = GUI_QT4
259 259 app._in_event_loop = True
260 260 self._apps[GUI_QT4] = app
261 261 return app
262 262
263 263 def disable_qt4(self):
264 264 """Disable event loop integration with PyQt4.
265 265
266 266 This merely sets PyOS_InputHook to NULL.
267 267 """
268 268 if GUI_QT4 in self._apps:
269 269 self._apps[GUI_QT4]._in_event_loop = False
270 270 self.clear_inputhook()
271 271
272 272 def enable_gtk(self, app=None):
273 273 """Enable event loop integration with PyGTK.
274 274
275 275 Parameters
276 276 ----------
277 277 app : ignored
278 278 Ignored, it's only a placeholder to keep the call signature of all
279 279 gui activation methods consistent, which simplifies the logic of
280 280 supporting magics.
281 281
282 282 Notes
283 283 -----
284 284 This methods sets the PyOS_InputHook for PyGTK, which allows
285 285 the PyGTK to integrate with terminal based applications like
286 286 IPython.
287 287 """
288 288 import gtk
289 289 try:
290 290 gtk.set_interactive(True)
291 291 self._current_gui = GUI_GTK
292 292 except AttributeError:
293 293 # For older versions of gtk, use our own ctypes version
294 294 from IPython.lib.inputhookgtk import inputhook_gtk
295 295 self.set_inputhook(inputhook_gtk)
296 296 self._current_gui = GUI_GTK
297 297
298 298 def disable_gtk(self):
299 299 """Disable event loop integration with PyGTK.
300 300
301 301 This merely sets PyOS_InputHook to NULL.
302 302 """
303 303 self.clear_inputhook()
304 304
305 305 def enable_tk(self, app=None):
306 306 """Enable event loop integration with Tk.
307 307
308 308 Parameters
309 309 ----------
310 310 app : toplevel :class:`Tkinter.Tk` widget, optional.
311 311 Running toplevel widget to use. If not given, we probe Tk for an
312 312 existing one, and create a new one if none is found.
313 313
314 314 Notes
315 315 -----
316 316 If you have already created a :class:`Tkinter.Tk` object, the only
317 317 thing done by this method is to register with the
318 318 :class:`InputHookManager`, since creating that object automatically
319 319 sets ``PyOS_InputHook``.
320 320 """
321 321 self._current_gui = GUI_TK
322 322 if app is None:
323 323 import Tkinter
324 324 app = Tkinter.Tk()
325 325 app.withdraw()
326 326 self._apps[GUI_TK] = app
327 327 return app
328 328
329 329 def disable_tk(self):
330 330 """Disable event loop integration with Tkinter.
331 331
332 332 This merely sets PyOS_InputHook to NULL.
333 333 """
334 334 self.clear_inputhook()
335 335
336 336
337 337 def enable_glut(self, app=None):
338 338 """ Enable event loop integration with GLUT.
339 339
340 340 Parameters
341 341 ----------
342 342
343 343 app : ignored
344 344 Ignored, it's only a placeholder to keep the call signature of all
345 345 gui activation methods consistent, which simplifies the logic of
346 346 supporting magics.
347 347
348 348 Notes
349 349 -----
350 350
351 351 This methods sets the PyOS_InputHook for GLUT, which allows the GLUT to
352 352 integrate with terminal based applications like IPython. Due to GLUT
353 353 limitations, it is currently not possible to start the event loop
354 354 without first creating a window. You should thus not create another
355 355 window but use instead the created one. See 'gui-glut.py' in the
356 356 docs/examples/lib directory.
357 357
358 358 The default screen mode is set to:
359 359 glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH
360 360 """
361 361
362 362 import OpenGL.GLUT as glut
363 363 from IPython.lib.inputhookglut import glut_display_mode, \
364 364 glut_close, glut_display, \
365 365 glut_idle, inputhook_glut
366 366
367 367 if GUI_GLUT not in self._apps:
368 368 glut.glutInit( sys.argv )
369 369 glut.glutInitDisplayMode( glut_display_mode )
370 370 # This is specific to freeglut
371 371 if bool(glut.glutSetOption):
372 372 glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
373 373 glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
374 374 glut.glutCreateWindow( sys.argv[0] )
375 375 glut.glutReshapeWindow( 1, 1 )
376 376 glut.glutHideWindow( )
377 377 glut.glutWMCloseFunc( glut_close )
378 378 glut.glutDisplayFunc( glut_display )
379 379 glut.glutIdleFunc( glut_idle )
380 380 else:
381 381 glut.glutWMCloseFunc( glut_close )
382 382 glut.glutDisplayFunc( glut_display )
383 383 glut.glutIdleFunc( glut_idle)
384 384 self.set_inputhook( inputhook_glut )
385 385 self._current_gui = GUI_GLUT
386 386 self._apps[GUI_GLUT] = True
387 387
388 388
389 389 def disable_glut(self):
390 390 """Disable event loop integration with glut.
391 391
392 392 This sets PyOS_InputHook to NULL and set the display function to a
393 393 dummy one and set the timer to a dummy timer that will be triggered
394 394 very far in the future.
395 395 """
396 396 import OpenGL.GLUT as glut
397 397 from glut_support import glutMainLoopEvent
398 398
399 399 glut.glutHideWindow() # This is an event to be processed below
400 400 glutMainLoopEvent()
401 401 self.clear_inputhook()
402 402
403 403 def enable_pyglet(self, app=None):
404 404 """Enable event loop integration with pyglet.
405 405
406 406 Parameters
407 407 ----------
408 408 app : ignored
409 409 Ignored, it's only a placeholder to keep the call signature of all
410 410 gui activation methods consistent, which simplifies the logic of
411 411 supporting magics.
412 412
413 413 Notes
414 414 -----
415 415 This methods sets the ``PyOS_InputHook`` for pyglet, which allows
416 416 pyglet to integrate with terminal based applications like
417 417 IPython.
418 418
419 419 """
420 import pyglet
421 420 from IPython.lib.inputhookpyglet import inputhook_pyglet
422 421 self.set_inputhook(inputhook_pyglet)
423 422 self._current_gui = GUI_PYGLET
424 423 return app
425 424
426 425 def disable_pyglet(self):
427 426 """Disable event loop integration with pyglet.
428 427
429 428 This merely sets PyOS_InputHook to NULL.
430 429 """
431 430 self.clear_inputhook()
432 431
433 432 def enable_gtk3(self, app=None):
434 433 """Enable event loop integration with Gtk3 (gir bindings).
435 434
436 435 Parameters
437 436 ----------
438 437 app : ignored
439 438 Ignored, it's only a placeholder to keep the call signature of all
440 439 gui activation methods consistent, which simplifies the logic of
441 440 supporting magics.
442 441
443 442 Notes
444 443 -----
445 444 This methods sets the PyOS_InputHook for Gtk3, which allows
446 445 the Gtk3 to integrate with terminal based applications like
447 446 IPython.
448 447 """
449 448 from IPython.lib.inputhookgtk3 import inputhook_gtk3
450 449 self.set_inputhook(inputhook_gtk3)
451 450 self._current_gui = GUI_GTK
452 451
453 452 def disable_gtk3(self):
454 453 """Disable event loop integration with PyGTK.
455 454
456 455 This merely sets PyOS_InputHook to NULL.
457 456 """
458 457 self.clear_inputhook()
459 458
460 459 def current_gui(self):
461 460 """Return a string indicating the currently active GUI or None."""
462 461 return self._current_gui
463 462
464 463 inputhook_manager = InputHookManager()
465 464
466 465 enable_wx = inputhook_manager.enable_wx
467 466 disable_wx = inputhook_manager.disable_wx
468 467 enable_qt4 = inputhook_manager.enable_qt4
469 468 disable_qt4 = inputhook_manager.disable_qt4
470 469 enable_gtk = inputhook_manager.enable_gtk
471 470 disable_gtk = inputhook_manager.disable_gtk
472 471 enable_tk = inputhook_manager.enable_tk
473 472 disable_tk = inputhook_manager.disable_tk
474 473 enable_glut = inputhook_manager.enable_glut
475 474 disable_glut = inputhook_manager.disable_glut
476 475 enable_pyglet = inputhook_manager.enable_pyglet
477 476 disable_pyglet = inputhook_manager.disable_pyglet
478 477 enable_gtk3 = inputhook_manager.enable_gtk3
479 478 disable_gtk3 = inputhook_manager.disable_gtk3
480 479 clear_inputhook = inputhook_manager.clear_inputhook
481 480 set_inputhook = inputhook_manager.set_inputhook
482 481 current_gui = inputhook_manager.current_gui
483 482 clear_app_refs = inputhook_manager.clear_app_refs
484 483
485 484
486 485 # Convenience function to switch amongst them
487 486 def enable_gui(gui=None, app=None):
488 487 """Switch amongst GUI input hooks by name.
489 488
490 489 This is just a utility wrapper around the methods of the InputHookManager
491 490 object.
492 491
493 492 Parameters
494 493 ----------
495 494 gui : optional, string or None
496 495 If None (or 'none'), clears input hook, otherwise it must be one
497 496 of the recognized GUI names (see ``GUI_*`` constants in module).
498 497
499 498 app : optional, existing application object.
500 499 For toolkits that have the concept of a global app, you can supply an
501 500 existing one. If not given, the toolkit will be probed for one, and if
502 501 none is found, a new one will be created. Note that GTK does not have
503 502 this concept, and passing an app if ``gui=="GTK"`` will raise an error.
504 503
505 504 Returns
506 505 -------
507 506 The output of the underlying gui switch routine, typically the actual
508 507 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
509 508 one.
510 509 """
511 510 guis = {None: clear_inputhook,
512 511 GUI_NONE: clear_inputhook,
513 512 GUI_OSX: lambda app=False: None,
514 513 GUI_TK: enable_tk,
515 514 GUI_GTK: enable_gtk,
516 515 GUI_WX: enable_wx,
517 516 GUI_QT: enable_qt4, # qt3 not supported
518 517 GUI_QT4: enable_qt4,
519 518 GUI_GLUT: enable_glut,
520 519 GUI_PYGLET: enable_pyglet,
521 520 GUI_GTK3: enable_gtk3,
522 521 }
523 522 try:
524 523 gui_hook = guis[gui]
525 524 except KeyError:
526 525 e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
527 526 raise ValueError(e)
528 527 return gui_hook(app)
529 528
@@ -1,176 +1,175 b''
1 1 # coding: utf-8
2 2 """
3 3 GLUT Inputhook support functions
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 # GLUT is quite an old library and it is difficult to ensure proper
14 14 # integration within IPython since original GLUT does not allow to handle
15 15 # events one by one. Instead, it requires for the mainloop to be entered
16 16 # and never returned (there is not even a function to exit he
17 17 # mainloop). Fortunately, there are alternatives such as freeglut
18 18 # (available for linux and windows) and the OSX implementation gives
19 19 # access to a glutCheckLoop() function that blocks itself until a new
20 20 # event is received. This means we have to setup the idle callback to
21 21 # ensure we got at least one event that will unblock the function.
22 22 #
23 23 # Furthermore, it is not possible to install these handlers without a window
24 24 # being first created. We choose to make this window invisible. This means that
25 25 # display mode options are set at this level and user won't be able to change
26 26 # them later without modifying the code. This should probably be made available
27 27 # via IPython options system.
28 28
29 29 #-----------------------------------------------------------------------------
30 30 # Imports
31 31 #-----------------------------------------------------------------------------
32 32 import os
33 33 import sys
34 34 import time
35 35 import signal
36 import OpenGL
37 36 import OpenGL.GLUT as glut
38 37 import OpenGL.platform as platform
39 38 from timeit import default_timer as clock
40 39
41 40 #-----------------------------------------------------------------------------
42 41 # Constants
43 42 #-----------------------------------------------------------------------------
44 43
45 44 # Frame per second : 60
46 45 # Should probably be an IPython option
47 46 glut_fps = 60
48 47
49 48
50 49 # Display mode : double buffeed + rgba + depth
51 50 # Should probably be an IPython option
52 51 glut_display_mode = (glut.GLUT_DOUBLE |
53 52 glut.GLUT_RGBA |
54 53 glut.GLUT_DEPTH)
55 54
56 55 glutMainLoopEvent = None
57 56 if sys.platform == 'darwin':
58 57 try:
59 58 glutCheckLoop = platform.createBaseFunction(
60 59 'glutCheckLoop', dll=platform.GLUT, resultType=None,
61 60 argTypes=[],
62 61 doc='glutCheckLoop( ) -> None',
63 62 argNames=(),
64 63 )
65 64 except AttributeError:
66 65 raise RuntimeError(
67 66 '''Your glut implementation does not allow interactive sessions'''
68 67 '''Consider installing freeglut.''')
69 68 glutMainLoopEvent = glutCheckLoop
70 69 elif glut.HAVE_FREEGLUT:
71 70 glutMainLoopEvent = glut.glutMainLoopEvent
72 71 else:
73 72 raise RuntimeError(
74 73 '''Your glut implementation does not allow interactive sessions. '''
75 74 '''Consider installing freeglut.''')
76 75
77 76
78 77 #-----------------------------------------------------------------------------
79 78 # Platform-dependent imports and functions
80 79 #-----------------------------------------------------------------------------
81 80
82 81 if os.name == 'posix':
83 82 import select
84 83
85 84 def stdin_ready():
86 85 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
87 86 if infds:
88 87 return True
89 88 else:
90 89 return False
91 90
92 91 elif sys.platform == 'win32':
93 92 import msvcrt
94 93
95 94 def stdin_ready():
96 95 return msvcrt.kbhit()
97 96
98 97 #-----------------------------------------------------------------------------
99 98 # Callback functions
100 99 #-----------------------------------------------------------------------------
101 100
102 101 def glut_display():
103 102 # Dummy display function
104 103 pass
105 104
106 105 def glut_idle():
107 106 # Dummy idle function
108 107 pass
109 108
110 109 def glut_close():
111 110 # Close function only hides the current window
112 111 glut.glutHideWindow()
113 112 glutMainLoopEvent()
114 113
115 114 def glut_int_handler(signum, frame):
116 115 # Catch sigint and print the defautl message
117 116 signal.signal(signal.SIGINT, signal.default_int_handler)
118 117 print '\nKeyboardInterrupt'
119 118 # Need to reprint the prompt at this stage
120 119
121 120
122 121
123 122 #-----------------------------------------------------------------------------
124 123 # Code
125 124 #-----------------------------------------------------------------------------
126 125 def inputhook_glut():
127 126 """Run the pyglet event loop by processing pending events only.
128 127
129 128 This keeps processing pending events until stdin is ready. After
130 129 processing all pending events, a call to time.sleep is inserted. This is
131 130 needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
132 131 though for best performance.
133 132 """
134 133 # We need to protect against a user pressing Control-C when IPython is
135 134 # idle and this is running. We trap KeyboardInterrupt and pass.
136 135
137 136 signal.signal(signal.SIGINT, glut_int_handler)
138 137
139 138 try:
140 139 t = clock()
141 140
142 141 # Make sure the default window is set after a window has been closed
143 142 if glut.glutGetWindow() == 0:
144 143 glut.glutSetWindow( 1 )
145 144 glutMainLoopEvent()
146 145 return 0
147 146
148 147 while not stdin_ready():
149 148 glutMainLoopEvent()
150 149 # We need to sleep at this point to keep the idle CPU load
151 150 # low. However, if sleep to long, GUI response is poor. As
152 151 # a compromise, we watch how often GUI events are being processed
153 152 # and switch between a short and long sleep time. Here are some
154 153 # stats useful in helping to tune this.
155 154 # time CPU load
156 155 # 0.001 13%
157 156 # 0.005 3%
158 157 # 0.01 1.5%
159 158 # 0.05 0.5%
160 159 used_time = clock() - t
161 160 if used_time > 5*60.0:
162 161 # print 'Sleep for 5 s' # dbg
163 162 time.sleep(5.0)
164 163 elif used_time > 10.0:
165 164 # print 'Sleep for 1 s' # dbg
166 165 time.sleep(1.0)
167 166 elif used_time > 0.1:
168 167 # Few GUI events coming in, so we can sleep longer
169 168 # print 'Sleep for 0.05 s' # dbg
170 169 time.sleep(0.05)
171 170 else:
172 171 # Many GUI events coming in, so sleep only very little
173 172 time.sleep(0.001)
174 173 except KeyboardInterrupt:
175 174 pass
176 175 return 0
@@ -1,115 +1,114 b''
1 1 # encoding: utf-8
2 2 """
3 3 Enable pyglet to be used interacive by setting PyOS_InputHook.
4 4
5 5 Authors
6 6 -------
7 7
8 8 * Nicolas P. Rougier
9 9 * Fernando Perez
10 10 """
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Copyright (C) 2008-2011 The IPython Development Team
14 14 #
15 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 import os
24 import signal
25 24 import sys
26 25 import time
27 26 from timeit import default_timer as clock
28 27 import pyglet
29 28
30 29 #-----------------------------------------------------------------------------
31 30 # Platform-dependent imports and functions
32 31 #-----------------------------------------------------------------------------
33 32
34 33 if os.name == 'posix':
35 34 import select
36 35
37 36 def stdin_ready():
38 37 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
39 38 if infds:
40 39 return True
41 40 else:
42 41 return False
43 42
44 43 elif sys.platform == 'win32':
45 44 import msvcrt
46 45
47 46 def stdin_ready():
48 47 return msvcrt.kbhit()
49 48
50 49
51 50 # On linux only, window.flip() has a bug that causes an AttributeError on
52 51 # window close. For details, see:
53 52 # http://groups.google.com/group/pyglet-users/browse_thread/thread/47c1aab9aa4a3d23/c22f9e819826799e?#c22f9e819826799e
54 53
55 54 if sys.platform.startswith('linux'):
56 55 def flip(window):
57 56 try:
58 57 window.flip()
59 58 except AttributeError:
60 59 pass
61 60 else:
62 61 def flip(window):
63 62 window.flip()
64 63
65 64 #-----------------------------------------------------------------------------
66 65 # Code
67 66 #-----------------------------------------------------------------------------
68 67
69 68 def inputhook_pyglet():
70 69 """Run the pyglet event loop by processing pending events only.
71 70
72 71 This keeps processing pending events until stdin is ready. After
73 72 processing all pending events, a call to time.sleep is inserted. This is
74 73 needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
75 74 though for best performance.
76 75 """
77 76 # We need to protect against a user pressing Control-C when IPython is
78 77 # idle and this is running. We trap KeyboardInterrupt and pass.
79 78 try:
80 79 t = clock()
81 80 while not stdin_ready():
82 81 pyglet.clock.tick()
83 82 for window in pyglet.app.windows:
84 83 window.switch_to()
85 84 window.dispatch_events()
86 85 window.dispatch_event('on_draw')
87 86 flip(window)
88 87
89 88 # We need to sleep at this point to keep the idle CPU load
90 89 # low. However, if sleep to long, GUI response is poor. As
91 90 # a compromise, we watch how often GUI events are being processed
92 91 # and switch between a short and long sleep time. Here are some
93 92 # stats useful in helping to tune this.
94 93 # time CPU load
95 94 # 0.001 13%
96 95 # 0.005 3%
97 96 # 0.01 1.5%
98 97 # 0.05 0.5%
99 98 used_time = clock() - t
100 99 if used_time > 5*60.0:
101 100 # print 'Sleep for 5 s' # dbg
102 101 time.sleep(5.0)
103 102 elif used_time > 10.0:
104 103 # print 'Sleep for 1 s' # dbg
105 104 time.sleep(1.0)
106 105 elif used_time > 0.1:
107 106 # Few GUI events coming in, so we can sleep longer
108 107 # print 'Sleep for 0.05 s' # dbg
109 108 time.sleep(0.05)
110 109 else:
111 110 # Many GUI events coming in, so sleep only very little
112 111 time.sleep(0.001)
113 112 except KeyboardInterrupt:
114 113 pass
115 114 return 0
@@ -1,181 +1,180 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Qt4's inputhook support function
4 4
5 5 Author: Christian Boos
6 6 """
7 7
8 8 #-----------------------------------------------------------------------------
9 9 # Copyright (C) 2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 import os
20 20 import signal
21 import time
22 21 import threading
23 22
24 23 from IPython.core.interactiveshell import InteractiveShell
25 24 from IPython.external.qt_for_kernel import QtCore, QtGui
26 25 from IPython.lib.inputhook import allow_CTRL_C, ignore_CTRL_C, stdin_ready
27 26
28 27 #-----------------------------------------------------------------------------
29 28 # Module Globals
30 29 #-----------------------------------------------------------------------------
31 30
32 31 got_kbdint = False
33 32 sigint_timer = None
34 33
35 34 #-----------------------------------------------------------------------------
36 35 # Code
37 36 #-----------------------------------------------------------------------------
38 37
39 38 def create_inputhook_qt4(mgr, app=None):
40 39 """Create an input hook for running the Qt4 application event loop.
41 40
42 41 Parameters
43 42 ----------
44 43 mgr : an InputHookManager
45 44
46 45 app : Qt Application, optional.
47 46 Running application to use. If not given, we probe Qt for an
48 47 existing application object, and create a new one if none is found.
49 48
50 49 Returns
51 50 -------
52 51 A pair consisting of a Qt Application (either the one given or the
53 52 one found or created) and a inputhook.
54 53
55 54 Notes
56 55 -----
57 56 We use a custom input hook instead of PyQt4's default one, as it
58 57 interacts better with the readline packages (issue #481).
59 58
60 59 The inputhook function works in tandem with a 'pre_prompt_hook'
61 60 which automatically restores the hook as an inputhook in case the
62 61 latter has been temporarily disabled after having intercepted a
63 62 KeyboardInterrupt.
64 63 """
65 64
66 65 if app is None:
67 66 app = QtCore.QCoreApplication.instance()
68 67 if app is None:
69 68 app = QtGui.QApplication([" "])
70 69
71 70 # Re-use previously created inputhook if any
72 71 ip = InteractiveShell.instance()
73 72 if hasattr(ip, '_inputhook_qt4'):
74 73 return app, ip._inputhook_qt4
75 74
76 75 # Otherwise create the inputhook_qt4/preprompthook_qt4 pair of
77 76 # hooks (they both share the got_kbdint flag)
78 77
79 78 def inputhook_qt4():
80 79 """PyOS_InputHook python hook for Qt4.
81 80
82 81 Process pending Qt events and if there's no pending keyboard
83 82 input, spend a short slice of time (50ms) running the Qt event
84 83 loop.
85 84
86 85 As a Python ctypes callback can't raise an exception, we catch
87 86 the KeyboardInterrupt and temporarily deactivate the hook,
88 87 which will let a *second* CTRL+C be processed normally and go
89 88 back to a clean prompt line.
90 89 """
91 90 try:
92 91 allow_CTRL_C()
93 92 app = QtCore.QCoreApplication.instance()
94 93 if not app: # shouldn't happen, but safer if it happens anyway...
95 94 return 0
96 95 app.processEvents(QtCore.QEventLoop.AllEvents, 300)
97 96 if not stdin_ready():
98 97 # Generally a program would run QCoreApplication::exec()
99 98 # from main() to enter and process the Qt event loop until
100 99 # quit() or exit() is called and the program terminates.
101 100 #
102 101 # For our input hook integration, we need to repeatedly
103 102 # enter and process the Qt event loop for only a short
104 103 # amount of time (say 50ms) to ensure that Python stays
105 104 # responsive to other user inputs.
106 105 #
107 106 # A naive approach would be to repeatedly call
108 107 # QCoreApplication::exec(), using a timer to quit after a
109 108 # short amount of time. Unfortunately, QCoreApplication
110 109 # emits an aboutToQuit signal before stopping, which has
111 110 # the undesirable effect of closing all modal windows.
112 111 #
113 112 # To work around this problem, we instead create a
114 113 # QEventLoop and call QEventLoop::exec(). Other than
115 114 # setting some state variables which do not seem to be
116 115 # used anywhere, the only thing QCoreApplication adds is
117 116 # the aboutToQuit signal which is precisely what we are
118 117 # trying to avoid.
119 118 timer = QtCore.QTimer()
120 119 event_loop = QtCore.QEventLoop()
121 120 timer.timeout.connect(event_loop.quit)
122 121 while not stdin_ready():
123 122 timer.start(50)
124 123 event_loop.exec_()
125 124 timer.stop()
126 125 except KeyboardInterrupt:
127 126 global got_kbdint, sigint_timer
128 127
129 128 ignore_CTRL_C()
130 129 got_kbdint = True
131 130 mgr.clear_inputhook()
132 131
133 132 # This generates a second SIGINT so the user doesn't have to
134 133 # press CTRL+C twice to get a clean prompt.
135 134 #
136 135 # Since we can't catch the resulting KeyboardInterrupt here
137 136 # (because this is a ctypes callback), we use a timer to
138 137 # generate the SIGINT after we leave this callback.
139 138 #
140 139 # Unfortunately this doesn't work on Windows (SIGINT kills
141 140 # Python and CTRL_C_EVENT doesn't work).
142 141 if(os.name == 'posix'):
143 142 pid = os.getpid()
144 143 if(not sigint_timer):
145 144 sigint_timer = threading.Timer(.01, os.kill,
146 145 args=[pid, signal.SIGINT] )
147 146 sigint_timer.start()
148 147 else:
149 148 print("\nKeyboardInterrupt - Ctrl-C again for new prompt")
150 149
151 150
152 151 except: # NO exceptions are allowed to escape from a ctypes callback
153 152 ignore_CTRL_C()
154 153 from traceback import print_exc
155 154 print_exc()
156 155 print("Got exception from inputhook_qt4, unregistering.")
157 156 mgr.clear_inputhook()
158 157 finally:
159 158 allow_CTRL_C()
160 159 return 0
161 160
162 161 def preprompthook_qt4(ishell):
163 162 """'pre_prompt_hook' used to restore the Qt4 input hook
164 163
165 164 (in case the latter was temporarily deactivated after a
166 165 CTRL+C)
167 166 """
168 167 global got_kbdint, sigint_timer
169 168
170 169 if(sigint_timer):
171 170 sigint_timer.cancel()
172 171 sigint_timer = None
173 172
174 173 if got_kbdint:
175 174 mgr.set_inputhook(inputhook_qt4)
176 175 got_kbdint = False
177 176
178 177 ip._inputhook_qt4 = inputhook_qt4
179 178 ip.set_hook('pre_prompt_hook', preprompthook_qt4)
180 179
181 180 return app, inputhook_qt4
@@ -1,91 +1,89 b''
1 1 """Tests for pylab tools module.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2011, the IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14 from __future__ import print_function
15 15
16 16 # Stdlib imports
17 import sys
18 17 import time
19 18
20 19 # Third-party imports
21 20 import nose.tools as nt
22 21
23 22 # Our own imports
24 23 from IPython.lib import backgroundjobs as bg
25 from IPython.testing import decorators as dec
26 24
27 25 #-----------------------------------------------------------------------------
28 26 # Globals and constants
29 27 #-----------------------------------------------------------------------------
30 28 t_short = 0.0001 # very short interval to wait on jobs
31 29
32 30 #-----------------------------------------------------------------------------
33 31 # Local utilities
34 32 #-----------------------------------------------------------------------------
35 33 def sleeper(interval=t_short, *a, **kw):
36 34 args = dict(interval=interval,
37 35 other_args=a,
38 36 kw_args=kw)
39 37 time.sleep(interval)
40 38 return args
41 39
42 40 def crasher(interval=t_short, *a, **kw):
43 41 time.sleep(interval)
44 42 raise Exception("Dead job with interval %s" % interval)
45 43
46 44 #-----------------------------------------------------------------------------
47 45 # Classes and functions
48 46 #-----------------------------------------------------------------------------
49 47
50 48 def test_result():
51 49 """Test job submission and result retrieval"""
52 50 jobs = bg.BackgroundJobManager()
53 51 j = jobs.new(sleeper)
54 52 j.join()
55 53 nt.assert_equal(j.result['interval'], t_short)
56 54
57 55
58 56 def test_flush():
59 57 """Test job control"""
60 58 jobs = bg.BackgroundJobManager()
61 59 j = jobs.new(sleeper)
62 60 j.join()
63 61 nt.assert_equal(len(jobs.completed), 1)
64 62 nt.assert_equal(len(jobs.dead), 0)
65 63 jobs.flush()
66 64 nt.assert_equal(len(jobs.completed), 0)
67 65
68 66
69 67 def test_dead():
70 68 """Test control of dead jobs"""
71 69 jobs = bg.BackgroundJobManager()
72 70 j = jobs.new(crasher)
73 71 j.join()
74 72 nt.assert_equal(len(jobs.completed), 0)
75 73 nt.assert_equal(len(jobs.dead), 1)
76 74 jobs.flush()
77 75 nt.assert_equal(len(jobs.dead), 0)
78 76
79 77
80 78 def test_longer():
81 79 """Test control of longer-running jobs"""
82 80 jobs = bg.BackgroundJobManager()
83 81 # Sleep for long enough for the following two checks to still report the
84 82 # job as running, but not so long that it makes the test suite noticeably
85 83 # slower.
86 84 j = jobs.new(sleeper, 0.1)
87 85 nt.assert_equal(len(jobs.running), 1)
88 86 nt.assert_equal(len(jobs.completed), 0)
89 87 j.join()
90 88 nt.assert_equal(len(jobs.running), 0)
91 89 nt.assert_equal(len(jobs.completed), 1)
@@ -1,53 +1,52 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Test suite for the deepreload module."""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Imports
6 6 #-----------------------------------------------------------------------------
7 7
8 8 import os
9 import sys
10 9
11 10 import nose.tools as nt
12 11
13 12 from IPython.testing import decorators as dec
14 13 from IPython.utils.syspathcontext import prepended_to_syspath
15 14 from IPython.utils.tempdir import TemporaryDirectory
16 15 from IPython.lib.deepreload import reload as dreload
17 16
18 17 #-----------------------------------------------------------------------------
19 18 # Test functions begin
20 19 #-----------------------------------------------------------------------------
21 20
22 21 @dec.skipif_not_numpy
23 22 def test_deepreload_numpy():
24 23 "Test that NumPy can be deep reloaded."
25 24 import numpy
26 25 exclude = [
27 26 # Standard exclusions:
28 27 'sys', 'os.path', '__builtin__', '__main__',
29 28 # Test-related exclusions:
30 29 'unittest', 'UserDict',
31 30 ]
32 31 dreload(numpy, exclude=exclude)
33 32
34 33 def test_deepreload():
35 34 "Test that dreload does deep reloads and skips excluded modules."
36 35 with TemporaryDirectory() as tmpdir:
37 36 with prepended_to_syspath(tmpdir):
38 37 with open(os.path.join(tmpdir, 'A.py'), 'w') as f:
39 38 f.write("class Object(object):\n pass\n")
40 39 with open(os.path.join(tmpdir, 'B.py'), 'w') as f:
41 40 f.write("import A\n")
42 41 import A
43 42 import B
44 43
45 44 # Test that A is not reloaded.
46 45 obj = A.Object()
47 46 dreload(B, exclude=['A'])
48 47 nt.assert_true(isinstance(obj, A.Object))
49 48
50 49 # Test that A is reloaded.
51 50 obj = A.Object()
52 51 dreload(B)
53 52 nt.assert_false(isinstance(obj, A.Object))
@@ -1,158 +1,157 b''
1 1 """Tests for IPython.lib.display.
2 2
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2012, the IPython Development Team.
6 6 #
7 7 # Distributed under the terms of the Modified BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15 from __future__ import print_function
16 16 from tempfile import NamedTemporaryFile, mkdtemp
17 17 from os.path import split
18 from os import sep
19 18
20 19 # Third-party imports
21 20 import nose.tools as nt
22 21
23 22 # Our own imports
24 23 from IPython.lib import display
25 24
26 25 #-----------------------------------------------------------------------------
27 26 # Classes and functions
28 27 #-----------------------------------------------------------------------------
29 28
30 29 #--------------------------
31 30 # FileLink tests
32 31 #--------------------------
33 32
34 33 def test_instantiation_FileLink():
35 34 """FileLink: Test class can be instantiated"""
36 35 fl = display.FileLink('example.txt')
37 36
38 37 def test_warning_on_non_existant_path_FileLink():
39 38 """FileLink: Calling _repr_html_ on non-existant files returns a warning
40 39 """
41 40 fl = display.FileLink('example.txt')
42 41 nt.assert_true(fl._repr_html_().startswith('Path (<tt>example.txt</tt>)'))
43 42
44 43 def test_existing_path_FileLink():
45 44 """FileLink: Calling _repr_html_ functions as expected on existing filepath
46 45 """
47 46 tf = NamedTemporaryFile()
48 47 fl = display.FileLink(tf.name)
49 48 actual = fl._repr_html_()
50 49 expected = "<a href='files/%s' target='_blank'>%s</a><br>" % (tf.name,tf.name)
51 50 nt.assert_equal(actual,expected)
52 51
53 52 def test_existing_path_FileLink_repr():
54 53 """FileLink: Calling repr() functions as expected on existing filepath
55 54 """
56 55 tf = NamedTemporaryFile()
57 56 fl = display.FileLink(tf.name)
58 57 actual = repr(fl)
59 58 expected = tf.name
60 59 nt.assert_equal(actual,expected)
61 60
62 61 def test_error_on_directory_to_FileLink():
63 62 """FileLink: Raises error when passed directory
64 63 """
65 64 td = mkdtemp()
66 65 nt.assert_raises(ValueError,display.FileLink,td)
67 66
68 67 #--------------------------
69 68 # FileLinks tests
70 69 #--------------------------
71 70
72 71 def test_instantiation_FileLinks():
73 72 """FileLinks: Test class can be instantiated
74 73 """
75 74 fls = display.FileLinks('example')
76 75
77 76 def test_warning_on_non_existant_path_FileLinks():
78 77 """FileLinks: Calling _repr_html_ on non-existant files returns a warning
79 78 """
80 79 fls = display.FileLinks('example')
81 80 nt.assert_true(fls._repr_html_().startswith('Path (<tt>example</tt>)'))
82 81
83 82 def test_existing_path_FileLinks():
84 83 """FileLinks: Calling _repr_html_ functions as expected on existing dir
85 84 """
86 85 td = mkdtemp()
87 86 tf1 = NamedTemporaryFile(dir=td)
88 87 tf2 = NamedTemporaryFile(dir=td)
89 88 fl = display.FileLinks(td)
90 89 actual = fl._repr_html_()
91 90 actual = actual.split('\n')
92 91 actual.sort()
93 92 # the links should always have forward slashes, even on windows, so replace
94 93 # backslashes with forward slashes here
95 94 expected = ["%s/<br>" % td,
96 95 "&nbsp;&nbsp;<a href='files/%s' target='_blank'>%s</a><br>" %\
97 96 (tf2.name.replace("\\","/"),split(tf2.name)[1]),
98 97 "&nbsp;&nbsp;<a href='files/%s' target='_blank'>%s</a><br>" %\
99 98 (tf1.name.replace("\\","/"),split(tf1.name)[1])]
100 99 expected.sort()
101 100 # We compare the sorted list of links here as that's more reliable
102 101 nt.assert_equal(actual,expected)
103 102
104 103 def test_existing_path_FileLinks_alt_formatter():
105 104 """FileLinks: Calling _repr_html_ functions as expected w/ an alt formatter
106 105 """
107 106 td = mkdtemp()
108 107 tf1 = NamedTemporaryFile(dir=td)
109 108 tf2 = NamedTemporaryFile(dir=td)
110 109 def fake_formatter(dirname,fnames,included_suffixes):
111 110 return ["hello","world"]
112 111 fl = display.FileLinks(td,notebook_display_formatter=fake_formatter)
113 112 actual = fl._repr_html_()
114 113 actual = actual.split('\n')
115 114 actual.sort()
116 115 expected = ["hello","world"]
117 116 expected.sort()
118 117 # We compare the sorted list of links here as that's more reliable
119 118 nt.assert_equal(actual,expected)
120 119
121 120 def test_existing_path_FileLinks_repr():
122 121 """FileLinks: Calling repr() functions as expected on existing directory """
123 122 td = mkdtemp()
124 123 tf1 = NamedTemporaryFile(dir=td)
125 124 tf2 = NamedTemporaryFile(dir=td)
126 125 fl = display.FileLinks(td)
127 126 actual = repr(fl)
128 127 actual = actual.split('\n')
129 128 actual.sort()
130 129 expected = ['%s/' % td, ' %s' % split(tf1.name)[1],' %s' % split(tf2.name)[1]]
131 130 expected.sort()
132 131 # We compare the sorted list of links here as that's more reliable
133 132 nt.assert_equal(actual,expected)
134 133
135 134 def test_existing_path_FileLinks_repr_alt_formatter():
136 135 """FileLinks: Calling repr() functions as expected w/ alt formatter
137 136 """
138 137 td = mkdtemp()
139 138 tf1 = NamedTemporaryFile(dir=td)
140 139 tf2 = NamedTemporaryFile(dir=td)
141 140 def fake_formatter(dirname,fnames,included_suffixes):
142 141 return ["hello","world"]
143 142 fl = display.FileLinks(td,terminal_display_formatter=fake_formatter)
144 143 actual = repr(fl)
145 144 actual = actual.split('\n')
146 145 actual.sort()
147 146 expected = ["hello","world"]
148 147 expected.sort()
149 148 # We compare the sorted list of links here as that's more reliable
150 149 nt.assert_equal(actual,expected)
151 150
152 151 def test_error_on_file_to_FileLinks():
153 152 """FileLinks: Raises error when passed file
154 153 """
155 154 td = mkdtemp()
156 155 tf1 = NamedTemporaryFile(dir=td)
157 156 nt.assert_raises(ValueError,display.FileLinks,tf1.name)
158 157
@@ -1,13 +1,13 b''
1 1 # encoding: utf-8
2 2
3 3 def test_import_backgroundjobs():
4 4 from IPython.lib import backgroundjobs
5 5
6 6 def test_import_deepreload():
7 7 from IPython.lib import deepreload
8 8
9 9 def test_import_demo():
10 10 from IPython.lib import demo
11 11
12 12 def test_import_irunner():
13 from IPython.lib import demo
13 from IPython.lib import irunner
General Comments 0
You need to be logged in to leave comments. Login now