##// END OF EJS Templates
Work in multiple places to improve state of the test suite....
Fernando Perez -
Show More
@@ -964,26 +964,43 b' class InteractiveShell(Component, Magic):'
964 method. If they were not empty before, data will simply be added to
964 method. If they were not empty before, data will simply be added to
965 therm.
965 therm.
966 """
966 """
967 # Store myself as the public api!!!
967 # This function works in two parts: first we put a few things in
968 self.user_ns['get_ipython'] = self.get_ipython
968 # user_ns, and we sync that contents into user_config_ns so that these
969 # initial variables aren't shown by %who. After the sync, we add the
970 # rest of what we *do* want the user to see with %who even on a new
971 # session.
972 ns = {}
973
974 # Put 'help' in the user namespace
975 try:
976 from site import _Helper
977 ns['help'] = _Helper()
978 except ImportError:
979 warn('help() not available - check site.py')
969
980
970 # make global variables for user access to the histories
981 # make global variables for user access to the histories
971 self.user_ns['_ih'] = self.input_hist
982 ns['_ih'] = self.input_hist
972 self.user_ns['_oh'] = self.output_hist
983 ns['_oh'] = self.output_hist
973 self.user_ns['_dh'] = self.dir_hist
984 ns['_dh'] = self.dir_hist
985
986 ns['_sh'] = shadowns
987
988 # Sync what we've added so far to user_config_ns so these aren't seen
989 # by %who
990 self.user_config_ns.update(ns)
991
992 # Now, continue adding more contents
974
993
975 # user aliases to input and output histories
994 # user aliases to input and output histories
976 self.user_ns['In'] = self.input_hist
995 ns['In'] = self.input_hist
977 self.user_ns['Out'] = self.output_hist
996 ns['Out'] = self.output_hist
978
997
979 self.user_ns['_sh'] = shadowns
998 # Store myself as the public api!!!
999 ns['get_ipython'] = self.get_ipython
1000
1001 # And update the real user's namespace
1002 self.user_ns.update(ns)
980
1003
981 # Put 'help' in the user namespace
982 try:
983 from site import _Helper
984 self.user_ns['help'] = _Helper()
985 except ImportError:
986 warn('help() not available - check site.py')
987
1004
988 def reset(self):
1005 def reset(self):
989 """Clear all internal namespaces.
1006 """Clear all internal namespaces.
@@ -15,7 +15,7 b' import nose.tools as nt'
15 # our own packages
15 # our own packages
16 from IPython.core import iplib
16 from IPython.core import iplib
17 from IPython.core import ipapi
17 from IPython.core import ipapi
18
18 from IPython.testing import decorators as dec
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Globals
21 # Globals
@@ -43,15 +43,33 b' if ip is None:'
43 # Test functions
43 # Test functions
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45
45
46 @dec.parametric
46 def test_reset():
47 def test_reset():
47 """reset must clear most namespaces."""
48 """reset must clear most namespaces."""
48 ip.reset() # first, it should run without error
49 # The number of variables in the private user_config_ns is not zero, but it
49 # Then, check that most namespaces end up empty
50 # should be constant regardless of what we do
51 nvars_config_ns = len(ip.user_config_ns)
52
53 # Check that reset runs without error
54 ip.reset()
55
56 # Once we've reset it (to clear of any junk that might have been there from
57 # other tests, we can count how many variables are in the user's namespace
58 nvars_user_ns = len(ip.user_ns)
59
60 # Now add a few variables to user_ns, and check that reset clears them
61 ip.user_ns['x'] = 1
62 ip.user_ns['y'] = 1
63 ip.reset()
64
65 # Finally, check that all namespaces have only as many variables as we
66 # expect to find in them:
50 for ns in ip.ns_refs_table:
67 for ns in ip.ns_refs_table:
51 if ns is ip.user_ns:
68 if ns is ip.user_ns:
52 # The user namespace is reset with some data, so we can't check for
69 nvars_expected = nvars_user_ns
53 # it being empty
70 elif ns is ip.user_config_ns:
54 continue
71 nvars_expected = nvars_config_ns
55 nt.assert_equals(len(ns),0)
72 else:
56
73 nvars_expected = 0
57 No newline at end of file
74
75 yield nt.assert_equals(len(ns), nvars_expected)
@@ -9,7 +9,6 b' functionnality is abstracted out of ipython0 in reusable functions and'
9 is added on the interpreter. This class can be a used to guide this
9 is added on the interpreter. This class can be a used to guide this
10 refactoring.
10 refactoring.
11 """
11 """
12 __docformat__ = "restructuredtext en"
13
12
14 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
15 # Copyright (C) 2008 The IPython Development Team
14 # Copyright (C) 2008 The IPython Development Team
@@ -27,7 +26,7 b' import os'
27 import re
26 import re
28 import __builtin__
27 import __builtin__
29
28
30 from IPython.core.ipmaker import make_IPython
29 from IPython.core.ipapp import IPythonApp
31 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
30 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
32
31
33 from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap
32 from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap
@@ -36,6 +35,9 b' from IPython.utils.genutils import Term'
36
35
37 from linefrontendbase import LineFrontEndBase, common_prefix
36 from linefrontendbase import LineFrontEndBase, common_prefix
38
37
38 #-----------------------------------------------------------------------------
39 # Utility functions
40 #-----------------------------------------------------------------------------
39
41
40 def mk_system_call(system_call_function, command):
42 def mk_system_call(system_call_function, command):
41 """ given a os.system replacement, and a leading string command,
43 """ given a os.system replacement, and a leading string command,
@@ -74,7 +76,7 b' class PrefilterFrontEnd(LineFrontEndBase):'
74 Used as the instance's argv value. If not given, [] is used.
76 Used as the instance's argv value. If not given, [] is used.
75 """
77 """
76 if argv is None:
78 if argv is None:
77 argv = []
79 argv = ['--no-banner']
78 # This is a hack to avoid the IPython exception hook to trigger
80 # This is a hack to avoid the IPython exception hook to trigger
79 # on exceptions (https://bugs.launchpad.net/bugs/337105)
81 # on exceptions (https://bugs.launchpad.net/bugs/337105)
80 # XXX: This is horrible: module-leve monkey patching -> side
82 # XXX: This is horrible: module-leve monkey patching -> side
@@ -101,12 +103,15 b' class PrefilterFrontEnd(LineFrontEndBase):'
101 return '\n'
103 return '\n'
102 old_rawinput = __builtin__.raw_input
104 old_rawinput = __builtin__.raw_input
103 __builtin__.raw_input = my_rawinput
105 __builtin__.raw_input = my_rawinput
104 # XXX: argv=[] is a bit bold.
106 ipython0 = IPythonApp(argv=argv,
105 ipython0 = make_IPython(argv=argv,
107 user_ns=self.shell.user_ns,
106 user_ns=self.shell.user_ns,
108 user_global_ns=self.shell.user_global_ns)
107 user_global_ns=self.shell.user_global_ns)
109 ipython0.initialize()
108 __builtin__.raw_input = old_rawinput
110 __builtin__.raw_input = old_rawinput
109 self.ipython0 = ipython0
111 # XXX This will need to be updated as we refactor things, but for now,
112 # the .shell attribute of the ipythonapp instance conforms to the old
113 # api.
114 self.ipython0 = ipython0.shell
110 # Set the pager:
115 # Set the pager:
111 self.ipython0.set_hook('show_in_pager',
116 self.ipython0.set_hook('show_in_pager',
112 lambda s, string: self.write("\n" + string))
117 lambda s, string: self.write("\n" + string))
@@ -202,8 +207,7 b' class PrefilterFrontEnd(LineFrontEndBase):'
202 if completions:
207 if completions:
203 prefix = common_prefix(completions)
208 prefix = common_prefix(completions)
204 line = line[:-len(word)] + prefix
209 line = line[:-len(word)] + prefix
205 return line, completions
210 return line, completions
206
207
211
208 #--------------------------------------------------------------------------
212 #--------------------------------------------------------------------------
209 # LineFrontEndBase interface
213 # LineFrontEndBase interface
@@ -220,23 +224,11 b' class PrefilterFrontEnd(LineFrontEndBase):'
220 self.capture_output()
224 self.capture_output()
221 self.last_result = dict(number=self.prompt_number)
225 self.last_result = dict(number=self.prompt_number)
222
226
223 ## try:
224 ## for line in input_string.split('\n'):
225 ## filtered_lines.append(
226 ## self.ipython0.prefilter(line, False).rstrip())
227 ## except:
228 ## # XXX: probably not the right thing to do.
229 ## self.ipython0.showsyntaxerror()
230 ## self.after_execute()
231 ## finally:
232 ## self.release_output()
233
234
235 try:
227 try:
236 try:
228 try:
237 for line in input_string.split('\n'):
229 for line in input_string.split('\n'):
238 filtered_lines.append(
230 pf = self.ipython0.prefilter_manager.prefilter_lines
239 self.ipython0.prefilter(line, False).rstrip())
231 filtered_lines.append(pf(line, False).rstrip())
240 except:
232 except:
241 # XXX: probably not the right thing to do.
233 # XXX: probably not the right thing to do.
242 self.ipython0.showsyntaxerror()
234 self.ipython0.showsyntaxerror()
@@ -244,13 +236,10 b' class PrefilterFrontEnd(LineFrontEndBase):'
244 finally:
236 finally:
245 self.release_output()
237 self.release_output()
246
238
247
248
249 # Clean up the trailing whitespace, to avoid indentation errors
239 # Clean up the trailing whitespace, to avoid indentation errors
250 filtered_string = '\n'.join(filtered_lines)
240 filtered_string = '\n'.join(filtered_lines)
251 return filtered_string
241 return filtered_string
252
242
253
254 #--------------------------------------------------------------------------
243 #--------------------------------------------------------------------------
255 # PrefilterFrontEnd interface
244 # PrefilterFrontEnd interface
256 #--------------------------------------------------------------------------
245 #--------------------------------------------------------------------------
@@ -261,13 +250,11 b' class PrefilterFrontEnd(LineFrontEndBase):'
261 """
250 """
262 return os.system(command_string)
251 return os.system(command_string)
263
252
264
265 def do_exit(self):
253 def do_exit(self):
266 """ Exit the shell, cleanup and save the history.
254 """ Exit the shell, cleanup and save the history.
267 """
255 """
268 self.ipython0.atexit_operations()
256 self.ipython0.atexit_operations()
269
257
270
271 def _get_completion_text(self, line):
258 def _get_completion_text(self, line):
272 """ Returns the text to be completed by breaking the line at specified
259 """ Returns the text to be completed by breaking the line at specified
273 delimiters.
260 delimiters.
@@ -281,4 +268,3 b' class PrefilterFrontEnd(LineFrontEndBase):'
281 complete_sep = re.compile(expression)
268 complete_sep = re.compile(expression)
282 text = complete_sep.split(line)[-1]
269 text = complete_sep.split(line)[-1]
283 return text
270 return text
284
@@ -23,6 +23,9 b' from IPython.frontend.prefilterfrontend import PrefilterFrontEnd'
23 from IPython.core.ipapi import get as get_ipython0
23 from IPython.core.ipapi import get as get_ipython0
24 from IPython.testing.plugin.ipdoctest import default_argv
24 from IPython.testing.plugin.ipdoctest import default_argv
25
25
26 #-----------------------------------------------------------------------------
27 # Support utilities
28 #-----------------------------------------------------------------------------
26
29
27 class TestPrefilterFrontEnd(PrefilterFrontEnd):
30 class TestPrefilterFrontEnd(PrefilterFrontEnd):
28
31
@@ -93,6 +96,9 b' def isolate_ipython0(func):'
93 my_func.__name__ = func.__name__
96 my_func.__name__ = func.__name__
94 return my_func
97 return my_func
95
98
99 #-----------------------------------------------------------------------------
100 # Tests
101 #-----------------------------------------------------------------------------
96
102
97 @isolate_ipython0
103 @isolate_ipython0
98 def test_execution():
104 def test_execution():
@@ -166,7 +172,7 b' def test_magic():'
166 f.input_buffer += '%who'
172 f.input_buffer += '%who'
167 f._on_enter()
173 f._on_enter()
168 out_value = f.out.getvalue()
174 out_value = f.out.getvalue()
169 assert_equal(out_value, 'Interactive namespace is empty.\n')
175 assert_equal(out_value, 'In\tOut\tget_ipython\t\n')
170
176
171
177
172 @isolate_ipython0
178 @isolate_ipython0
@@ -31,12 +31,20 b' import warnings'
31 import nose.plugins.builtin
31 import nose.plugins.builtin
32 from nose.core import TestProgram
32 from nose.core import TestProgram
33
33
34 from IPython.utils.platutils import find_cmd
34 from IPython.utils import genutils
35 # from IPython.testing.plugin.ipdoctest import IPythonDoctest
35 from IPython.utils.platutils import find_cmd, FindCmdError
36
36
37 pjoin = path.join
37 pjoin = path.join
38
38
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40 # Warnings control
41 #-----------------------------------------------------------------------------
42 # Twisted generates annoying warnings with Python 2.6, as will do other code
43 # that imports 'sets' as of today
44 warnings.filterwarnings('ignore', 'the sets module is deprecated',
45 DeprecationWarning )
46
47 #-----------------------------------------------------------------------------
40 # Logic for skipping doctests
48 # Logic for skipping doctests
41 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
42
50
@@ -63,10 +71,10 b" have_gobject = test_for('gobject')"
63
71
64 def make_exclude():
72 def make_exclude():
65
73
66 # For the IPythonDoctest plugin, we need to exclude certain patterns that cause
74 # For the IPythonDoctest plugin, we need to exclude certain patterns that
67 # testing problems. We should strive to minimize the number of skipped
75 # cause testing problems. We should strive to minimize the number of
68 # modules, since this means untested code. As the testing machinery
76 # skipped modules, since this means untested code. As the testing
69 # solidifies, this list should eventually become empty.
77 # machinery solidifies, this list should eventually become empty.
70 EXCLUDE = [pjoin('IPython', 'external'),
78 EXCLUDE = [pjoin('IPython', 'external'),
71 pjoin('IPython', 'frontend', 'process', 'winprocess.py'),
79 pjoin('IPython', 'frontend', 'process', 'winprocess.py'),
72 pjoin('IPython_doctest_plugin'),
80 pjoin('IPython_doctest_plugin'),
@@ -137,6 +145,82 b' def make_exclude():'
137 # Functions and classes
145 # Functions and classes
138 #-----------------------------------------------------------------------------
146 #-----------------------------------------------------------------------------
139
147
148 class IPTester(object):
149 """Call that calls iptest or trial in a subprocess.
150 """
151 def __init__(self,runner='iptest',params=None):
152 """ """
153 if runner == 'iptest':
154 # Find our own 'iptest' script OS-level entry point
155 try:
156 iptest_path = find_cmd('iptest')
157 except FindCmdError:
158 # Script not installed (may be the case for testing situations
159 # that are running from a source tree only), pull from internal
160 # path:
161 iptest_path = pjoin(genutils.get_ipython_package_dir(),
162 'scripts','iptest')
163 self.runner = [iptest_path,'-v']
164 else:
165 self.runner = [find_cmd('trial')]
166 if params is None:
167 params = []
168 if isinstance(params,str):
169 params = [params]
170 self.params = params
171
172 # Assemble call
173 self.call_args = self.runner+self.params
174
175 if sys.platform == 'win32':
176 def _run_cmd(self):
177 # On Windows, use os.system instead of subprocess.call, because I
178 # was having problems with subprocess and I just don't know enough
179 # about win32 to debug this reliably. Os.system may be the 'old
180 # fashioned' way to do it, but it works just fine. If someone
181 # later can clean this up that's fine, as long as the tests run
182 # reliably in win32.
183 return os.system(' '.join(self.call_args))
184 else:
185 def _run_cmd(self):
186 return subprocess.call(self.call_args)
187
188 def run(self):
189 """Run the stored commands"""
190 try:
191 return self._run_cmd()
192 except:
193 import traceback
194 traceback.print_exc()
195 return 1 # signal failure
196
197
198 def make_runners():
199 """Define the top-level packages that need to be tested.
200 """
201
202 nose_packages = ['config', 'core', 'extensions', 'frontend', 'lib',
203 'scripts', 'testing', 'utils']
204 trial_packages = ['kernel']
205 #trial_packages = [] # dbg
206
207 if have_wx:
208 nose_packages.append('gui')
209
210 nose_packages = ['IPython.%s' % m for m in nose_packages ]
211 trial_packages = ['IPython.%s' % m for m in trial_packages ]
212
213 # Make runners, most with nose
214 nose_testers = [IPTester(params=v) for v in nose_packages]
215 runners = dict(zip(nose_packages, nose_testers))
216 # And add twisted ones if conditions are met
217 if have_zi and have_twisted and have_foolscap:
218 trial_testers = [IPTester('trial',params=v) for v in trial_packages]
219 runners.update(dict(zip(trial_packages,trial_testers)))
220
221 return runners
222
223
140 def run_iptest():
224 def run_iptest():
141 """Run the IPython test suite using nose.
225 """Run the IPython test suite using nose.
142
226
@@ -194,81 +278,6 b' def run_iptest():'
194 TestProgram(argv=argv,plugins=plugins)
278 TestProgram(argv=argv,plugins=plugins)
195
279
196
280
197 class IPTester(object):
198 """Call that calls iptest or trial in a subprocess.
199 """
200 def __init__(self,runner='iptest',params=None):
201 """ """
202 if runner == 'iptest':
203 self.runner = ['iptest','-v']
204 else:
205 self.runner = [find_cmd('trial')]
206 if params is None:
207 params = []
208 if isinstance(params,str):
209 params = [params]
210 self.params = params
211
212 # Assemble call
213 self.call_args = self.runner+self.params
214
215 if sys.platform == 'win32':
216 def run(self):
217 """Run the stored commands"""
218 # On Windows, cd to temporary directory to run tests. Otherwise,
219 # Twisted's trial may not be able to execute 'trial IPython', since
220 # it will confuse the IPython module name with the ipython
221 # execution scripts, because the windows file system isn't case
222 # sensitive.
223 # We also use os.system instead of subprocess.call, because I was
224 # having problems with subprocess and I just don't know enough
225 # about win32 to debug this reliably. Os.system may be the 'old
226 # fashioned' way to do it, but it works just fine. If someone
227 # later can clean this up that's fine, as long as the tests run
228 # reliably in win32.
229 curdir = os.getcwd()
230 os.chdir(tempfile.gettempdir())
231 stat = os.system(' '.join(self.call_args))
232 os.chdir(curdir)
233 return stat
234 else:
235 def run(self):
236 """Run the stored commands"""
237 try:
238 return subprocess.call(self.call_args)
239 except:
240 import traceback
241 traceback.print_exc()
242 return 1 # signal failure
243
244
245 def make_runners():
246 """Define the top-level packages that need to be tested.
247 """
248
249 nose_packages = ['config', 'core', 'extensions',
250 'frontend', 'lib',
251 'scripts', 'testing', 'utils']
252 trial_packages = ['kernel']
253
254 if have_wx:
255 nose_packages.append('gui')
256
257 nose_packages = ['IPython.%s' % m for m in nose_packages ]
258 trial_packages = ['IPython.%s' % m for m in trial_packages ]
259
260 # Make runners
261 runners = dict()
262
263 nose_runners = dict(zip(nose_packages, [IPTester(params=v) for v in nose_packages]))
264 if have_zi and have_twisted and have_foolscap:
265 trial_runners = dict(zip(trial_packages, [IPTester('trial',params=v) for v in trial_packages]))
266 runners.update(nose_runners)
267 runners.update(trial_runners)
268
269 return runners
270
271
272 def run_iptestall():
281 def run_iptestall():
273 """Run the entire IPython test suite by calling nose and trial.
282 """Run the entire IPython test suite by calling nose and trial.
274
283
@@ -280,15 +289,26 b' def run_iptestall():'
280
289
281 runners = make_runners()
290 runners = make_runners()
282
291
292 # Run the test runners in a temporary dir so we can nuke it when finished
293 # to clean up any junk files left over by accident. This also makes it
294 # robust against being run in non-writeable directories by mistake, as the
295 # temp dir will always be user-writeable.
296 curdir = os.getcwd()
297 testdir = tempfile.gettempdir()
298 os.chdir(testdir)
299
283 # Run all test runners, tracking execution time
300 # Run all test runners, tracking execution time
284 failed = {}
301 failed = {}
285 t_start = time.time()
302 t_start = time.time()
286 for name,runner in runners.iteritems():
303 try:
287 print '*'*77
304 for name,runner in runners.iteritems():
288 print 'IPython test group:',name
305 print '*'*77
289 res = runner.run()
306 print 'IPython test group:',name
290 if res:
307 res = runner.run()
291 failed[name] = res
308 if res:
309 failed[name] = res
310 finally:
311 os.chdir(curdir)
292 t_end = time.time()
312 t_end = time.time()
293 t_tests = t_end - t_start
313 t_tests = t_end - t_start
294 nrunners = len(runners)
314 nrunners = len(runners)
@@ -68,7 +68,8 b' def default_argv():'
68 ipcdir = os.path.dirname(default.__file__)
68 ipcdir = os.path.dirname(default.__file__)
69 ipconf = os.path.join(ipcdir,'ipython_config.py')
69 ipconf = os.path.join(ipcdir,'ipython_config.py')
70 #print 'conf:',ipconf # dbg
70 #print 'conf:',ipconf # dbg
71 return ['--colors=NoColor','--no-term-title','--config-file=%s' % ipconf]
71 return ['--colors=NoColor', '--no-term-title','--no-banner',
72 '--config-file=%s' % ipconf]
72
73
73
74
74 # Hack to modify the %run command so we can sync the user's namespace with the
75 # Hack to modify the %run command so we can sync the user's namespace with the
General Comments 0
You need to be logged in to leave comments. Login now