##// END OF EJS Templates
Removed the top-level iptest.py and INSTALLED logic....
Brian Granger -
Show More
@@ -1,651 +1,654 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 The :class:`~IPython.core.application.Application` object for the command
5 5 line :command:`ipython` program.
6 6
7 7 Authors
8 8 -------
9 9
10 10 * Brian Granger
11 11 * Fernando Perez
12 12 """
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Copyright (C) 2008-2010 The IPython Development Team
16 16 #
17 17 # Distributed under the terms of the BSD License. The full license is in
18 18 # the file COPYING, distributed as part of this software.
19 19 #-----------------------------------------------------------------------------
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Imports
23 23 #-----------------------------------------------------------------------------
24 24
25 25 from __future__ import absolute_import
26 26
27 27 import logging
28 28 import os
29 29 import sys
30 30
31 31 from IPython.core import release
32 32 from IPython.core.crashhandler import CrashHandler
33 33 from IPython.core.application import Application, BaseAppConfigLoader
34 34 from IPython.core.iplib import InteractiveShell
35 35 from IPython.config.loader import (
36 36 Config,
37 37 PyFileConfigLoader
38 38 )
39 39 from IPython.lib import inputhook
40 40 from IPython.utils.path import filefind, get_ipython_dir
41 41 from . import usage
42 42
43 43 #-----------------------------------------------------------------------------
44 44 # Globals, utilities and helpers
45 45 #-----------------------------------------------------------------------------
46 46
47 47 #: The default config file name for this application.
48 48 default_config_file_name = u'ipython_config.py'
49 49
50 50
51 51 class IPAppConfigLoader(BaseAppConfigLoader):
52 52
53 53 def _add_arguments(self):
54 54 super(IPAppConfigLoader, self)._add_arguments()
55 55 paa = self.parser.add_argument
56 56 paa('-p',
57 57 '--profile', dest='Global.profile', type=unicode,
58 58 help=
59 59 """The string name of the ipython profile to be used. Assume that your
60 60 config file is ipython_config-<name>.py (looks in current dir first,
61 61 then in IPYTHON_DIR). This is a quick way to keep and load multiple
62 62 config files for different tasks, especially if include your basic one
63 63 in your more specialized ones. You can keep a basic
64 64 IPYTHON_DIR/ipython_config.py file and then have other 'profiles' which
65 65 include this one and load extra things for particular tasks.""",
66 66 metavar='Global.profile')
67 67 paa('--config-file',
68 68 dest='Global.config_file', type=unicode,
69 69 help=
70 70 """Set the config file name to override default. Normally IPython
71 71 loads ipython_config.py (from current directory) or
72 72 IPYTHON_DIR/ipython_config.py. If the loading of your config file
73 73 fails, IPython starts with a bare bones configuration (no modules
74 74 loaded at all).""",
75 75 metavar='Global.config_file')
76 76 paa('--autocall',
77 77 dest='InteractiveShell.autocall', type=int,
78 78 help=
79 79 """Make IPython automatically call any callable object even if you
80 80 didn't type explicit parentheses. For example, 'str 43' becomes
81 81 'str(43)' automatically. The value can be '0' to disable the feature,
82 82 '1' for 'smart' autocall, where it is not applied if there are no more
83 83 arguments on the line, and '2' for 'full' autocall, where all callable
84 84 objects are automatically called (even if no arguments are present).
85 85 The default is '1'.""",
86 86 metavar='InteractiveShell.autocall')
87 87 paa('--autoindent',
88 88 action='store_true', dest='InteractiveShell.autoindent',
89 89 help='Turn on autoindenting.')
90 90 paa('--no-autoindent',
91 91 action='store_false', dest='InteractiveShell.autoindent',
92 92 help='Turn off autoindenting.')
93 93 paa('--automagic',
94 94 action='store_true', dest='InteractiveShell.automagic',
95 95 help=
96 96 """Turn on the auto calling of magic commands. Type %%magic at the
97 97 IPython prompt for more information.""")
98 98 paa('--no-automagic',
99 99 action='store_false', dest='InteractiveShell.automagic',
100 100 help='Turn off the auto calling of magic commands.')
101 101 paa('--autoedit-syntax',
102 102 action='store_true', dest='InteractiveShell.autoedit_syntax',
103 103 help='Turn on auto editing of files with syntax errors.')
104 104 paa('--no-autoedit-syntax',
105 105 action='store_false', dest='InteractiveShell.autoedit_syntax',
106 106 help='Turn off auto editing of files with syntax errors.')
107 107 paa('--banner',
108 108 action='store_true', dest='Global.display_banner',
109 109 help='Display a banner upon starting IPython.')
110 110 paa('--no-banner',
111 111 action='store_false', dest='Global.display_banner',
112 112 help="Don't display a banner upon starting IPython.")
113 113 paa('--cache-size',
114 114 type=int, dest='InteractiveShell.cache_size',
115 115 help=
116 116 """Set the size of the output cache. The default is 1000, you can
117 117 change it permanently in your config file. Setting it to 0 completely
118 118 disables the caching system, and the minimum value accepted is 20 (if
119 119 you provide a value less than 20, it is reset to 0 and a warning is
120 120 issued). This limit is defined because otherwise you'll spend more
121 121 time re-flushing a too small cache than working""",
122 122 metavar='InteractiveShell.cache_size')
123 123 paa('--classic',
124 124 action='store_true', dest='Global.classic',
125 125 help="Gives IPython a similar feel to the classic Python prompt.")
126 126 paa('--colors',
127 127 type=str, dest='InteractiveShell.colors',
128 128 help="Set the color scheme (NoColor, Linux, and LightBG).",
129 129 metavar='InteractiveShell.colors')
130 130 paa('--color-info',
131 131 action='store_true', dest='InteractiveShell.color_info',
132 132 help=
133 133 """IPython can display information about objects via a set of func-
134 134 tions, and optionally can use colors for this, syntax highlighting
135 135 source code and various other elements. However, because this
136 136 information is passed through a pager (like 'less') and many pagers get
137 137 confused with color codes, this option is off by default. You can test
138 138 it and turn it on permanently in your ipython_config.py file if it
139 139 works for you. Test it and turn it on permanently if it works with
140 140 your system. The magic function %%color_info allows you to toggle this
141 141 inter- actively for testing.""")
142 142 paa('--no-color-info',
143 143 action='store_false', dest='InteractiveShell.color_info',
144 144 help="Disable using colors for info related things.")
145 145 paa('--confirm-exit',
146 146 action='store_true', dest='InteractiveShell.confirm_exit',
147 147 help=
148 148 """Set to confirm when you try to exit IPython with an EOF (Control-D
149 149 in Unix, Control-Z/Enter in Windows). By typing 'exit', 'quit' or
150 150 '%%Exit', you can force a direct exit without any confirmation.""")
151 151 paa('--no-confirm-exit',
152 152 action='store_false', dest='InteractiveShell.confirm_exit',
153 153 help="Don't prompt the user when exiting.")
154 154 paa('--deep-reload',
155 155 action='store_true', dest='InteractiveShell.deep_reload',
156 156 help=
157 157 """Enable deep (recursive) reloading by default. IPython can use the
158 158 deep_reload module which reloads changes in modules recursively (it
159 159 replaces the reload() function, so you don't need to change anything to
160 160 use it). deep_reload() forces a full reload of modules whose code may
161 161 have changed, which the default reload() function does not. When
162 162 deep_reload is off, IPython will use the normal reload(), but
163 163 deep_reload will still be available as dreload(). This fea- ture is off
164 164 by default [which means that you have both normal reload() and
165 165 dreload()].""")
166 166 paa('--no-deep-reload',
167 167 action='store_false', dest='InteractiveShell.deep_reload',
168 168 help="Disable deep (recursive) reloading by default.")
169 169 paa('--editor',
170 170 type=str, dest='InteractiveShell.editor',
171 171 help="Set the editor used by IPython (default to $EDITOR/vi/notepad).",
172 172 metavar='InteractiveShell.editor')
173 173 paa('--log','-l',
174 174 action='store_true', dest='InteractiveShell.logstart',
175 175 help="Start logging to the default log file (./ipython_log.py).")
176 176 paa('--logfile','-lf',
177 177 type=unicode, dest='InteractiveShell.logfile',
178 178 help="Start logging to logfile with this name.",
179 179 metavar='InteractiveShell.logfile')
180 180 paa('--log-append','-la',
181 181 type=unicode, dest='InteractiveShell.logappend',
182 182 help="Start logging to the given file in append mode.",
183 183 metavar='InteractiveShell.logfile')
184 184 paa('--pdb',
185 185 action='store_true', dest='InteractiveShell.pdb',
186 186 help="Enable auto calling the pdb debugger after every exception.")
187 187 paa('--no-pdb',
188 188 action='store_false', dest='InteractiveShell.pdb',
189 189 help="Disable auto calling the pdb debugger after every exception.")
190 190 paa('--pprint',
191 191 action='store_true', dest='InteractiveShell.pprint',
192 192 help="Enable auto pretty printing of results.")
193 193 paa('--no-pprint',
194 194 action='store_false', dest='InteractiveShell.pprint',
195 195 help="Disable auto auto pretty printing of results.")
196 196 paa('--prompt-in1','-pi1',
197 197 type=str, dest='InteractiveShell.prompt_in1',
198 198 help=
199 199 """Set the main input prompt ('In [\#]: '). Note that if you are using
200 200 numbered prompts, the number is represented with a '\#' in the string.
201 201 Don't forget to quote strings with spaces embedded in them. Most
202 202 bash-like escapes can be used to customize IPython's prompts, as well
203 203 as a few additional ones which are IPython-spe- cific. All valid
204 204 prompt escapes are described in detail in the Customization section of
205 205 the IPython manual.""",
206 206 metavar='InteractiveShell.prompt_in1')
207 207 paa('--prompt-in2','-pi2',
208 208 type=str, dest='InteractiveShell.prompt_in2',
209 209 help=
210 210 """Set the secondary input prompt (' .\D.: '). Similar to the previous
211 211 option, but used for the continuation prompts. The special sequence
212 212 '\D' is similar to '\#', but with all digits replaced by dots (so you
213 213 can have your continuation prompt aligned with your input prompt).
214 214 Default: ' .\D.: ' (note three spaces at the start for alignment with
215 215 'In [\#]')""",
216 216 metavar='InteractiveShell.prompt_in2')
217 217 paa('--prompt-out','-po',
218 218 type=str, dest='InteractiveShell.prompt_out',
219 219 help="Set the output prompt ('Out[\#]:')",
220 220 metavar='InteractiveShell.prompt_out')
221 221 paa('--quick',
222 222 action='store_true', dest='Global.quick',
223 223 help="Enable quick startup with no config files.")
224 224 paa('--readline',
225 225 action='store_true', dest='InteractiveShell.readline_use',
226 226 help="Enable readline for command line usage.")
227 227 paa('--no-readline',
228 228 action='store_false', dest='InteractiveShell.readline_use',
229 229 help="Disable readline for command line usage.")
230 230 paa('--screen-length','-sl',
231 231 type=int, dest='InteractiveShell.screen_length',
232 232 help=
233 233 """Number of lines of your screen, used to control printing of very
234 234 long strings. Strings longer than this number of lines will be sent
235 235 through a pager instead of directly printed. The default value for
236 236 this is 0, which means IPython will auto-detect your screen size every
237 237 time it needs to print certain potentially long strings (this doesn't
238 238 change the behavior of the 'print' keyword, it's only triggered
239 239 internally). If for some reason this isn't working well (it needs
240 240 curses support), specify it yourself. Otherwise don't change the
241 241 default.""",
242 242 metavar='InteractiveShell.screen_length')
243 243 paa('--separate-in','-si',
244 244 type=str, dest='InteractiveShell.separate_in',
245 245 help="Separator before input prompts. Default '\\n'.",
246 246 metavar='InteractiveShell.separate_in')
247 247 paa('--separate-out','-so',
248 248 type=str, dest='InteractiveShell.separate_out',
249 249 help="Separator before output prompts. Default 0 (nothing).",
250 250 metavar='InteractiveShell.separate_out')
251 251 paa('--separate-out2','-so2',
252 252 type=str, dest='InteractiveShell.separate_out2',
253 253 help="Separator after output prompts. Default 0 (nonight).",
254 254 metavar='InteractiveShell.separate_out2')
255 255 paa('-no-sep',
256 256 action='store_true', dest='Global.nosep',
257 257 help="Eliminate all spacing between prompts.")
258 258 paa('--term-title',
259 259 action='store_true', dest='InteractiveShell.term_title',
260 260 help="Enable auto setting the terminal title.")
261 261 paa('--no-term-title',
262 262 action='store_false', dest='InteractiveShell.term_title',
263 263 help="Disable auto setting the terminal title.")
264 264 paa('--xmode',
265 265 type=str, dest='InteractiveShell.xmode',
266 266 help=
267 267 """Exception reporting mode ('Plain','Context','Verbose'). Plain:
268 268 similar to python's normal traceback printing. Context: prints 5 lines
269 269 of context source code around each line in the traceback. Verbose:
270 270 similar to Context, but additionally prints the variables currently
271 271 visible where the exception happened (shortening their strings if too
272 272 long). This can potentially be very slow, if you happen to have a huge
273 273 data structure whose string representation is complex to compute.
274 274 Your computer may appear to freeze for a while with cpu usage at 100%%.
275 275 If this occurs, you can cancel the traceback with Ctrl-C (maybe hitting
276 276 it more than once).
277 277 """,
278 278 metavar='InteractiveShell.xmode')
279 279 paa('--ext',
280 280 type=str, dest='Global.extra_extension',
281 281 help="The dotted module name of an IPython extension to load.",
282 282 metavar='Global.extra_extension')
283 283 paa('-c',
284 284 type=str, dest='Global.code_to_run',
285 285 help="Execute the given command string.",
286 286 metavar='Global.code_to_run')
287 287 paa('-i',
288 288 action='store_true', dest='Global.force_interact',
289 289 help=
290 290 "If running code from the command line, become interactive afterwards.")
291 291
292 292 # Options to start with GUI control enabled from the beginning
293 293 paa('--gui',
294 294 type=str, dest='Global.gui',
295 295 help="Enable GUI event loop integration ('qt', 'wx', 'gtk').",
296 296 metavar='gui-mode')
297 297 paa('--pylab','-pylab',
298 298 type=str, dest='Global.pylab',
299 299 nargs='?', const='auto', metavar='gui-mode',
300 300 help="Pre-load matplotlib and numpy for interactive use. "+
301 301 "If no value is given, the gui backend is matplotlib's, else use "+
302 302 "one of: ['tk', 'qt', 'wx', 'gtk'].")
303 303
304 304 # Legacy GUI options. Leave them in for backwards compatibility, but the
305 305 # 'thread' names are really a misnomer now.
306 306 paa('--wthread', '-wthread',
307 307 action='store_true', dest='Global.wthread',
308 308 help=
309 309 """Enable wxPython event loop integration. (DEPRECATED, use --gui wx)""")
310 310 paa('--q4thread', '--qthread', '-q4thread', '-qthread',
311 311 action='store_true', dest='Global.q4thread',
312 312 help=
313 313 """Enable Qt4 event loop integration. Qt3 is no longer supported.
314 314 (DEPRECATED, use --gui qt)""")
315 315 paa('--gthread', '-gthread',
316 316 action='store_true', dest='Global.gthread',
317 317 help=
318 318 """Enable GTK event loop integration. (DEPRECATED, use --gui gtk)""")
319 319
320 320
321 321 #-----------------------------------------------------------------------------
322 322 # Crash handler for this application
323 323 #-----------------------------------------------------------------------------
324 324
325 325
326 326 _message_template = """\
327 327 Oops, $self.app_name crashed. We do our best to make it stable, but...
328 328
329 329 A crash report was automatically generated with the following information:
330 330 - A verbatim copy of the crash traceback.
331 331 - A copy of your input history during this session.
332 332 - Data on your current $self.app_name configuration.
333 333
334 334 It was left in the file named:
335 335 \t'$self.crash_report_fname'
336 336 If you can email this file to the developers, the information in it will help
337 337 them in understanding and correcting the problem.
338 338
339 339 You can mail it to: $self.contact_name at $self.contact_email
340 340 with the subject '$self.app_name Crash Report'.
341 341
342 342 If you want to do it now, the following command will work (under Unix):
343 343 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
344 344
345 345 To ensure accurate tracking of this issue, please file a report about it at:
346 346 $self.bug_tracker
347 347 """
348 348
349 349 class IPAppCrashHandler(CrashHandler):
350 350 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
351 351
352 352 message_template = _message_template
353 353
354 354 def __init__(self, app):
355 355 contact_name = release.authors['Fernando'][0]
356 356 contact_email = release.authors['Fernando'][1]
357 357 bug_tracker = 'https://bugs.launchpad.net/ipython/+filebug'
358 358 super(IPAppCrashHandler,self).__init__(
359 359 app, contact_name, contact_email, bug_tracker
360 360 )
361 361
362 362 def make_report(self,traceback):
363 363 """Return a string containing a crash report."""
364 364
365 365 sec_sep = self.section_sep
366 366 # Start with parent report
367 367 report = [super(IPAppCrashHandler, self).make_report(traceback)]
368 368 # Add interactive-specific info we may have
369 369 rpt_add = report.append
370 370 try:
371 371 rpt_add(sec_sep+"History of session input:")
372 372 for line in self.app.shell.user_ns['_ih']:
373 373 rpt_add(line)
374 374 rpt_add('\n*** Last line of input (may not be in above history):\n')
375 375 rpt_add(self.app.shell._last_input_line+'\n')
376 376 except:
377 377 pass
378 378
379 379 return ''.join(report)
380 380
381 381
382 382 #-----------------------------------------------------------------------------
383 383 # Main classes and functions
384 384 #-----------------------------------------------------------------------------
385 385
386 386 class IPythonApp(Application):
387 387 name = u'ipython'
388 388 #: argparse formats better the 'usage' than the 'description' field
389 389 description = None
390 390 usage = usage.cl_usage
391 391 command_line_loader = IPAppConfigLoader
392 392 config_file_name = default_config_file_name
393 393 crash_handler_class = IPAppCrashHandler
394 394
395 395 def create_default_config(self):
396 396 super(IPythonApp, self).create_default_config()
397 397 # Eliminate multiple lookups
398 398 Global = self.default_config.Global
399 399
400 400 # Set all default values
401 401 Global.display_banner = True
402 402
403 403 # If the -c flag is given or a file is given to run at the cmd line
404 404 # like "ipython foo.py", normally we exit without starting the main
405 405 # loop. The force_interact config variable allows a user to override
406 406 # this and interact. It is also set by the -i cmd line flag, just
407 407 # like Python.
408 408 Global.force_interact = False
409 409
410 410 # By default always interact by starting the IPython mainloop.
411 411 Global.interact = True
412 412
413 413 # No GUI integration by default
414 414 Global.gui = False
415 415 # Pylab off by default
416 416 Global.pylab = False
417 417
418 418 # Deprecated versions of gui support that used threading, we support
419 419 # them just for bacwards compatibility as an alternate spelling for
420 420 # '--gui X'
421 421 Global.qthread = False
422 422 Global.q4thread = False
423 423 Global.wthread = False
424 424 Global.gthread = False
425 425
426 426 def load_file_config(self):
427 427 if hasattr(self.command_line_config.Global, 'quick'):
428 428 if self.command_line_config.Global.quick:
429 429 self.file_config = Config()
430 430 return
431 431 super(IPythonApp, self).load_file_config()
432 432
433 433 def post_load_file_config(self):
434 434 if hasattr(self.command_line_config.Global, 'extra_extension'):
435 435 if not hasattr(self.file_config.Global, 'extensions'):
436 436 self.file_config.Global.extensions = []
437 437 self.file_config.Global.extensions.append(
438 438 self.command_line_config.Global.extra_extension)
439 439 del self.command_line_config.Global.extra_extension
440 440
441 441 def pre_construct(self):
442 442 config = self.master_config
443 443
444 444 if hasattr(config.Global, 'classic'):
445 445 if config.Global.classic:
446 446 config.InteractiveShell.cache_size = 0
447 447 config.InteractiveShell.pprint = 0
448 448 config.InteractiveShell.prompt_in1 = '>>> '
449 449 config.InteractiveShell.prompt_in2 = '... '
450 450 config.InteractiveShell.prompt_out = ''
451 451 config.InteractiveShell.separate_in = \
452 452 config.InteractiveShell.separate_out = \
453 453 config.InteractiveShell.separate_out2 = ''
454 454 config.InteractiveShell.colors = 'NoColor'
455 455 config.InteractiveShell.xmode = 'Plain'
456 456
457 457 if hasattr(config.Global, 'nosep'):
458 458 if config.Global.nosep:
459 459 config.InteractiveShell.separate_in = \
460 460 config.InteractiveShell.separate_out = \
461 461 config.InteractiveShell.separate_out2 = ''
462 462
463 463 # if there is code of files to run from the cmd line, don't interact
464 464 # unless the -i flag (Global.force_interact) is true.
465 465 code_to_run = config.Global.get('code_to_run','')
466 466 file_to_run = False
467 467 if self.extra_args and self.extra_args[0]:
468 468 file_to_run = True
469 469 if file_to_run or code_to_run:
470 470 if not config.Global.force_interact:
471 471 config.Global.interact = False
472 472
473 473 def construct(self):
474 474 # I am a little hesitant to put these into InteractiveShell itself.
475 475 # But that might be the place for them
476 476 sys.path.insert(0, '')
477 477
478 478 # Create an InteractiveShell instance
479 479 self.shell = InteractiveShell(None, self.master_config)
480 480
481 481 def post_construct(self):
482 482 """Do actions after construct, but before starting the app."""
483 483 config = self.master_config
484 484
485 485 # shell.display_banner should always be False for the terminal
486 486 # based app, because we call shell.show_banner() by hand below
487 487 # so the banner shows *before* all extension loading stuff.
488 488 self.shell.display_banner = False
489 489
490 490 if config.Global.display_banner and \
491 491 config.Global.interact:
492 492 self.shell.show_banner()
493 493
494 494 # Make sure there is a space below the banner.
495 495 if self.log_level <= logging.INFO: print
496 496
497 497 # Now a variety of things that happen after the banner is printed.
498 498 self._enable_gui_pylab()
499 499 self._load_extensions()
500 500 self._run_exec_lines()
501 501 self._run_exec_files()
502 502 self._run_cmd_line_code()
503 503
504 504 def _enable_gui_pylab(self):
505 505 """Enable GUI event loop integration, taking pylab into account."""
506 506 Global = self.master_config.Global
507 507
508 508 # Select which gui to use
509 509 if Global.gui:
510 510 gui = Global.gui
511 511 # The following are deprecated, but there's likely to be a lot of use
512 512 # of this form out there, so we might as well support it for now. But
513 513 # the --gui option above takes precedence.
514 514 elif Global.wthread:
515 515 gui = inputhook.GUI_WX
516 516 elif Global.qthread:
517 517 gui = inputhook.GUI_QT
518 518 elif Global.gthread:
519 519 gui = inputhook.GUI_GTK
520 520 else:
521 521 gui = None
522 522
523 523 # Using --pylab will also require gui activation, though which toolkit
524 524 # to use may be chosen automatically based on mpl configuration.
525 525 if Global.pylab:
526 526 activate = self.shell.enable_pylab
527 527 if Global.pylab == 'auto':
528 528 gui = None
529 529 else:
530 530 gui = Global.pylab
531 531 else:
532 532 # Enable only GUI integration, no pylab
533 533 activate = inputhook.enable_gui
534 534
535 535 if gui or Global.pylab:
536 536 try:
537 537 self.log.info("Enabling GUI event loop integration, "
538 538 "toolkit=%s, pylab=%s" % (gui, Global.pylab) )
539 539 activate(gui)
540 540 except:
541 541 self.log.warn("Error in enabling GUI event loop integration:")
542 542 self.shell.showtraceback()
543 543
544 544 def _load_extensions(self):
545 545 """Load all IPython extensions in Global.extensions.
546 546
547 547 This uses the :meth:`InteractiveShell.load_extensions` to load all
548 548 the extensions listed in ``self.master_config.Global.extensions``.
549 549 """
550 550 try:
551 551 if hasattr(self.master_config.Global, 'extensions'):
552 552 self.log.debug("Loading IPython extensions...")
553 553 extensions = self.master_config.Global.extensions
554 554 for ext in extensions:
555 555 try:
556 556 self.log.info("Loading IPython extension: %s" % ext)
557 557 self.shell.load_extension(ext)
558 558 except:
559 559 self.log.warn("Error in loading extension: %s" % ext)
560 560 self.shell.showtraceback()
561 561 except:
562 562 self.log.warn("Unknown error in loading extensions:")
563 563 self.shell.showtraceback()
564 564
565 565 def _run_exec_lines(self):
566 566 """Run lines of code in Global.exec_lines in the user's namespace."""
567 567 try:
568 568 if hasattr(self.master_config.Global, 'exec_lines'):
569 569 self.log.debug("Running code from Global.exec_lines...")
570 570 exec_lines = self.master_config.Global.exec_lines
571 571 for line in exec_lines:
572 572 try:
573 573 self.log.info("Running code in user namespace: %s" % line)
574 574 self.shell.runlines(line)
575 575 except:
576 576 self.log.warn("Error in executing line in user namespace: %s" % line)
577 577 self.shell.showtraceback()
578 578 except:
579 579 self.log.warn("Unknown error in handling Global.exec_lines:")
580 580 self.shell.showtraceback()
581 581
582 582 def _exec_file(self, fname):
583 583 full_filename = filefind(fname, [u'.', self.ipython_dir])
584 584 if os.path.isfile(full_filename):
585 585 if full_filename.endswith(u'.py'):
586 586 self.log.info("Running file in user namespace: %s" % full_filename)
587 587 self.shell.safe_execfile(full_filename, self.shell.user_ns)
588 588 elif full_filename.endswith('.ipy'):
589 589 self.log.info("Running file in user namespace: %s" % full_filename)
590 590 self.shell.safe_execfile_ipy(full_filename)
591 591 else:
592 592 self.log.warn("File does not have a .py or .ipy extension: <%s>" % full_filename)
593 593
594 594 def _run_exec_files(self):
595 595 try:
596 596 if hasattr(self.master_config.Global, 'exec_files'):
597 597 self.log.debug("Running files in Global.exec_files...")
598 598 exec_files = self.master_config.Global.exec_files
599 599 for fname in exec_files:
600 600 self._exec_file(fname)
601 601 except:
602 602 self.log.warn("Unknown error in handling Global.exec_files:")
603 603 self.shell.showtraceback()
604 604
605 605 def _run_cmd_line_code(self):
606 606 if hasattr(self.master_config.Global, 'code_to_run'):
607 607 line = self.master_config.Global.code_to_run
608 608 try:
609 609 self.log.info("Running code given at command line (-c): %s" % line)
610 610 self.shell.runlines(line)
611 611 except:
612 612 self.log.warn("Error in executing line in user namespace: %s" % line)
613 613 self.shell.showtraceback()
614 614 return
615 615 # Like Python itself, ignore the second if the first of these is present
616 616 try:
617 617 fname = self.extra_args[0]
618 618 except:
619 619 pass
620 620 else:
621 621 try:
622 622 self._exec_file(fname)
623 623 except:
624 624 self.log.warn("Error in executing file in user namespace: %s" % fname)
625 625 self.shell.showtraceback()
626 626
627 627 def start_app(self):
628 628 if self.master_config.Global.interact:
629 629 self.log.debug("Starting IPython's mainloop...")
630 630 self.shell.mainloop()
631 631 else:
632 632 self.log.debug("IPython not interactive, start_app is no-op...")
633 633
634 634
635 635 def load_default_config(ipython_dir=None):
636 636 """Load the default config file from the default ipython_dir.
637 637
638 638 This is useful for embedded shells.
639 639 """
640 640 if ipython_dir is None:
641 641 ipython_dir = get_ipython_dir()
642 642 cl = PyFileConfigLoader(default_config_file_name, ipython_dir)
643 643 config = cl.load_config()
644 644 return config
645 645
646 646
647 647 def launch_new_instance():
648 648 """Create and run a full blown IPython instance"""
649 649 app = IPythonApp()
650 650 app.start()
651 651
652
653 if __name__ == '__main__':
654 launch_new_instance()
@@ -1,207 +1,207 b''
1 1 # encoding: utf-8
2 2
3 3 """Classes and functions for kernel related errors and exceptions."""
4 4
5 5 __docformat__ = "restructuredtext en"
6 6
7 7 # Tell nose to skip this module
8 8 __test__ = {}
9 9
10 10 #-------------------------------------------------------------------------------
11 11 # Copyright (C) 2008 The IPython Development Team
12 12 #
13 13 # Distributed under the terms of the BSD License. The full license is in
14 14 # the file COPYING, distributed as part of this software.
15 15 #-------------------------------------------------------------------------------
16 16
17 17 #-------------------------------------------------------------------------------
18 18 # Imports
19 19 #-------------------------------------------------------------------------------
20
20 21 from IPython.kernel.core import error
21 22
22 23 #-------------------------------------------------------------------------------
23 24 # Error classes
24 25 #-------------------------------------------------------------------------------
25 26
26 27 class KernelError(error.IPythonError):
27 28 pass
28 29
29 30 class NotDefined(KernelError):
30 31 def __init__(self, name):
31 32 self.name = name
32 33 self.args = (name,)
33 34
34 35 def __repr__(self):
35 36 return '<NotDefined: %s>' % self.name
36 37
37 38 __str__ = __repr__
38 39
39 40 class QueueCleared(KernelError):
40 41 pass
41 42
42 43 class IdInUse(KernelError):
43 44 pass
44 45
45 46 class ProtocolError(KernelError):
46 47 pass
47 48
48 49 class ConnectionError(KernelError):
49 50 pass
50 51
51 52 class InvalidEngineID(KernelError):
52 53 pass
53 54
54 55 class NoEnginesRegistered(KernelError):
55 56 pass
56 57
57 58 class InvalidClientID(KernelError):
58 59 pass
59 60
60 61 class InvalidDeferredID(KernelError):
61 62 pass
62 63
63 64 class SerializationError(KernelError):
64 65 pass
65 66
66 67 class MessageSizeError(KernelError):
67 68 pass
68 69
69 70 class PBMessageSizeError(MessageSizeError):
70 71 pass
71 72
72 73 class ResultNotCompleted(KernelError):
73 74 pass
74 75
75 76 class ResultAlreadyRetrieved(KernelError):
76 77 pass
77 78
78 79 class ClientError(KernelError):
79 80 pass
80 81
81 82 class TaskAborted(KernelError):
82 83 pass
83 84
84 85 class TaskTimeout(KernelError):
85 86 pass
86 87
87 88 class NotAPendingResult(KernelError):
88 89 pass
89 90
90 91 class UnpickleableException(KernelError):
91 92 pass
92 93
93 94 class AbortedPendingDeferredError(KernelError):
94 95 pass
95 96
96 97 class InvalidProperty(KernelError):
97 98 pass
98 99
99 100 class MissingBlockArgument(KernelError):
100 101 pass
101 102
102 103 class StopLocalExecution(KernelError):
103 104 pass
104 105
105 106 class SecurityError(KernelError):
106 107 pass
107 108
108 109 class FileTimeoutError(KernelError):
109 110 pass
110 111
111 112 class TaskRejectError(KernelError):
112 113 """Exception to raise when a task should be rejected by an engine.
113 114
114 115 This exception can be used to allow a task running on an engine to test
115 116 if the engine (or the user's namespace on the engine) has the needed
116 117 task dependencies. If not, the task should raise this exception. For
117 118 the task to be retried on another engine, the task should be created
118 119 with the `retries` argument > 1.
119 120
120 121 The advantage of this approach over our older properties system is that
121 122 tasks have full access to the user's namespace on the engines and the
122 123 properties don't have to be managed or tested by the controller.
123 124 """
124 125
125 126 class CompositeError(KernelError):
126 127 def __init__(self, message, elist):
127 128 Exception.__init__(self, *(message, elist))
128 129 # Don't use pack_exception because it will conflict with the .message
129 130 # attribute that is being deprecated in 2.6 and beyond.
130 131 self.msg = message
131 132 self.elist = elist
132 133
133 134 def _get_engine_str(self, ev):
134 135 try:
135 136 ei = ev._ipython_engine_info
136 137 except AttributeError:
137 138 return '[Engine Exception]'
138 139 else:
139 140 return '[%i:%s]: ' % (ei['engineid'], ei['method'])
140 141
141 142 def _get_traceback(self, ev):
142 143 try:
143 144 tb = ev._ipython_traceback_text
144 145 except AttributeError:
145 146 return 'No traceback available'
146 147 else:
147 148 return tb
148 149
149 150 def __str__(self):
150 151 s = str(self.msg)
151 152 for et, ev, etb in self.elist:
152 153 engine_str = self._get_engine_str(ev)
153 154 s = s + '\n' + engine_str + str(et.__name__) + ': ' + str(ev)
154 155 return s
155 156
156 157 def print_tracebacks(self, excid=None):
157 158 if excid is None:
158 159 for (et,ev,etb) in self.elist:
159 160 print self._get_engine_str(ev)
160 161 print self._get_traceback(ev)
161 162 print
162 163 else:
163 164 try:
164 165 et,ev,etb = self.elist[excid]
165 166 except:
166 167 raise IndexError("an exception with index %i does not exist"%excid)
167 168 else:
168 169 print self._get_engine_str(ev)
169 170 print self._get_traceback(ev)
170 171
171 172 def raise_exception(self, excid=0):
172 173 try:
173 174 et,ev,etb = self.elist[excid]
174 175 except:
175 176 raise IndexError("an exception with index %i does not exist"%excid)
176 177 else:
177 178 raise et, ev, etb
178 179
179 180 def collect_exceptions(rlist, method):
180 181 from twisted.python import failure
181 182
182 183 elist = []
183 184 for r in rlist:
184 185 if isinstance(r, failure.Failure):
185 186 r.cleanFailure()
186 187 et, ev, etb = r.type, r.value, r.tb
187 188 # Sometimes we could have CompositeError in our list. Just take
188 189 # the errors out of them and put them in our new list. This
189 190 # has the effect of flattening lists of CompositeErrors into one
190 191 # CompositeError
191 192 if et==CompositeError:
192 193 for e in ev.elist:
193 194 elist.append(e)
194 195 else:
195 196 elist.append((et, ev, etb))
196 197 if len(elist)==0:
197 198 return rlist
198 199 else:
199 200 msg = "one or more exceptions from call to method: %s" % (method)
200 201 # This silliness is needed so the debugger has access to the exception
201 202 # instance (e in this case)
202 203 try:
203 204 raise CompositeError(msg, elist)
204 205 except CompositeError, e:
205 206 raise e
206 207
207
@@ -1,488 +1,471 b''
1 1 # -*- coding: utf-8 -*-
2 2 """IPython Test Suite Runner.
3 3
4 4 This module provides a main entry point to a user script to test IPython
5 5 itself from the command line. There are two ways of running this script:
6 6
7 7 1. With the syntax `iptest all`. This runs our entire test suite by
8 8 calling this script (with different arguments) or trial recursively. This
9 9 causes modules and package to be tested in different processes, using nose
10 10 or trial where appropriate.
11 11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
12 12 the script simply calls nose, but with special command line flags and
13 13 plugins loaded.
14 14
15 15 For now, this script requires that both nose and twisted are installed. This
16 16 will change in the future.
17 17 """
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Copyright (C) 2009 The IPython Development Team
21 21 #
22 22 # Distributed under the terms of the BSD License. The full license is in
23 23 # the file COPYING, distributed as part of this software.
24 24 #-----------------------------------------------------------------------------
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Imports
28 28 #-----------------------------------------------------------------------------
29 29
30 30 # Stdlib
31 31 import os
32 32 import os.path as path
33 33 import signal
34 34 import sys
35 35 import subprocess
36 36 import tempfile
37 37 import time
38 38 import warnings
39 39
40 40
41 41 # Ugly, but necessary hack to ensure the test suite finds our version of
42 42 # IPython and not a possibly different one that may exist system-wide.
43 43 # Note that this must be done here, so the imports that come next work
44 44 # correctly even if IPython isn't installed yet.
45 45 p = os.path
46 46 ippath = p.abspath(p.join(p.dirname(__file__),'..','..'))
47 47 sys.path.insert(0, ippath)
48 48
49 49 # Note: monkeypatch!
50 50 # We need to monkeypatch a small problem in nose itself first, before importing
51 51 # it for actual use. This should get into nose upstream, but its release cycle
52 52 # is slow and we need it for our parametric tests to work correctly.
53 53 from IPython.testing import nosepatch
54 54 # Now, proceed to import nose itself
55 55 import nose.plugins.builtin
56 56 from nose.core import TestProgram
57 57
58 58 # Our own imports
59 59 from IPython.utils.path import get_ipython_module_path
60 60 from IPython.utils.process import find_cmd, pycmd2argv
61 61 from IPython.utils.sysinfo import sys_info
62 62
63 63 from IPython.testing import globalipapp
64 64 from IPython.testing.plugin.ipdoctest import IPythonDoctest
65 65
66 66 pjoin = path.join
67 67
68 68
69 69 #-----------------------------------------------------------------------------
70 70 # Globals
71 71 #-----------------------------------------------------------------------------
72 72
73 # By default, we assume IPython has been installed. But if the test suite is
74 # being run from a source tree that has NOT been installed yet, this flag can
75 # be set to False by the entry point scripts, to let us know that we must call
76 # the source tree versions of the scripts which manipulate sys.path instead of
77 # assuming that things exist system-wide.
78 INSTALLED = True
79 73
80 74 #-----------------------------------------------------------------------------
81 75 # Warnings control
82 76 #-----------------------------------------------------------------------------
83 77 # Twisted generates annoying warnings with Python 2.6, as will do other code
84 78 # that imports 'sets' as of today
85 79 warnings.filterwarnings('ignore', 'the sets module is deprecated',
86 80 DeprecationWarning )
87 81
88 82 # This one also comes from Twisted
89 83 warnings.filterwarnings('ignore', 'the sha module is deprecated',
90 84 DeprecationWarning)
91 85
92 86 # Wx on Fedora11 spits these out
93 87 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
94 88 UserWarning)
95 89
96 90 #-----------------------------------------------------------------------------
97 91 # Logic for skipping doctests
98 92 #-----------------------------------------------------------------------------
99 93
100 94 def test_for(mod):
101 95 """Test to see if mod is importable."""
102 96 try:
103 97 __import__(mod)
104 98 except (ImportError, RuntimeError):
105 99 # GTK reports Runtime error if it can't be initialized even if it's
106 100 # importable.
107 101 return False
108 102 else:
109 103 return True
110 104
111 105 # Global dict where we can store information on what we have and what we don't
112 106 # have available at test run time
113 107 have = {}
114 108
115 109 have['curses'] = test_for('_curses')
116 110 have['wx'] = test_for('wx')
117 111 have['wx.aui'] = test_for('wx.aui')
118 112 have['zope.interface'] = test_for('zope.interface')
119 113 have['twisted'] = test_for('twisted')
120 114 have['foolscap'] = test_for('foolscap')
121 115 have['objc'] = test_for('objc')
122 116 have['pexpect'] = test_for('pexpect')
123 117 have['gtk'] = test_for('gtk')
124 118 have['gobject'] = test_for('gobject')
125 119
126 120 #-----------------------------------------------------------------------------
127 121 # Functions and classes
128 122 #-----------------------------------------------------------------------------
129 123
130 124 def report():
131 125 """Return a string with a summary report of test-related variables."""
132 126
133 127 out = [ sys_info() ]
134 128
135 out.append('\nRunning from an installed IPython: %s\n' % INSTALLED)
136
137 129 avail = []
138 130 not_avail = []
139 131
140 132 for k, is_avail in have.items():
141 133 if is_avail:
142 134 avail.append(k)
143 135 else:
144 136 not_avail.append(k)
145 137
146 138 if avail:
147 139 out.append('\nTools and libraries available at test time:\n')
148 140 avail.sort()
149 141 out.append(' ' + ' '.join(avail)+'\n')
150 142
151 143 if not_avail:
152 144 out.append('\nTools and libraries NOT available at test time:\n')
153 145 not_avail.sort()
154 146 out.append(' ' + ' '.join(not_avail)+'\n')
155 147
156 148 return ''.join(out)
157 149
158 150
159 151 def make_exclude():
160 152 """Make patterns of modules and packages to exclude from testing.
161 153
162 154 For the IPythonDoctest plugin, we need to exclude certain patterns that
163 155 cause testing problems. We should strive to minimize the number of
164 156 skipped modules, since this means untested code. As the testing
165 157 machinery solidifies, this list should eventually become empty.
166 158 These modules and packages will NOT get scanned by nose at all for tests.
167 159 """
168 160 # Simple utility to make IPython paths more readably, we need a lot of
169 161 # these below
170 162 ipjoin = lambda *paths: pjoin('IPython', *paths)
171 163
172 164 exclusions = [ipjoin('external'),
173 165 ipjoin('frontend', 'process', 'winprocess.py'),
174 166 # Deprecated old Shell and iplib modules, skip to avoid
175 167 # warnings
176 168 ipjoin('Shell'),
177 169 ipjoin('iplib'),
178 170 pjoin('IPython_doctest_plugin'),
179 171 ipjoin('quarantine'),
180 172 ipjoin('deathrow'),
181 173 ipjoin('testing', 'attic'),
182 174 # This guy is probably attic material
183 175 ipjoin('testing', 'mkdoctests'),
184 176 # Testing inputhook will need a lot of thought, to figure out
185 177 # how to have tests that don't lock up with the gui event
186 178 # loops in the picture
187 179 ipjoin('lib', 'inputhook'),
188 180 # Config files aren't really importable stand-alone
189 181 ipjoin('config', 'default'),
190 182 ipjoin('config', 'profile'),
191 183 ]
192 184
193 185 if not have['wx']:
194 186 exclusions.append(ipjoin('gui'))
195 187 exclusions.append(ipjoin('frontend', 'wx'))
196 188 exclusions.append(ipjoin('lib', 'inputhookwx'))
197 189
198 190 if not have['gtk'] or not have['gobject']:
199 191 exclusions.append(ipjoin('lib', 'inputhookgtk'))
200 192
201 193 if not have['wx.aui']:
202 194 exclusions.append(ipjoin('gui', 'wx', 'wxIPython'))
203 195
204 196 if not have['objc']:
205 197 exclusions.append(ipjoin('frontend', 'cocoa'))
206 198
207 199 # These have to be skipped on win32 because the use echo, rm, cd, etc.
208 200 # See ticket https://bugs.launchpad.net/bugs/366982
209 201 if sys.platform == 'win32':
210 202 exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
211 203 exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
212 204
213 205 if not have['pexpect']:
214 206 exclusions.extend([ipjoin('scripts', 'irunner'),
215 207 ipjoin('lib', 'irunner')])
216 208
217 209 # This is scary. We still have things in frontend and testing that
218 210 # are being tested by nose that use twisted. We need to rethink
219 211 # how we are isolating dependencies in testing.
220 212 if not (have['twisted'] and have['zope.interface'] and have['foolscap']):
221 213 exclusions.extend(
222 214 [ipjoin('frontend', 'asyncfrontendbase'),
223 215 ipjoin('frontend', 'prefilterfrontend'),
224 216 ipjoin('frontend', 'frontendbase'),
225 217 ipjoin('frontend', 'linefrontendbase'),
226 218 ipjoin('frontend', 'tests', 'test_linefrontend'),
227 219 ipjoin('frontend', 'tests', 'test_frontendbase'),
228 220 ipjoin('frontend', 'tests', 'test_prefilterfrontend'),
229 221 ipjoin('frontend', 'tests', 'test_asyncfrontendbase'),
230 222 ipjoin('testing', 'parametric'),
231 223 ipjoin('testing', 'util'),
232 224 ipjoin('testing', 'tests', 'test_decorators_trial'),
233 225 ] )
234 226
235 227 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
236 228 if sys.platform == 'win32':
237 229 exclusions = [s.replace('\\','\\\\') for s in exclusions]
238 230
239 231 return exclusions
240 232
241 233
242 234 class IPTester(object):
243 235 """Call that calls iptest or trial in a subprocess.
244 236 """
245 237 #: string, name of test runner that will be called
246 238 runner = None
247 239 #: list, parameters for test runner
248 240 params = None
249 241 #: list, arguments of system call to be made to call test runner
250 242 call_args = None
251 243 #: list, process ids of subprocesses we start (for cleanup)
252 244 pids = None
253 245
254 246 def __init__(self, runner='iptest', params=None):
255 247 """Create new test runner."""
256 248 p = os.path
257 249 if runner == 'iptest':
258 if INSTALLED:
259 250 iptest_app = get_ipython_module_path('IPython.testing.iptest')
260 251 self.runner = pycmd2argv(iptest_app) + sys.argv[1:]
261 252 else:
262 # Find our own 'iptest' script OS-level entry point. Don't
263 # look system-wide, so we are sure we pick up *this one*. And
264 # pass through to subprocess call our own sys.argv
265 ippath = p.abspath(p.join(p.dirname(__file__),'..','..'))
266 script = p.join(ippath, 'iptest.py')
267 self.runner = pycmd2argv(script) + sys.argv[1:]
268
269 else:
270 253 # For trial, it needs to be installed system-wide
271 254 self.runner = pycmd2argv(p.abspath(find_cmd('trial')))
272 255 if params is None:
273 256 params = []
274 257 if isinstance(params, str):
275 258 params = [params]
276 259 self.params = params
277 260
278 261 # Assemble call
279 262 self.call_args = self.runner+self.params
280 263
281 264 # Store pids of anything we start to clean up on deletion, if possible
282 265 # (on posix only, since win32 has no os.kill)
283 266 self.pids = []
284 267
285 268 if sys.platform == 'win32':
286 269 def _run_cmd(self):
287 270 # On Windows, use os.system instead of subprocess.call, because I
288 271 # was having problems with subprocess and I just don't know enough
289 272 # about win32 to debug this reliably. Os.system may be the 'old
290 273 # fashioned' way to do it, but it works just fine. If someone
291 274 # later can clean this up that's fine, as long as the tests run
292 275 # reliably in win32.
293 276 return os.system(' '.join(self.call_args))
294 277 else:
295 278 def _run_cmd(self):
296 279 #print >> sys.stderr, '*** CMD:', ' '.join(self.call_args) # dbg
297 280 subp = subprocess.Popen(self.call_args)
298 281 self.pids.append(subp.pid)
299 282 # If this fails, the pid will be left in self.pids and cleaned up
300 283 # later, but if the wait call succeeds, then we can clear the
301 284 # stored pid.
302 285 retcode = subp.wait()
303 286 self.pids.pop()
304 287 return retcode
305 288
306 289 def run(self):
307 290 """Run the stored commands"""
308 291 try:
309 292 return self._run_cmd()
310 293 except:
311 294 import traceback
312 295 traceback.print_exc()
313 296 return 1 # signal failure
314 297
315 298 def __del__(self):
316 299 """Cleanup on exit by killing any leftover processes."""
317 300
318 301 if not hasattr(os, 'kill'):
319 302 return
320 303
321 304 for pid in self.pids:
322 305 try:
323 306 print 'Cleaning stale PID:', pid
324 307 os.kill(pid, signal.SIGKILL)
325 308 except OSError:
326 309 # This is just a best effort, if we fail or the process was
327 310 # really gone, ignore it.
328 311 pass
329 312
330 313
331 314 def make_runners():
332 315 """Define the top-level packages that need to be tested.
333 316 """
334 317
335 318 # Packages to be tested via nose, that only depend on the stdlib
336 319 nose_pkg_names = ['config', 'core', 'extensions', 'frontend', 'lib',
337 320 'scripts', 'testing', 'utils' ]
338 321 # The machinery in kernel needs twisted for real testing
339 322 trial_pkg_names = []
340 323
341 324 if have['wx']:
342 325 nose_pkg_names.append('gui')
343 326
344 327 # And add twisted ones if conditions are met
345 328 if have['zope.interface'] and have['twisted'] and have['foolscap']:
346 329 # We only list IPython.kernel for testing using twisted.trial as
347 330 # nose and twisted.trial have conflicts that make the testing system
348 331 # unstable.
349 332 trial_pkg_names.append('kernel')
350 333
351 334 # For debugging this code, only load quick stuff
352 335 #nose_pkg_names = ['core', 'extensions'] # dbg
353 336 #trial_pkg_names = [] # dbg
354 337
355 338 # Make fully qualified package names prepending 'IPython.' to our name lists
356 339 nose_packages = ['IPython.%s' % m for m in nose_pkg_names ]
357 340 trial_packages = ['IPython.%s' % m for m in trial_pkg_names ]
358 341
359 342 # Make runners
360 343 runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ]
361 344 runners.extend([ (v, IPTester('trial', params=v)) for v in trial_packages ])
362 345
363 346 return runners
364 347
365 348
366 349 def run_iptest():
367 350 """Run the IPython test suite using nose.
368 351
369 352 This function is called when this script is **not** called with the form
370 353 `iptest all`. It simply calls nose with appropriate command line flags
371 354 and accepts all of the standard nose arguments.
372 355 """
373 356
374 357 warnings.filterwarnings('ignore',
375 358 'This will be removed soon. Use IPython.testing.util instead')
376 359
377 360 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
378 361
379 362 # Loading ipdoctest causes problems with Twisted, but
380 363 # our test suite runner now separates things and runs
381 364 # all Twisted tests with trial.
382 365 '--with-ipdoctest',
383 366 '--ipdoctest-tests','--ipdoctest-extension=txt',
384 367
385 368 # We add --exe because of setuptools' imbecility (it
386 369 # blindly does chmod +x on ALL files). Nose does the
387 370 # right thing and it tries to avoid executables,
388 371 # setuptools unfortunately forces our hand here. This
389 372 # has been discussed on the distutils list and the
390 373 # setuptools devs refuse to fix this problem!
391 374 '--exe',
392 375 ]
393 376
394 377 if nose.__version__ >= '0.11':
395 378 # I don't fully understand why we need this one, but depending on what
396 379 # directory the test suite is run from, if we don't give it, 0 tests
397 380 # get run. Specifically, if the test suite is run from the source dir
398 381 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
399 382 # even if the same call done in this directory works fine). It appears
400 383 # that if the requested package is in the current dir, nose bails early
401 384 # by default. Since it's otherwise harmless, leave it in by default
402 385 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
403 386 argv.append('--traverse-namespace')
404 387
405 388 # Construct list of plugins, omitting the existing doctest plugin, which
406 389 # ours replaces (and extends).
407 390 plugins = [IPythonDoctest(make_exclude())]
408 391 for p in nose.plugins.builtin.plugins:
409 392 plug = p()
410 393 if plug.name == 'doctest':
411 394 continue
412 395 plugins.append(plug)
413 396
414 397 # We need a global ipython running in this process
415 398 globalipapp.start_ipython()
416 399 # Now nose can run
417 400 TestProgram(argv=argv, plugins=plugins)
418 401
419 402
420 403 def run_iptestall():
421 404 """Run the entire IPython test suite by calling nose and trial.
422 405
423 406 This function constructs :class:`IPTester` instances for all IPython
424 407 modules and package and then runs each of them. This causes the modules
425 408 and packages of IPython to be tested each in their own subprocess using
426 409 nose or twisted.trial appropriately.
427 410 """
428 411
429 412 runners = make_runners()
430 413
431 414 # Run the test runners in a temporary dir so we can nuke it when finished
432 415 # to clean up any junk files left over by accident. This also makes it
433 416 # robust against being run in non-writeable directories by mistake, as the
434 417 # temp dir will always be user-writeable.
435 418 curdir = os.getcwd()
436 419 testdir = tempfile.gettempdir()
437 420 os.chdir(testdir)
438 421
439 422 # Run all test runners, tracking execution time
440 423 failed = []
441 424 t_start = time.time()
442 425 try:
443 426 for (name, runner) in runners:
444 427 print '*'*70
445 428 print 'IPython test group:',name
446 429 res = runner.run()
447 430 if res:
448 431 failed.append( (name, runner) )
449 432 finally:
450 433 os.chdir(curdir)
451 434 t_end = time.time()
452 435 t_tests = t_end - t_start
453 436 nrunners = len(runners)
454 437 nfail = len(failed)
455 438 # summarize results
456 439 print
457 440 print '*'*70
458 441 print 'Test suite completed for system with the following information:'
459 442 print report()
460 443 print 'Ran %s test groups in %.3fs' % (nrunners, t_tests)
461 444 print
462 445 print 'Status:'
463 446 if not failed:
464 447 print 'OK'
465 448 else:
466 449 # If anything went wrong, point out what command to rerun manually to
467 450 # see the actual errors and individual summary
468 451 print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners)
469 452 for name, failed_runner in failed:
470 453 print '-'*40
471 454 print 'Runner failed:',name
472 455 print 'You may wish to rerun this one individually, with:'
473 456 print ' '.join(failed_runner.call_args)
474 457 print
475 458
476 459
477 460 def main():
478 461 for arg in sys.argv[1:]:
479 462 if arg.startswith('IPython'):
480 463 # This is in-process
481 464 run_iptest()
482 465 else:
483 466 # This starts subprocesses
484 467 run_iptestall()
485 468
486 469
487 470 if __name__ == '__main__':
488 471 main()
@@ -1,292 +1,277 b''
1 1 """Generic testing tools that do NOT depend on Twisted.
2 2
3 3 In particular, this module exposes a set of top-level assert* functions that
4 4 can be used in place of nose.tools.assert* in method generators (the ones in
5 5 nose can not, at least as of nose 0.10.4).
6 6
7 7 Note: our testing package contains testing.util, which does depend on Twisted
8 8 and provides utilities for tests that manage Deferreds. All testing support
9 9 tools that only depend on nose, IPython or the standard library should go here
10 10 instead.
11 11
12 12
13 13 Authors
14 14 -------
15 15 - Fernando Perez <Fernando.Perez@berkeley.edu>
16 16 """
17 17
18 18 from __future__ import absolute_import
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Copyright (C) 2009 The IPython Development Team
22 22 #
23 23 # Distributed under the terms of the BSD License. The full license is in
24 24 # the file COPYING, distributed as part of this software.
25 25 #-----------------------------------------------------------------------------
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Imports
29 29 #-----------------------------------------------------------------------------
30 30
31 31 import os
32 32 import re
33 33 import sys
34 34
35 35 try:
36 36 # These tools are used by parts of the runtime, so we make the nose
37 37 # dependency optional at this point. Nose is a hard dependency to run the
38 38 # test suite, but NOT to use ipython itself.
39 39 import nose.tools as nt
40 40 has_nose = True
41 41 except ImportError:
42 42 has_nose = False
43 43
44 44 from IPython.config.loader import Config
45 45 from IPython.utils.process import find_cmd, getoutputerror
46 46 from IPython.utils.text import list_strings
47 47 from IPython.utils.io import temp_pyfile
48 48
49 49 from . import decorators as dec
50 50
51 51 #-----------------------------------------------------------------------------
52 52 # Globals
53 53 #-----------------------------------------------------------------------------
54 54
55 # By default, we assume IPython has been installed. But if the test suite is
56 # being run from a source tree that has NOT been installed yet, this flag can
57 # be set to False by the entry point scripts, to let us know that we must call
58 # the source tree versions of the scripts which manipulate sys.path instead of
59 # assuming that things exist system-wide.
60 INSTALLED = True
61
62 55 # Make a bunch of nose.tools assert wrappers that can be used in test
63 56 # generators. This will expose an assert* function for each one in nose.tools.
64 57
65 58 _tpl = """
66 59 def %(name)s(*a,**kw):
67 60 return nt.%(name)s(*a,**kw)
68 61 """
69 62
70 63 if has_nose:
71 64 for _x in [a for a in dir(nt) if a.startswith('assert')]:
72 65 exec _tpl % dict(name=_x)
73 66
74 67 #-----------------------------------------------------------------------------
75 68 # Functions and classes
76 69 #-----------------------------------------------------------------------------
77 70
78 71 # The docstring for full_path doctests differently on win32 (different path
79 72 # separator) so just skip the doctest there. The example remains informative.
80 73 doctest_deco = dec.skip_doctest if sys.platform == 'win32' else dec.null_deco
81 74
82 75 @doctest_deco
83 76 def full_path(startPath,files):
84 77 """Make full paths for all the listed files, based on startPath.
85 78
86 79 Only the base part of startPath is kept, since this routine is typically
87 80 used with a script's __file__ variable as startPath. The base of startPath
88 81 is then prepended to all the listed files, forming the output list.
89 82
90 83 Parameters
91 84 ----------
92 85 startPath : string
93 86 Initial path to use as the base for the results. This path is split
94 87 using os.path.split() and only its first component is kept.
95 88
96 89 files : string or list
97 90 One or more files.
98 91
99 92 Examples
100 93 --------
101 94
102 95 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
103 96 ['/foo/a.txt', '/foo/b.txt']
104 97
105 98 >>> full_path('/foo',['a.txt','b.txt'])
106 99 ['/a.txt', '/b.txt']
107 100
108 101 If a single file is given, the output is still a list:
109 102 >>> full_path('/foo','a.txt')
110 103 ['/a.txt']
111 104 """
112 105
113 106 files = list_strings(files)
114 107 base = os.path.split(startPath)[0]
115 108 return [ os.path.join(base,f) for f in files ]
116 109
117 110
118 111 def parse_test_output(txt):
119 112 """Parse the output of a test run and return errors, failures.
120 113
121 114 Parameters
122 115 ----------
123 116 txt : str
124 117 Text output of a test run, assumed to contain a line of one of the
125 118 following forms::
126 119 'FAILED (errors=1)'
127 120 'FAILED (failures=1)'
128 121 'FAILED (errors=1, failures=1)'
129 122
130 123 Returns
131 124 -------
132 125 nerr, nfail: number of errors and failures.
133 126 """
134 127
135 128 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
136 129 if err_m:
137 130 nerr = int(err_m.group(1))
138 131 nfail = 0
139 132 return nerr, nfail
140 133
141 134 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
142 135 if fail_m:
143 136 nerr = 0
144 137 nfail = int(fail_m.group(1))
145 138 return nerr, nfail
146 139
147 140 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
148 141 re.MULTILINE)
149 142 if both_m:
150 143 nerr = int(both_m.group(1))
151 144 nfail = int(both_m.group(2))
152 145 return nerr, nfail
153 146
154 147 # If the input didn't match any of these forms, assume no error/failures
155 148 return 0, 0
156 149
157 150
158 151 # So nose doesn't think this is a test
159 152 parse_test_output.__test__ = False
160 153
161 154
162 155 def default_argv():
163 156 """Return a valid default argv for creating testing instances of ipython"""
164 157
165 158 return ['--quick', # so no config file is loaded
166 159 # Other defaults to minimize side effects on stdout
167 160 '--colors=NoColor', '--no-term-title','--no-banner',
168 161 '--autocall=0']
169 162
170 163
171 164 def default_config():
172 165 """Return a config object with good defaults for testing."""
173 166 config = Config()
174 167 config.InteractiveShell.colors = 'NoColor'
175 168 config.InteractiveShell.term_title = False,
176 169 config.InteractiveShell.autocall = 0
177 170 return config
178 171
179 172
180 173 def ipexec(fname, options=None):
181 174 """Utility to call 'ipython filename'.
182 175
183 176 Starts IPython witha minimal and safe configuration to make startup as fast
184 177 as possible.
185 178
186 179 Note that this starts IPython in a subprocess!
187 180
188 181 Parameters
189 182 ----------
190 183 fname : str
191 184 Name of file to be executed (should have .py or .ipy extension).
192 185
193 186 options : optional, list
194 187 Extra command-line flags to be passed to IPython.
195 188
196 189 Returns
197 190 -------
198 191 (stdout, stderr) of ipython subprocess.
199 192 """
200 193 if options is None: options = []
201 194
202 195 # For these subprocess calls, eliminate all prompt printing so we only see
203 196 # output from script execution
204 197 prompt_opts = ['--prompt-in1=""', '--prompt-in2=""', '--prompt-out=""']
205 198 cmdargs = ' '.join(default_argv() + prompt_opts + options)
206 199
207 200 _ip = get_ipython()
208 201 test_dir = os.path.dirname(__file__)
209 202
210 # Find the ipython script from the package we're using, so that the test
211 # suite can be run from the source tree without an installed IPython
212 p = os.path
213 if INSTALLED:
214 203 ipython_cmd = find_cmd('ipython')
215 else:
216 ippath = p.abspath(p.join(p.dirname(__file__),'..','..'))
217 ipython_script = p.join(ippath, 'ipython.py')
218 ipython_cmd = 'python "%s"' % ipython_script
219 204 # Absolute path for filename
220 full_fname = p.join(test_dir, fname)
205 full_fname = os.path.join(test_dir, fname)
221 206 full_cmd = '%s %s %s' % (ipython_cmd, cmdargs, full_fname)
222 207 #print >> sys.stderr, 'FULL CMD:', full_cmd # dbg
223 208 return getoutputerror(full_cmd)
224 209
225 210
226 211 def ipexec_validate(fname, expected_out, expected_err='',
227 212 options=None):
228 213 """Utility to call 'ipython filename' and validate output/error.
229 214
230 215 This function raises an AssertionError if the validation fails.
231 216
232 217 Note that this starts IPython in a subprocess!
233 218
234 219 Parameters
235 220 ----------
236 221 fname : str
237 222 Name of the file to be executed (should have .py or .ipy extension).
238 223
239 224 expected_out : str
240 225 Expected stdout of the process.
241 226
242 227 expected_err : optional, str
243 228 Expected stderr of the process.
244 229
245 230 options : optional, list
246 231 Extra command-line flags to be passed to IPython.
247 232
248 233 Returns
249 234 -------
250 235 None
251 236 """
252 237
253 238 import nose.tools as nt
254 239
255 240 out, err = ipexec(fname)
256 241 #print 'OUT', out # dbg
257 242 #print 'ERR', err # dbg
258 243 # If there are any errors, we must check those befor stdout, as they may be
259 244 # more informative than simply having an empty stdout.
260 245 if err:
261 246 if expected_err:
262 247 nt.assert_equals(err.strip(), expected_err.strip())
263 248 else:
264 249 raise ValueError('Running file %r produced error: %r' %
265 250 (fname, err))
266 251 # If no errors or output on stderr was expected, match stdout
267 252 nt.assert_equals(out.strip(), expected_out.strip())
268 253
269 254
270 255 class TempFileMixin(object):
271 256 """Utility class to create temporary Python/IPython files.
272 257
273 258 Meant as a mixin class for test cases."""
274 259
275 260 def mktmp(self, src, ext='.py'):
276 261 """Make a valid python temp file."""
277 262 fname, f = temp_pyfile(src, ext)
278 263 self.tmpfile = f
279 264 self.fname = fname
280 265
281 266 def teardown(self):
282 267 if hasattr(self, 'tmpfile'):
283 268 # If the tmpfile wasn't made because of skipped tests, like in
284 269 # win32, there's nothing to cleanup.
285 270 self.tmpfile.close()
286 271 try:
287 272 os.unlink(self.fname)
288 273 except:
289 274 # On Windows, even though we close the file, we still can't
290 275 # delete it. I have no clue why
291 276 pass
292 277
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now