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