##// END OF EJS Templates
Fix some tests using magics....
Fernando Perez -
Show More
@@ -1,908 +1,917 b''
1 """Nose Plugin that supports IPython doctests.
1 """Nose Plugin that supports IPython doctests.
2
2
3 Limitations:
3 Limitations:
4
4
5 - When generating examples for use as doctests, make sure that you have
5 - When generating examples for use as doctests, make sure that you have
6 pretty-printing OFF. This can be done either by starting ipython with the
6 pretty-printing OFF. This can be done either by starting ipython with the
7 flag '--nopprint', by setting pprint to 0 in your ipythonrc file, or by
7 flag '--nopprint', by setting pprint to 0 in your ipythonrc file, or by
8 interactively disabling it with %Pprint. This is required so that IPython
8 interactively disabling it with %Pprint. This is required so that IPython
9 output matches that of normal Python, which is used by doctest for internal
9 output matches that of normal Python, which is used by doctest for internal
10 execution.
10 execution.
11
11
12 - Do not rely on specific prompt numbers for results (such as using
12 - Do not rely on specific prompt numbers for results (such as using
13 '_34==True', for example). For IPython tests run via an external process the
13 '_34==True', for example). For IPython tests run via an external process the
14 prompt numbers may be different, and IPython tests run as normal python code
14 prompt numbers may be different, and IPython tests run as normal python code
15 won't even have these special _NN variables set at all.
15 won't even have these special _NN variables set at all.
16 """
16 """
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Module imports
19 # Module imports
20
20
21 # From the standard library
21 # From the standard library
22 import __builtin__
22 import __builtin__
23 import commands
23 import commands
24 import doctest
24 import doctest
25 import inspect
25 import inspect
26 import logging
26 import logging
27 import os
27 import os
28 import re
28 import re
29 import sys
29 import sys
30 import traceback
30 import traceback
31 import unittest
31 import unittest
32
32
33 from inspect import getmodule
33 from inspect import getmodule
34 from StringIO import StringIO
34 from StringIO import StringIO
35
35
36 # We are overriding the default doctest runner, so we need to import a few
36 # We are overriding the default doctest runner, so we need to import a few
37 # things from doctest directly
37 # things from doctest directly
38 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
38 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
39 _unittest_reportflags, DocTestRunner,
39 _unittest_reportflags, DocTestRunner,
40 _extract_future_flags, pdb, _OutputRedirectingPdb,
40 _extract_future_flags, pdb, _OutputRedirectingPdb,
41 _exception_traceback,
41 _exception_traceback,
42 linecache)
42 linecache)
43
43
44 # Third-party modules
44 # Third-party modules
45 import nose.core
45 import nose.core
46
46
47 from nose.plugins import doctests, Plugin
47 from nose.plugins import doctests, Plugin
48 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
48 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
49
49
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51 # Module globals and other constants
51 # Module globals and other constants
52
52
53 log = logging.getLogger(__name__)
53 log = logging.getLogger(__name__)
54
54
55 ###########################################################################
55 ###########################################################################
56 # *** HACK ***
56 # *** HACK ***
57 # We must start our own ipython object and heavily muck with it so that all the
57 # We must start our own ipython object and heavily muck with it so that all the
58 # modifications IPython makes to system behavior don't send the doctest
58 # modifications IPython makes to system behavior don't send the doctest
59 # machinery into a fit. This code should be considered a gross hack, but it
59 # machinery into a fit. This code should be considered a gross hack, but it
60 # gets the job done.
60 # gets the job done.
61
61
62 def default_argv():
62 def default_argv():
63 """Return a valid default argv for creating testing instances of ipython"""
63 """Return a valid default argv for creating testing instances of ipython"""
64
64
65 # Get the install directory for the user configuration and tell ipython to
65 # Get the install directory for the user configuration and tell ipython to
66 # use the default profile from there.
66 # use the default profile from there.
67 from IPython import UserConfig
67 from IPython import UserConfig
68 ipcdir = os.path.dirname(UserConfig.__file__)
68 ipcdir = os.path.dirname(UserConfig.__file__)
69 #ipconf = os.path.join(ipcdir,'ipy_user_conf.py')
69 #ipconf = os.path.join(ipcdir,'ipy_user_conf.py')
70 ipconf = os.path.join(ipcdir,'ipythonrc')
70 ipconf = os.path.join(ipcdir,'ipythonrc')
71 #print 'conf:',ipconf # dbg
71 #print 'conf:',ipconf # dbg
72
72
73 return ['--colors=NoColor','--noterm_title','-rcfile=%s' % ipconf]
73 return ['--colors=NoColor','--noterm_title','-rcfile=%s' % ipconf]
74
74
75
75
76 # Hack to modify the %run command so we can sync the user's namespace with the
76 # Hack to modify the %run command so we can sync the user's namespace with the
77 # test globals. Once we move over to a clean magic system, this will be done
77 # test globals. Once we move over to a clean magic system, this will be done
78 # with much less ugliness.
78 # with much less ugliness.
79
79
80 class py_file_finder(object):
80 class py_file_finder(object):
81 def __init__(self,test_filename):
81 def __init__(self,test_filename):
82 self.test_filename = test_filename
82 self.test_filename = test_filename
83
83
84 def __call__(self,name):
84 def __call__(self,name):
85 from IPython.genutils import get_py_filename
85 from IPython.genutils import get_py_filename
86 try:
86 try:
87 return get_py_filename(name)
87 return get_py_filename(name)
88 except IOError:
88 except IOError:
89 test_dir = os.path.dirname(self.test_filename)
89 test_dir = os.path.dirname(self.test_filename)
90 new_path = os.path.join(test_dir,name)
90 new_path = os.path.join(test_dir,name)
91 return get_py_filename(new_path)
91 return get_py_filename(new_path)
92
92
93
93
94 def _run_ns_sync(self,arg_s,runner=None):
94 def _run_ns_sync(self,arg_s,runner=None):
95 """Modified version of %run that syncs testing namespaces.
95 """Modified version of %run that syncs testing namespaces.
96
96
97 This is strictly needed for running doctests that call %run.
97 This is strictly needed for running doctests that call %run.
98 """
98 """
99
99
100 # When tests call %run directly (not via doctest) these function attributes
100 # When tests call %run directly (not via doctest) these function attributes
101 # are not set
101 # are not set
102 try:
102 try:
103 fname = _run_ns_sync.test_filename
103 fname = _run_ns_sync.test_filename
104 except AttributeError:
104 except AttributeError:
105 fname = arg_s
105 fname = arg_s
106
106
107 finder = py_file_finder(fname)
107 finder = py_file_finder(fname)
108 out = _ip.IP.magic_run_ori(arg_s,runner,finder)
108 out = _ip.IP.magic_run_ori(arg_s,runner,finder)
109
109
110 # Simliarly, there is no test_globs when a test is NOT a doctest
110 # Simliarly, there is no test_globs when a test is NOT a doctest
111 if hasattr(_run_ns_sync,'test_globs'):
111 if hasattr(_run_ns_sync,'test_globs'):
112 _run_ns_sync.test_globs.update(_ip.user_ns)
112 _run_ns_sync.test_globs.update(_ip.user_ns)
113 return out
113 return out
114
114
115
115
116 class ipnsdict(dict):
116 class ipnsdict(dict):
117 """A special subclass of dict for use as an IPython namespace in doctests.
117 """A special subclass of dict for use as an IPython namespace in doctests.
118
118
119 This subclass adds a simple checkpointing capability so that when testing
119 This subclass adds a simple checkpointing capability so that when testing
120 machinery clears it (we use it as the test execution context), it doesn't
120 machinery clears it (we use it as the test execution context), it doesn't
121 get completely destroyed.
121 get completely destroyed.
122 """
122 """
123
123
124 def __init__(self,*a):
124 def __init__(self,*a):
125 dict.__init__(self,*a)
125 dict.__init__(self,*a)
126 self._savedict = {}
126 self._savedict = {}
127
127
128 def clear(self):
128 def clear(self):
129 dict.clear(self)
129 dict.clear(self)
130 self.update(self._savedict)
130 self.update(self._savedict)
131
131
132 def _checkpoint(self):
132 def _checkpoint(self):
133 self._savedict.clear()
133 self._savedict.clear()
134 self._savedict.update(self)
134 self._savedict.update(self)
135
135
136 def update(self,other):
136 def update(self,other):
137 self._checkpoint()
137 self._checkpoint()
138 dict.update(self,other)
138 dict.update(self,other)
139
139
140 # If '_' is in the namespace, python won't set it when executing code,
140 # If '_' is in the namespace, python won't set it when executing code,
141 # and we have examples that test it. So we ensure that the namespace
141 # and we have examples that test it. So we ensure that the namespace
142 # is always 'clean' of it before it's used for test code execution.
142 # is always 'clean' of it before it's used for test code execution.
143 self.pop('_',None)
143 self.pop('_',None)
144
144
145 # The builtins namespace must *always* be the real __builtin__ module,
145 # The builtins namespace must *always* be the real __builtin__ module,
146 # else weird stuff happens. The main ipython code does have provisions
146 # else weird stuff happens. The main ipython code does have provisions
147 # to ensure this after %run, but since in this class we do some
147 # to ensure this after %run, but since in this class we do some
148 # aggressive low-level cleaning of the execution namespace, we need to
148 # aggressive low-level cleaning of the execution namespace, we need to
149 # correct for that ourselves, to ensure consitency with the 'real'
149 # correct for that ourselves, to ensure consitency with the 'real'
150 # ipython.
150 # ipython.
151 self['__builtins__'] = __builtin__
151 self['__builtins__'] = __builtin__
152
152
153
153
154 def start_ipython():
154 def start_ipython():
155 """Start a global IPython shell, which we need for IPython-specific syntax.
155 """Start a global IPython shell, which we need for IPython-specific syntax.
156 """
156 """
157
157
158 # This function should only ever run once!
158 # This function should only ever run once!
159 if hasattr(start_ipython,'already_called'):
159 if hasattr(start_ipython,'already_called'):
160 return
160 return
161 start_ipython.already_called = True
161 start_ipython.already_called = True
162
162
163 # Ok, first time we're called, go ahead
163 # Ok, first time we're called, go ahead
164 import new
164 import new
165
165
166 import IPython
166 import IPython
167
167
168 def xsys(cmd):
168 def xsys(cmd):
169 """Execute a command and print its output.
169 """Execute a command and print its output.
170
170
171 This is just a convenience function to replace the IPython system call
171 This is just a convenience function to replace the IPython system call
172 with one that is more doctest-friendly.
172 with one that is more doctest-friendly.
173 """
173 """
174 cmd = _ip.IP.var_expand(cmd,depth=1)
174 cmd = _ip.IP.var_expand(cmd,depth=1)
175 sys.stdout.write(commands.getoutput(cmd))
175 sys.stdout.write(commands.getoutput(cmd))
176 sys.stdout.flush()
176 sys.stdout.flush()
177
177
178 # Store certain global objects that IPython modifies
178 # Store certain global objects that IPython modifies
179 _displayhook = sys.displayhook
179 _displayhook = sys.displayhook
180 _excepthook = sys.excepthook
180 _excepthook = sys.excepthook
181 _main = sys.modules.get('__main__')
181 _main = sys.modules.get('__main__')
182
182
183 argv = default_argv()
183 argv = default_argv()
184
184
185 # Start IPython instance. We customize it to start with minimal frills.
185 # Start IPython instance. We customize it to start with minimal frills.
186 user_ns,global_ns = IPython.ipapi.make_user_namespaces(ipnsdict(),dict())
186 user_ns,global_ns = IPython.ipapi.make_user_namespaces(ipnsdict(),dict())
187 IPython.Shell.IPShell(argv,user_ns,global_ns)
187 IPython.Shell.IPShell(argv,user_ns,global_ns)
188
188
189 # Deactivate the various python system hooks added by ipython for
189 # Deactivate the various python system hooks added by ipython for
190 # interactive convenience so we don't confuse the doctest system
190 # interactive convenience so we don't confuse the doctest system
191 sys.modules['__main__'] = _main
191 sys.modules['__main__'] = _main
192 sys.displayhook = _displayhook
192 sys.displayhook = _displayhook
193 sys.excepthook = _excepthook
193 sys.excepthook = _excepthook
194
194
195 # So that ipython magics and aliases can be doctested (they work by making
195 # So that ipython magics and aliases can be doctested (they work by making
196 # a call into a global _ip object)
196 # a call into a global _ip object)
197 _ip = IPython.ipapi.get()
197 _ip = IPython.ipapi.get()
198 __builtin__._ip = _ip
198 __builtin__._ip = _ip
199
199
200 # Modify the IPython system call with one that uses getoutput, so that we
200 # Modify the IPython system call with one that uses getoutput, so that we
201 # can capture subcommands and print them to Python's stdout, otherwise the
201 # can capture subcommands and print them to Python's stdout, otherwise the
202 # doctest machinery would miss them.
202 # doctest machinery would miss them.
203 _ip.system = xsys
203 _ip.system = xsys
204
204
205 # Also patch our %run function in.
205 # Also patch our %run function in.
206 im = new.instancemethod(_run_ns_sync,_ip.IP, _ip.IP.__class__)
206 im = new.instancemethod(_run_ns_sync,_ip.IP, _ip.IP.__class__)
207 _ip.IP.magic_run_ori = _ip.IP.magic_run
207 _ip.IP.magic_run_ori = _ip.IP.magic_run
208 _ip.IP.magic_run = im
208 _ip.IP.magic_run = im
209
209
210 # XXX - For some very bizarre reason, the loading of %history by default is
211 # failing. This needs to be fixed later, but for now at least this ensures
212 # that tests that use %hist run to completion.
213 from IPython import history
214 history.init_ipython(_ip)
215 if not hasattr(_ip.IP,'magic_history'):
216 raise RuntimeError("Can't load magics, aborting")
217
218
210 # The start call MUST be made here. I'm not sure yet why it doesn't work if
219 # The start call MUST be made here. I'm not sure yet why it doesn't work if
211 # it is made later, at plugin initialization time, but in all my tests, that's
220 # it is made later, at plugin initialization time, but in all my tests, that's
212 # the case.
221 # the case.
213 start_ipython()
222 start_ipython()
214
223
215 # *** END HACK ***
224 # *** END HACK ***
216 ###########################################################################
225 ###########################################################################
217
226
218 # Classes and functions
227 # Classes and functions
219
228
220 def is_extension_module(filename):
229 def is_extension_module(filename):
221 """Return whether the given filename is an extension module.
230 """Return whether the given filename is an extension module.
222
231
223 This simply checks that the extension is either .so or .pyd.
232 This simply checks that the extension is either .so or .pyd.
224 """
233 """
225 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
234 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
226
235
227
236
228 class DocTestSkip(object):
237 class DocTestSkip(object):
229 """Object wrapper for doctests to be skipped."""
238 """Object wrapper for doctests to be skipped."""
230
239
231 ds_skip = """Doctest to skip.
240 ds_skip = """Doctest to skip.
232 >>> 1 #doctest: +SKIP
241 >>> 1 #doctest: +SKIP
233 """
242 """
234
243
235 def __init__(self,obj):
244 def __init__(self,obj):
236 self.obj = obj
245 self.obj = obj
237
246
238 def __getattribute__(self,key):
247 def __getattribute__(self,key):
239 if key == '__doc__':
248 if key == '__doc__':
240 return DocTestSkip.ds_skip
249 return DocTestSkip.ds_skip
241 else:
250 else:
242 return getattr(object.__getattribute__(self,'obj'),key)
251 return getattr(object.__getattribute__(self,'obj'),key)
243
252
244 # Modified version of the one in the stdlib, that fixes a python bug (doctests
253 # Modified version of the one in the stdlib, that fixes a python bug (doctests
245 # not found in extension modules, http://bugs.python.org/issue3158)
254 # not found in extension modules, http://bugs.python.org/issue3158)
246 class DocTestFinder(doctest.DocTestFinder):
255 class DocTestFinder(doctest.DocTestFinder):
247
256
248 def _from_module(self, module, object):
257 def _from_module(self, module, object):
249 """
258 """
250 Return true if the given object is defined in the given
259 Return true if the given object is defined in the given
251 module.
260 module.
252 """
261 """
253 if module is None:
262 if module is None:
254 return True
263 return True
255 elif inspect.isfunction(object):
264 elif inspect.isfunction(object):
256 return module.__dict__ is object.func_globals
265 return module.__dict__ is object.func_globals
257 elif inspect.isbuiltin(object):
266 elif inspect.isbuiltin(object):
258 return module.__name__ == object.__module__
267 return module.__name__ == object.__module__
259 elif inspect.isclass(object):
268 elif inspect.isclass(object):
260 return module.__name__ == object.__module__
269 return module.__name__ == object.__module__
261 elif inspect.ismethod(object):
270 elif inspect.ismethod(object):
262 # This one may be a bug in cython that fails to correctly set the
271 # This one may be a bug in cython that fails to correctly set the
263 # __module__ attribute of methods, but since the same error is easy
272 # __module__ attribute of methods, but since the same error is easy
264 # to make by extension code writers, having this safety in place
273 # to make by extension code writers, having this safety in place
265 # isn't such a bad idea
274 # isn't such a bad idea
266 return module.__name__ == object.im_class.__module__
275 return module.__name__ == object.im_class.__module__
267 elif inspect.getmodule(object) is not None:
276 elif inspect.getmodule(object) is not None:
268 return module is inspect.getmodule(object)
277 return module is inspect.getmodule(object)
269 elif hasattr(object, '__module__'):
278 elif hasattr(object, '__module__'):
270 return module.__name__ == object.__module__
279 return module.__name__ == object.__module__
271 elif isinstance(object, property):
280 elif isinstance(object, property):
272 return True # [XX] no way not be sure.
281 return True # [XX] no way not be sure.
273 else:
282 else:
274 raise ValueError("object must be a class or function")
283 raise ValueError("object must be a class or function")
275
284
276 def _find(self, tests, obj, name, module, source_lines, globs, seen):
285 def _find(self, tests, obj, name, module, source_lines, globs, seen):
277 """
286 """
278 Find tests for the given object and any contained objects, and
287 Find tests for the given object and any contained objects, and
279 add them to `tests`.
288 add them to `tests`.
280 """
289 """
281
290
282 if hasattr(obj,"skip_doctest"):
291 if hasattr(obj,"skip_doctest"):
283 #print 'SKIPPING DOCTEST FOR:',obj # dbg
292 #print 'SKIPPING DOCTEST FOR:',obj # dbg
284 obj = DocTestSkip(obj)
293 obj = DocTestSkip(obj)
285
294
286 doctest.DocTestFinder._find(self,tests, obj, name, module,
295 doctest.DocTestFinder._find(self,tests, obj, name, module,
287 source_lines, globs, seen)
296 source_lines, globs, seen)
288
297
289 # Below we re-run pieces of the above method with manual modifications,
298 # Below we re-run pieces of the above method with manual modifications,
290 # because the original code is buggy and fails to correctly identify
299 # because the original code is buggy and fails to correctly identify
291 # doctests in extension modules.
300 # doctests in extension modules.
292
301
293 # Local shorthands
302 # Local shorthands
294 from inspect import isroutine, isclass, ismodule
303 from inspect import isroutine, isclass, ismodule
295
304
296 # Look for tests in a module's contained objects.
305 # Look for tests in a module's contained objects.
297 if inspect.ismodule(obj) and self._recurse:
306 if inspect.ismodule(obj) and self._recurse:
298 for valname, val in obj.__dict__.items():
307 for valname, val in obj.__dict__.items():
299 valname1 = '%s.%s' % (name, valname)
308 valname1 = '%s.%s' % (name, valname)
300 if ( (isroutine(val) or isclass(val))
309 if ( (isroutine(val) or isclass(val))
301 and self._from_module(module, val) ):
310 and self._from_module(module, val) ):
302
311
303 self._find(tests, val, valname1, module, source_lines,
312 self._find(tests, val, valname1, module, source_lines,
304 globs, seen)
313 globs, seen)
305
314
306 # Look for tests in a class's contained objects.
315 # Look for tests in a class's contained objects.
307 if inspect.isclass(obj) and self._recurse:
316 if inspect.isclass(obj) and self._recurse:
308 #print 'RECURSE into class:',obj # dbg
317 #print 'RECURSE into class:',obj # dbg
309 for valname, val in obj.__dict__.items():
318 for valname, val in obj.__dict__.items():
310 # Special handling for staticmethod/classmethod.
319 # Special handling for staticmethod/classmethod.
311 if isinstance(val, staticmethod):
320 if isinstance(val, staticmethod):
312 val = getattr(obj, valname)
321 val = getattr(obj, valname)
313 if isinstance(val, classmethod):
322 if isinstance(val, classmethod):
314 val = getattr(obj, valname).im_func
323 val = getattr(obj, valname).im_func
315
324
316 # Recurse to methods, properties, and nested classes.
325 # Recurse to methods, properties, and nested classes.
317 if ((inspect.isfunction(val) or inspect.isclass(val) or
326 if ((inspect.isfunction(val) or inspect.isclass(val) or
318 inspect.ismethod(val) or
327 inspect.ismethod(val) or
319 isinstance(val, property)) and
328 isinstance(val, property)) and
320 self._from_module(module, val)):
329 self._from_module(module, val)):
321 valname = '%s.%s' % (name, valname)
330 valname = '%s.%s' % (name, valname)
322 self._find(tests, val, valname, module, source_lines,
331 self._find(tests, val, valname, module, source_lines,
323 globs, seen)
332 globs, seen)
324
333
325
334
326 class IPDoctestOutputChecker(doctest.OutputChecker):
335 class IPDoctestOutputChecker(doctest.OutputChecker):
327 """Second-chance checker with support for random tests.
336 """Second-chance checker with support for random tests.
328
337
329 If the default comparison doesn't pass, this checker looks in the expected
338 If the default comparison doesn't pass, this checker looks in the expected
330 output string for flags that tell us to ignore the output.
339 output string for flags that tell us to ignore the output.
331 """
340 """
332
341
333 random_re = re.compile(r'#\s*random\s+')
342 random_re = re.compile(r'#\s*random\s+')
334
343
335 def check_output(self, want, got, optionflags):
344 def check_output(self, want, got, optionflags):
336 """Check output, accepting special markers embedded in the output.
345 """Check output, accepting special markers embedded in the output.
337
346
338 If the output didn't pass the default validation but the special string
347 If the output didn't pass the default validation but the special string
339 '#random' is included, we accept it."""
348 '#random' is included, we accept it."""
340
349
341 # Let the original tester verify first, in case people have valid tests
350 # Let the original tester verify first, in case people have valid tests
342 # that happen to have a comment saying '#random' embedded in.
351 # that happen to have a comment saying '#random' embedded in.
343 ret = doctest.OutputChecker.check_output(self, want, got,
352 ret = doctest.OutputChecker.check_output(self, want, got,
344 optionflags)
353 optionflags)
345 if not ret and self.random_re.search(want):
354 if not ret and self.random_re.search(want):
346 #print >> sys.stderr, 'RANDOM OK:',want # dbg
355 #print >> sys.stderr, 'RANDOM OK:',want # dbg
347 return True
356 return True
348
357
349 return ret
358 return ret
350
359
351
360
352 class DocTestCase(doctests.DocTestCase):
361 class DocTestCase(doctests.DocTestCase):
353 """Proxy for DocTestCase: provides an address() method that
362 """Proxy for DocTestCase: provides an address() method that
354 returns the correct address for the doctest case. Otherwise
363 returns the correct address for the doctest case. Otherwise
355 acts as a proxy to the test case. To provide hints for address(),
364 acts as a proxy to the test case. To provide hints for address(),
356 an obj may also be passed -- this will be used as the test object
365 an obj may also be passed -- this will be used as the test object
357 for purposes of determining the test address, if it is provided.
366 for purposes of determining the test address, if it is provided.
358 """
367 """
359
368
360 # Note: this method was taken from numpy's nosetester module.
369 # Note: this method was taken from numpy's nosetester module.
361
370
362 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
371 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
363 # its constructor that blocks non-default arguments from being passed
372 # its constructor that blocks non-default arguments from being passed
364 # down into doctest.DocTestCase
373 # down into doctest.DocTestCase
365
374
366 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
375 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
367 checker=None, obj=None, result_var='_'):
376 checker=None, obj=None, result_var='_'):
368 self._result_var = result_var
377 self._result_var = result_var
369 doctests.DocTestCase.__init__(self, test,
378 doctests.DocTestCase.__init__(self, test,
370 optionflags=optionflags,
379 optionflags=optionflags,
371 setUp=setUp, tearDown=tearDown,
380 setUp=setUp, tearDown=tearDown,
372 checker=checker)
381 checker=checker)
373 # Now we must actually copy the original constructor from the stdlib
382 # Now we must actually copy the original constructor from the stdlib
374 # doctest class, because we can't call it directly and a bug in nose
383 # doctest class, because we can't call it directly and a bug in nose
375 # means it never gets passed the right arguments.
384 # means it never gets passed the right arguments.
376
385
377 self._dt_optionflags = optionflags
386 self._dt_optionflags = optionflags
378 self._dt_checker = checker
387 self._dt_checker = checker
379 self._dt_test = test
388 self._dt_test = test
380 self._dt_setUp = setUp
389 self._dt_setUp = setUp
381 self._dt_tearDown = tearDown
390 self._dt_tearDown = tearDown
382
391
383 # XXX - store this runner once in the object!
392 # XXX - store this runner once in the object!
384 runner = IPDocTestRunner(optionflags=optionflags,
393 runner = IPDocTestRunner(optionflags=optionflags,
385 checker=checker, verbose=False)
394 checker=checker, verbose=False)
386 self._dt_runner = runner
395 self._dt_runner = runner
387
396
388
397
389 # Each doctest should remember what directory it was loaded from...
398 # Each doctest should remember what directory it was loaded from...
390 self._ori_dir = os.getcwd()
399 self._ori_dir = os.getcwd()
391
400
392 # Modified runTest from the default stdlib
401 # Modified runTest from the default stdlib
393 def runTest(self):
402 def runTest(self):
394 test = self._dt_test
403 test = self._dt_test
395 runner = self._dt_runner
404 runner = self._dt_runner
396
405
397 old = sys.stdout
406 old = sys.stdout
398 new = StringIO()
407 new = StringIO()
399 optionflags = self._dt_optionflags
408 optionflags = self._dt_optionflags
400
409
401 if not (optionflags & REPORTING_FLAGS):
410 if not (optionflags & REPORTING_FLAGS):
402 # The option flags don't include any reporting flags,
411 # The option flags don't include any reporting flags,
403 # so add the default reporting flags
412 # so add the default reporting flags
404 optionflags |= _unittest_reportflags
413 optionflags |= _unittest_reportflags
405
414
406 try:
415 try:
407 # Save our current directory and switch out to the one where the
416 # Save our current directory and switch out to the one where the
408 # test was originally created, in case another doctest did a
417 # test was originally created, in case another doctest did a
409 # directory change. We'll restore this in the finally clause.
418 # directory change. We'll restore this in the finally clause.
410 curdir = os.getcwd()
419 curdir = os.getcwd()
411 os.chdir(self._ori_dir)
420 os.chdir(self._ori_dir)
412
421
413 runner.DIVIDER = "-"*70
422 runner.DIVIDER = "-"*70
414 failures, tries = runner.run(test,out=new.write,
423 failures, tries = runner.run(test,out=new.write,
415 clear_globs=False)
424 clear_globs=False)
416 finally:
425 finally:
417 sys.stdout = old
426 sys.stdout = old
418 os.chdir(curdir)
427 os.chdir(curdir)
419
428
420 if failures:
429 if failures:
421 raise self.failureException(self.format_failure(new.getvalue()))
430 raise self.failureException(self.format_failure(new.getvalue()))
422
431
423 def setUp(self):
432 def setUp(self):
424 """Modified test setup that syncs with ipython namespace"""
433 """Modified test setup that syncs with ipython namespace"""
425
434
426 if isinstance(self._dt_test.examples[0],IPExample):
435 if isinstance(self._dt_test.examples[0],IPExample):
427 # for IPython examples *only*, we swap the globals with the ipython
436 # for IPython examples *only*, we swap the globals with the ipython
428 # namespace, after updating it with the globals (which doctest
437 # namespace, after updating it with the globals (which doctest
429 # fills with the necessary info from the module being tested).
438 # fills with the necessary info from the module being tested).
430 _ip.IP.user_ns.update(self._dt_test.globs)
439 _ip.IP.user_ns.update(self._dt_test.globs)
431 self._dt_test.globs = _ip.IP.user_ns
440 self._dt_test.globs = _ip.IP.user_ns
432
441
433 doctests.DocTestCase.setUp(self)
442 doctests.DocTestCase.setUp(self)
434
443
435
444
436 # A simple subclassing of the original with a different class name, so we can
445 # A simple subclassing of the original with a different class name, so we can
437 # distinguish and treat differently IPython examples from pure python ones.
446 # distinguish and treat differently IPython examples from pure python ones.
438 class IPExample(doctest.Example): pass
447 class IPExample(doctest.Example): pass
439
448
440
449
441 class IPExternalExample(doctest.Example):
450 class IPExternalExample(doctest.Example):
442 """Doctest examples to be run in an external process."""
451 """Doctest examples to be run in an external process."""
443
452
444 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
453 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
445 options=None):
454 options=None):
446 # Parent constructor
455 # Parent constructor
447 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
456 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
448
457
449 # An EXTRA newline is needed to prevent pexpect hangs
458 # An EXTRA newline is needed to prevent pexpect hangs
450 self.source += '\n'
459 self.source += '\n'
451
460
452
461
453 class IPDocTestParser(doctest.DocTestParser):
462 class IPDocTestParser(doctest.DocTestParser):
454 """
463 """
455 A class used to parse strings containing doctest examples.
464 A class used to parse strings containing doctest examples.
456
465
457 Note: This is a version modified to properly recognize IPython input and
466 Note: This is a version modified to properly recognize IPython input and
458 convert any IPython examples into valid Python ones.
467 convert any IPython examples into valid Python ones.
459 """
468 """
460 # This regular expression is used to find doctest examples in a
469 # This regular expression is used to find doctest examples in a
461 # string. It defines three groups: `source` is the source code
470 # string. It defines three groups: `source` is the source code
462 # (including leading indentation and prompts); `indent` is the
471 # (including leading indentation and prompts); `indent` is the
463 # indentation of the first (PS1) line of the source code; and
472 # indentation of the first (PS1) line of the source code; and
464 # `want` is the expected output (including leading indentation).
473 # `want` is the expected output (including leading indentation).
465
474
466 # Classic Python prompts or default IPython ones
475 # Classic Python prompts or default IPython ones
467 _PS1_PY = r'>>>'
476 _PS1_PY = r'>>>'
468 _PS2_PY = r'\.\.\.'
477 _PS2_PY = r'\.\.\.'
469
478
470 _PS1_IP = r'In\ \[\d+\]:'
479 _PS1_IP = r'In\ \[\d+\]:'
471 _PS2_IP = r'\ \ \ \.\.\.+:'
480 _PS2_IP = r'\ \ \ \.\.\.+:'
472
481
473 _RE_TPL = r'''
482 _RE_TPL = r'''
474 # Source consists of a PS1 line followed by zero or more PS2 lines.
483 # Source consists of a PS1 line followed by zero or more PS2 lines.
475 (?P<source>
484 (?P<source>
476 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
485 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
477 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
486 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
478 \n? # a newline
487 \n? # a newline
479 # Want consists of any non-blank lines that do not start with PS1.
488 # Want consists of any non-blank lines that do not start with PS1.
480 (?P<want> (?:(?![ ]*$) # Not a blank line
489 (?P<want> (?:(?![ ]*$) # Not a blank line
481 (?![ ]*%s) # Not a line starting with PS1
490 (?![ ]*%s) # Not a line starting with PS1
482 (?![ ]*%s) # Not a line starting with PS2
491 (?![ ]*%s) # Not a line starting with PS2
483 .*$\n? # But any other line
492 .*$\n? # But any other line
484 )*)
493 )*)
485 '''
494 '''
486
495
487 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
496 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
488 re.MULTILINE | re.VERBOSE)
497 re.MULTILINE | re.VERBOSE)
489
498
490 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
499 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
491 re.MULTILINE | re.VERBOSE)
500 re.MULTILINE | re.VERBOSE)
492
501
493 # Mark a test as being fully random. In this case, we simply append the
502 # Mark a test as being fully random. In this case, we simply append the
494 # random marker ('#random') to each individual example's output. This way
503 # random marker ('#random') to each individual example's output. This way
495 # we don't need to modify any other code.
504 # we don't need to modify any other code.
496 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
505 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
497
506
498 # Mark tests to be executed in an external process - currently unsupported.
507 # Mark tests to be executed in an external process - currently unsupported.
499 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
508 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
500
509
501 def ip2py(self,source):
510 def ip2py(self,source):
502 """Convert input IPython source into valid Python."""
511 """Convert input IPython source into valid Python."""
503 out = []
512 out = []
504 newline = out.append
513 newline = out.append
505 #print 'IPSRC:\n',source,'\n###' # dbg
514 #print 'IPSRC:\n',source,'\n###' # dbg
506 # The input source must be first stripped of all bracketing whitespace
515 # The input source must be first stripped of all bracketing whitespace
507 # and turned into lines, so it looks to the parser like regular user
516 # and turned into lines, so it looks to the parser like regular user
508 # input
517 # input
509 for lnum,line in enumerate(source.strip().splitlines()):
518 for lnum,line in enumerate(source.strip().splitlines()):
510 newline(_ip.IP.prefilter(line,lnum>0))
519 newline(_ip.IP.prefilter(line,lnum>0))
511 newline('') # ensure a closing newline, needed by doctest
520 newline('') # ensure a closing newline, needed by doctest
512 #print "PYSRC:", '\n'.join(out) # dbg
521 #print "PYSRC:", '\n'.join(out) # dbg
513 return '\n'.join(out)
522 return '\n'.join(out)
514
523
515 def parse(self, string, name='<string>'):
524 def parse(self, string, name='<string>'):
516 """
525 """
517 Divide the given string into examples and intervening text,
526 Divide the given string into examples and intervening text,
518 and return them as a list of alternating Examples and strings.
527 and return them as a list of alternating Examples and strings.
519 Line numbers for the Examples are 0-based. The optional
528 Line numbers for the Examples are 0-based. The optional
520 argument `name` is a name identifying this string, and is only
529 argument `name` is a name identifying this string, and is only
521 used for error messages.
530 used for error messages.
522 """
531 """
523
532
524 #print 'Parse string:\n',string # dbg
533 #print 'Parse string:\n',string # dbg
525
534
526 string = string.expandtabs()
535 string = string.expandtabs()
527 # If all lines begin with the same indentation, then strip it.
536 # If all lines begin with the same indentation, then strip it.
528 min_indent = self._min_indent(string)
537 min_indent = self._min_indent(string)
529 if min_indent > 0:
538 if min_indent > 0:
530 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
539 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
531
540
532 output = []
541 output = []
533 charno, lineno = 0, 0
542 charno, lineno = 0, 0
534
543
535 # We make 'all random' tests by adding the '# random' mark to every
544 # We make 'all random' tests by adding the '# random' mark to every
536 # block of output in the test.
545 # block of output in the test.
537 if self._RANDOM_TEST.search(string):
546 if self._RANDOM_TEST.search(string):
538 random_marker = '\n# random'
547 random_marker = '\n# random'
539 else:
548 else:
540 random_marker = ''
549 random_marker = ''
541
550
542 # Whether to convert the input from ipython to python syntax
551 # Whether to convert the input from ipython to python syntax
543 ip2py = False
552 ip2py = False
544 # Find all doctest examples in the string. First, try them as Python
553 # Find all doctest examples in the string. First, try them as Python
545 # examples, then as IPython ones
554 # examples, then as IPython ones
546 terms = list(self._EXAMPLE_RE_PY.finditer(string))
555 terms = list(self._EXAMPLE_RE_PY.finditer(string))
547 if terms:
556 if terms:
548 # Normal Python example
557 # Normal Python example
549 #print '-'*70 # dbg
558 #print '-'*70 # dbg
550 #print 'PyExample, Source:\n',string # dbg
559 #print 'PyExample, Source:\n',string # dbg
551 #print '-'*70 # dbg
560 #print '-'*70 # dbg
552 Example = doctest.Example
561 Example = doctest.Example
553 else:
562 else:
554 # It's an ipython example. Note that IPExamples are run
563 # It's an ipython example. Note that IPExamples are run
555 # in-process, so their syntax must be turned into valid python.
564 # in-process, so their syntax must be turned into valid python.
556 # IPExternalExamples are run out-of-process (via pexpect) so they
565 # IPExternalExamples are run out-of-process (via pexpect) so they
557 # don't need any filtering (a real ipython will be executing them).
566 # don't need any filtering (a real ipython will be executing them).
558 terms = list(self._EXAMPLE_RE_IP.finditer(string))
567 terms = list(self._EXAMPLE_RE_IP.finditer(string))
559 if self._EXTERNAL_IP.search(string):
568 if self._EXTERNAL_IP.search(string):
560 #print '-'*70 # dbg
569 #print '-'*70 # dbg
561 #print 'IPExternalExample, Source:\n',string # dbg
570 #print 'IPExternalExample, Source:\n',string # dbg
562 #print '-'*70 # dbg
571 #print '-'*70 # dbg
563 Example = IPExternalExample
572 Example = IPExternalExample
564 else:
573 else:
565 #print '-'*70 # dbg
574 #print '-'*70 # dbg
566 #print 'IPExample, Source:\n',string # dbg
575 #print 'IPExample, Source:\n',string # dbg
567 #print '-'*70 # dbg
576 #print '-'*70 # dbg
568 Example = IPExample
577 Example = IPExample
569 ip2py = True
578 ip2py = True
570
579
571 for m in terms:
580 for m in terms:
572 # Add the pre-example text to `output`.
581 # Add the pre-example text to `output`.
573 output.append(string[charno:m.start()])
582 output.append(string[charno:m.start()])
574 # Update lineno (lines before this example)
583 # Update lineno (lines before this example)
575 lineno += string.count('\n', charno, m.start())
584 lineno += string.count('\n', charno, m.start())
576 # Extract info from the regexp match.
585 # Extract info from the regexp match.
577 (source, options, want, exc_msg) = \
586 (source, options, want, exc_msg) = \
578 self._parse_example(m, name, lineno,ip2py)
587 self._parse_example(m, name, lineno,ip2py)
579
588
580 # Append the random-output marker (it defaults to empty in most
589 # Append the random-output marker (it defaults to empty in most
581 # cases, it's only non-empty for 'all-random' tests):
590 # cases, it's only non-empty for 'all-random' tests):
582 want += random_marker
591 want += random_marker
583
592
584 if Example is IPExternalExample:
593 if Example is IPExternalExample:
585 options[doctest.NORMALIZE_WHITESPACE] = True
594 options[doctest.NORMALIZE_WHITESPACE] = True
586 want += '\n'
595 want += '\n'
587
596
588 # Create an Example, and add it to the list.
597 # Create an Example, and add it to the list.
589 if not self._IS_BLANK_OR_COMMENT(source):
598 if not self._IS_BLANK_OR_COMMENT(source):
590 output.append(Example(source, want, exc_msg,
599 output.append(Example(source, want, exc_msg,
591 lineno=lineno,
600 lineno=lineno,
592 indent=min_indent+len(m.group('indent')),
601 indent=min_indent+len(m.group('indent')),
593 options=options))
602 options=options))
594 # Update lineno (lines inside this example)
603 # Update lineno (lines inside this example)
595 lineno += string.count('\n', m.start(), m.end())
604 lineno += string.count('\n', m.start(), m.end())
596 # Update charno.
605 # Update charno.
597 charno = m.end()
606 charno = m.end()
598 # Add any remaining post-example text to `output`.
607 # Add any remaining post-example text to `output`.
599 output.append(string[charno:])
608 output.append(string[charno:])
600 return output
609 return output
601
610
602 def _parse_example(self, m, name, lineno,ip2py=False):
611 def _parse_example(self, m, name, lineno,ip2py=False):
603 """
612 """
604 Given a regular expression match from `_EXAMPLE_RE` (`m`),
613 Given a regular expression match from `_EXAMPLE_RE` (`m`),
605 return a pair `(source, want)`, where `source` is the matched
614 return a pair `(source, want)`, where `source` is the matched
606 example's source code (with prompts and indentation stripped);
615 example's source code (with prompts and indentation stripped);
607 and `want` is the example's expected output (with indentation
616 and `want` is the example's expected output (with indentation
608 stripped).
617 stripped).
609
618
610 `name` is the string's name, and `lineno` is the line number
619 `name` is the string's name, and `lineno` is the line number
611 where the example starts; both are used for error messages.
620 where the example starts; both are used for error messages.
612
621
613 Optional:
622 Optional:
614 `ip2py`: if true, filter the input via IPython to convert the syntax
623 `ip2py`: if true, filter the input via IPython to convert the syntax
615 into valid python.
624 into valid python.
616 """
625 """
617
626
618 # Get the example's indentation level.
627 # Get the example's indentation level.
619 indent = len(m.group('indent'))
628 indent = len(m.group('indent'))
620
629
621 # Divide source into lines; check that they're properly
630 # Divide source into lines; check that they're properly
622 # indented; and then strip their indentation & prompts.
631 # indented; and then strip their indentation & prompts.
623 source_lines = m.group('source').split('\n')
632 source_lines = m.group('source').split('\n')
624
633
625 # We're using variable-length input prompts
634 # We're using variable-length input prompts
626 ps1 = m.group('ps1')
635 ps1 = m.group('ps1')
627 ps2 = m.group('ps2')
636 ps2 = m.group('ps2')
628 ps1_len = len(ps1)
637 ps1_len = len(ps1)
629
638
630 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
639 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
631 if ps2:
640 if ps2:
632 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
641 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
633
642
634 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
643 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
635
644
636 if ip2py:
645 if ip2py:
637 # Convert source input from IPython into valid Python syntax
646 # Convert source input from IPython into valid Python syntax
638 source = self.ip2py(source)
647 source = self.ip2py(source)
639
648
640 # Divide want into lines; check that it's properly indented; and
649 # Divide want into lines; check that it's properly indented; and
641 # then strip the indentation. Spaces before the last newline should
650 # then strip the indentation. Spaces before the last newline should
642 # be preserved, so plain rstrip() isn't good enough.
651 # be preserved, so plain rstrip() isn't good enough.
643 want = m.group('want')
652 want = m.group('want')
644 want_lines = want.split('\n')
653 want_lines = want.split('\n')
645 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
654 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
646 del want_lines[-1] # forget final newline & spaces after it
655 del want_lines[-1] # forget final newline & spaces after it
647 self._check_prefix(want_lines, ' '*indent, name,
656 self._check_prefix(want_lines, ' '*indent, name,
648 lineno + len(source_lines))
657 lineno + len(source_lines))
649
658
650 # Remove ipython output prompt that might be present in the first line
659 # Remove ipython output prompt that might be present in the first line
651 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
660 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
652
661
653 want = '\n'.join([wl[indent:] for wl in want_lines])
662 want = '\n'.join([wl[indent:] for wl in want_lines])
654
663
655 # If `want` contains a traceback message, then extract it.
664 # If `want` contains a traceback message, then extract it.
656 m = self._EXCEPTION_RE.match(want)
665 m = self._EXCEPTION_RE.match(want)
657 if m:
666 if m:
658 exc_msg = m.group('msg')
667 exc_msg = m.group('msg')
659 else:
668 else:
660 exc_msg = None
669 exc_msg = None
661
670
662 # Extract options from the source.
671 # Extract options from the source.
663 options = self._find_options(source, name, lineno)
672 options = self._find_options(source, name, lineno)
664
673
665 return source, options, want, exc_msg
674 return source, options, want, exc_msg
666
675
667 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
676 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
668 """
677 """
669 Given the lines of a source string (including prompts and
678 Given the lines of a source string (including prompts and
670 leading indentation), check to make sure that every prompt is
679 leading indentation), check to make sure that every prompt is
671 followed by a space character. If any line is not followed by
680 followed by a space character. If any line is not followed by
672 a space character, then raise ValueError.
681 a space character, then raise ValueError.
673
682
674 Note: IPython-modified version which takes the input prompt length as a
683 Note: IPython-modified version which takes the input prompt length as a
675 parameter, so that prompts of variable length can be dealt with.
684 parameter, so that prompts of variable length can be dealt with.
676 """
685 """
677 space_idx = indent+ps1_len
686 space_idx = indent+ps1_len
678 min_len = space_idx+1
687 min_len = space_idx+1
679 for i, line in enumerate(lines):
688 for i, line in enumerate(lines):
680 if len(line) >= min_len and line[space_idx] != ' ':
689 if len(line) >= min_len and line[space_idx] != ' ':
681 raise ValueError('line %r of the docstring for %s '
690 raise ValueError('line %r of the docstring for %s '
682 'lacks blank after %s: %r' %
691 'lacks blank after %s: %r' %
683 (lineno+i+1, name,
692 (lineno+i+1, name,
684 line[indent:space_idx], line))
693 line[indent:space_idx], line))
685
694
686
695
687 SKIP = doctest.register_optionflag('SKIP')
696 SKIP = doctest.register_optionflag('SKIP')
688
697
689
698
690 class IPDocTestRunner(doctest.DocTestRunner,object):
699 class IPDocTestRunner(doctest.DocTestRunner,object):
691 """Test runner that synchronizes the IPython namespace with test globals.
700 """Test runner that synchronizes the IPython namespace with test globals.
692 """
701 """
693
702
694 def run(self, test, compileflags=None, out=None, clear_globs=True):
703 def run(self, test, compileflags=None, out=None, clear_globs=True):
695
704
696 # Hack: ipython needs access to the execution context of the example,
705 # Hack: ipython needs access to the execution context of the example,
697 # so that it can propagate user variables loaded by %run into
706 # so that it can propagate user variables loaded by %run into
698 # test.globs. We put them here into our modified %run as a function
707 # test.globs. We put them here into our modified %run as a function
699 # attribute. Our new %run will then only make the namespace update
708 # attribute. Our new %run will then only make the namespace update
700 # when called (rather than unconconditionally updating test.globs here
709 # when called (rather than unconconditionally updating test.globs here
701 # for all examples, most of which won't be calling %run anyway).
710 # for all examples, most of which won't be calling %run anyway).
702 _run_ns_sync.test_globs = test.globs
711 _run_ns_sync.test_globs = test.globs
703 _run_ns_sync.test_filename = test.filename
712 _run_ns_sync.test_filename = test.filename
704
713
705 return super(IPDocTestRunner,self).run(test,
714 return super(IPDocTestRunner,self).run(test,
706 compileflags,out,clear_globs)
715 compileflags,out,clear_globs)
707
716
708
717
709 class DocFileCase(doctest.DocFileCase):
718 class DocFileCase(doctest.DocFileCase):
710 """Overrides to provide filename
719 """Overrides to provide filename
711 """
720 """
712 def address(self):
721 def address(self):
713 return (self._dt_test.filename, None, None)
722 return (self._dt_test.filename, None, None)
714
723
715
724
716 class ExtensionDoctest(doctests.Doctest):
725 class ExtensionDoctest(doctests.Doctest):
717 """Nose Plugin that supports doctests in extension modules.
726 """Nose Plugin that supports doctests in extension modules.
718 """
727 """
719 name = 'extdoctest' # call nosetests with --with-extdoctest
728 name = 'extdoctest' # call nosetests with --with-extdoctest
720 enabled = True
729 enabled = True
721
730
722 def __init__(self,exclude_patterns=None):
731 def __init__(self,exclude_patterns=None):
723 """Create a new ExtensionDoctest plugin.
732 """Create a new ExtensionDoctest plugin.
724
733
725 Parameters
734 Parameters
726 ----------
735 ----------
727
736
728 exclude_patterns : sequence of strings, optional
737 exclude_patterns : sequence of strings, optional
729 These patterns are compiled as regular expressions, subsequently used
738 These patterns are compiled as regular expressions, subsequently used
730 to exclude any filename which matches them from inclusion in the test
739 to exclude any filename which matches them from inclusion in the test
731 suite (using pattern.search(), NOT pattern.match() ).
740 suite (using pattern.search(), NOT pattern.match() ).
732 """
741 """
733
742
734 if exclude_patterns is None:
743 if exclude_patterns is None:
735 exclude_patterns = []
744 exclude_patterns = []
736 self.exclude_patterns = map(re.compile,exclude_patterns)
745 self.exclude_patterns = map(re.compile,exclude_patterns)
737 doctests.Doctest.__init__(self)
746 doctests.Doctest.__init__(self)
738
747
739 def options(self, parser, env=os.environ):
748 def options(self, parser, env=os.environ):
740 Plugin.options(self, parser, env)
749 Plugin.options(self, parser, env)
741 parser.add_option('--doctest-tests', action='store_true',
750 parser.add_option('--doctest-tests', action='store_true',
742 dest='doctest_tests',
751 dest='doctest_tests',
743 default=env.get('NOSE_DOCTEST_TESTS',True),
752 default=env.get('NOSE_DOCTEST_TESTS',True),
744 help="Also look for doctests in test modules. "
753 help="Also look for doctests in test modules. "
745 "Note that classes, methods and functions should "
754 "Note that classes, methods and functions should "
746 "have either doctests or non-doctest tests, "
755 "have either doctests or non-doctest tests, "
747 "not both. [NOSE_DOCTEST_TESTS]")
756 "not both. [NOSE_DOCTEST_TESTS]")
748 parser.add_option('--doctest-extension', action="append",
757 parser.add_option('--doctest-extension', action="append",
749 dest="doctestExtension",
758 dest="doctestExtension",
750 help="Also look for doctests in files with "
759 help="Also look for doctests in files with "
751 "this extension [NOSE_DOCTEST_EXTENSION]")
760 "this extension [NOSE_DOCTEST_EXTENSION]")
752 # Set the default as a list, if given in env; otherwise
761 # Set the default as a list, if given in env; otherwise
753 # an additional value set on the command line will cause
762 # an additional value set on the command line will cause
754 # an error.
763 # an error.
755 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
764 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
756 if env_setting is not None:
765 if env_setting is not None:
757 parser.set_defaults(doctestExtension=tolist(env_setting))
766 parser.set_defaults(doctestExtension=tolist(env_setting))
758
767
759
768
760 def configure(self, options, config):
769 def configure(self, options, config):
761 Plugin.configure(self, options, config)
770 Plugin.configure(self, options, config)
762 self.doctest_tests = options.doctest_tests
771 self.doctest_tests = options.doctest_tests
763 self.extension = tolist(options.doctestExtension)
772 self.extension = tolist(options.doctestExtension)
764
773
765 self.parser = doctest.DocTestParser()
774 self.parser = doctest.DocTestParser()
766 self.finder = DocTestFinder()
775 self.finder = DocTestFinder()
767 self.checker = IPDoctestOutputChecker()
776 self.checker = IPDoctestOutputChecker()
768 self.globs = None
777 self.globs = None
769 self.extraglobs = None
778 self.extraglobs = None
770
779
771
780
772 def loadTestsFromExtensionModule(self,filename):
781 def loadTestsFromExtensionModule(self,filename):
773 bpath,mod = os.path.split(filename)
782 bpath,mod = os.path.split(filename)
774 modname = os.path.splitext(mod)[0]
783 modname = os.path.splitext(mod)[0]
775 try:
784 try:
776 sys.path.append(bpath)
785 sys.path.append(bpath)
777 module = __import__(modname)
786 module = __import__(modname)
778 tests = list(self.loadTestsFromModule(module))
787 tests = list(self.loadTestsFromModule(module))
779 finally:
788 finally:
780 sys.path.pop()
789 sys.path.pop()
781 return tests
790 return tests
782
791
783 # NOTE: the method below is almost a copy of the original one in nose, with
792 # NOTE: the method below is almost a copy of the original one in nose, with
784 # a few modifications to control output checking.
793 # a few modifications to control output checking.
785
794
786 def loadTestsFromModule(self, module):
795 def loadTestsFromModule(self, module):
787 #print '*** ipdoctest - lTM',module # dbg
796 #print '*** ipdoctest - lTM',module # dbg
788
797
789 if not self.matches(module.__name__):
798 if not self.matches(module.__name__):
790 log.debug("Doctest doesn't want module %s", module)
799 log.debug("Doctest doesn't want module %s", module)
791 return
800 return
792
801
793 tests = self.finder.find(module,globs=self.globs,
802 tests = self.finder.find(module,globs=self.globs,
794 extraglobs=self.extraglobs)
803 extraglobs=self.extraglobs)
795 if not tests:
804 if not tests:
796 return
805 return
797
806
798 # always use whitespace and ellipsis options
807 # always use whitespace and ellipsis options
799 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
808 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
800
809
801 tests.sort()
810 tests.sort()
802 module_file = module.__file__
811 module_file = module.__file__
803 if module_file[-4:] in ('.pyc', '.pyo'):
812 if module_file[-4:] in ('.pyc', '.pyo'):
804 module_file = module_file[:-1]
813 module_file = module_file[:-1]
805 for test in tests:
814 for test in tests:
806 if not test.examples:
815 if not test.examples:
807 continue
816 continue
808 if not test.filename:
817 if not test.filename:
809 test.filename = module_file
818 test.filename = module_file
810
819
811 yield DocTestCase(test,
820 yield DocTestCase(test,
812 optionflags=optionflags,
821 optionflags=optionflags,
813 checker=self.checker)
822 checker=self.checker)
814
823
815
824
816 def loadTestsFromFile(self, filename):
825 def loadTestsFromFile(self, filename):
817 if is_extension_module(filename):
826 if is_extension_module(filename):
818 for t in self.loadTestsFromExtensionModule(filename):
827 for t in self.loadTestsFromExtensionModule(filename):
819 yield t
828 yield t
820 else:
829 else:
821 if self.extension and anyp(filename.endswith, self.extension):
830 if self.extension and anyp(filename.endswith, self.extension):
822 name = os.path.basename(filename)
831 name = os.path.basename(filename)
823 dh = open(filename)
832 dh = open(filename)
824 try:
833 try:
825 doc = dh.read()
834 doc = dh.read()
826 finally:
835 finally:
827 dh.close()
836 dh.close()
828 test = self.parser.get_doctest(
837 test = self.parser.get_doctest(
829 doc, globs={'__file__': filename}, name=name,
838 doc, globs={'__file__': filename}, name=name,
830 filename=filename, lineno=0)
839 filename=filename, lineno=0)
831 if test.examples:
840 if test.examples:
832 #print 'FileCase:',test.examples # dbg
841 #print 'FileCase:',test.examples # dbg
833 yield DocFileCase(test)
842 yield DocFileCase(test)
834 else:
843 else:
835 yield False # no tests to load
844 yield False # no tests to load
836
845
837 def wantFile(self,filename):
846 def wantFile(self,filename):
838 """Return whether the given filename should be scanned for tests.
847 """Return whether the given filename should be scanned for tests.
839
848
840 Modified version that accepts extension modules as valid containers for
849 Modified version that accepts extension modules as valid containers for
841 doctests.
850 doctests.
842 """
851 """
843 # print '*** ipdoctest- wantFile:',filename # dbg
852 # print '*** ipdoctest- wantFile:',filename # dbg
844
853
845 for pat in self.exclude_patterns:
854 for pat in self.exclude_patterns:
846 if pat.search(filename):
855 if pat.search(filename):
847 # print '###>>> SKIP:',filename # dbg
856 # print '###>>> SKIP:',filename # dbg
848 return False
857 return False
849
858
850 if is_extension_module(filename):
859 if is_extension_module(filename):
851 return True
860 return True
852 else:
861 else:
853 return doctests.Doctest.wantFile(self,filename)
862 return doctests.Doctest.wantFile(self,filename)
854
863
855
864
856 class IPythonDoctest(ExtensionDoctest):
865 class IPythonDoctest(ExtensionDoctest):
857 """Nose Plugin that supports doctests in extension modules.
866 """Nose Plugin that supports doctests in extension modules.
858 """
867 """
859 name = 'ipdoctest' # call nosetests with --with-ipdoctest
868 name = 'ipdoctest' # call nosetests with --with-ipdoctest
860 enabled = True
869 enabled = True
861
870
862 def makeTest(self, obj, parent):
871 def makeTest(self, obj, parent):
863 """Look for doctests in the given object, which will be a
872 """Look for doctests in the given object, which will be a
864 function, method or class.
873 function, method or class.
865 """
874 """
866 # always use whitespace and ellipsis options
875 # always use whitespace and ellipsis options
867 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
876 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
868
877
869 doctests = self.finder.find(obj, module=getmodule(parent))
878 doctests = self.finder.find(obj, module=getmodule(parent))
870 if doctests:
879 if doctests:
871 for test in doctests:
880 for test in doctests:
872 if len(test.examples) == 0:
881 if len(test.examples) == 0:
873 continue
882 continue
874
883
875 yield DocTestCase(test, obj=obj,
884 yield DocTestCase(test, obj=obj,
876 optionflags=optionflags,
885 optionflags=optionflags,
877 checker=self.checker)
886 checker=self.checker)
878
887
879 def options(self, parser, env=os.environ):
888 def options(self, parser, env=os.environ):
880 Plugin.options(self, parser, env)
889 Plugin.options(self, parser, env)
881 parser.add_option('--ipdoctest-tests', action='store_true',
890 parser.add_option('--ipdoctest-tests', action='store_true',
882 dest='ipdoctest_tests',
891 dest='ipdoctest_tests',
883 default=env.get('NOSE_IPDOCTEST_TESTS',True),
892 default=env.get('NOSE_IPDOCTEST_TESTS',True),
884 help="Also look for doctests in test modules. "
893 help="Also look for doctests in test modules. "
885 "Note that classes, methods and functions should "
894 "Note that classes, methods and functions should "
886 "have either doctests or non-doctest tests, "
895 "have either doctests or non-doctest tests, "
887 "not both. [NOSE_IPDOCTEST_TESTS]")
896 "not both. [NOSE_IPDOCTEST_TESTS]")
888 parser.add_option('--ipdoctest-extension', action="append",
897 parser.add_option('--ipdoctest-extension', action="append",
889 dest="ipdoctest_extension",
898 dest="ipdoctest_extension",
890 help="Also look for doctests in files with "
899 help="Also look for doctests in files with "
891 "this extension [NOSE_IPDOCTEST_EXTENSION]")
900 "this extension [NOSE_IPDOCTEST_EXTENSION]")
892 # Set the default as a list, if given in env; otherwise
901 # Set the default as a list, if given in env; otherwise
893 # an additional value set on the command line will cause
902 # an additional value set on the command line will cause
894 # an error.
903 # an error.
895 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
904 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
896 if env_setting is not None:
905 if env_setting is not None:
897 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
906 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
898
907
899 def configure(self, options, config):
908 def configure(self, options, config):
900 Plugin.configure(self, options, config)
909 Plugin.configure(self, options, config)
901 self.doctest_tests = options.ipdoctest_tests
910 self.doctest_tests = options.ipdoctest_tests
902 self.extension = tolist(options.ipdoctest_extension)
911 self.extension = tolist(options.ipdoctest_extension)
903
912
904 self.parser = IPDocTestParser()
913 self.parser = IPDocTestParser()
905 self.finder = DocTestFinder(parser=self.parser)
914 self.finder = DocTestFinder(parser=self.parser)
906 self.checker = IPDoctestOutputChecker()
915 self.checker = IPDoctestOutputChecker()
907 self.globs = None
916 self.globs = None
908 self.extraglobs = None
917 self.extraglobs = None
@@ -1,249 +1,261 b''
1 """Tests for various magic functions.
1 """Tests for various magic functions.
2
2
3 Needs to be run by nose (to make ipython session available).
3 Needs to be run by nose (to make ipython session available).
4 """
4 """
5
5
6 import os
6 import os
7 import sys
7 import sys
8 import tempfile
8 import tempfile
9 import types
9 import types
10
10
11 import nose.tools as nt
11 import nose.tools as nt
12
12
13 from IPython.platutils import find_cmd, get_long_path_name
13 from IPython.platutils import find_cmd, get_long_path_name
14 from IPython.testing import decorators as dec
14 from IPython.testing import decorators as dec
15 from IPython.testing import tools as tt
15 from IPython.testing import tools as tt
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Test functions begin
18 # Test functions begin
19
19
20 def test_rehashx():
20 def test_rehashx():
21 # clear up everything
21 # clear up everything
22 _ip.IP.alias_table.clear()
22 _ip.IP.alias_table.clear()
23 del _ip.db['syscmdlist']
23 del _ip.db['syscmdlist']
24
24
25 _ip.magic('rehashx')
25 _ip.magic('rehashx')
26 # Practically ALL ipython development systems will have more than 10 aliases
26 # Practically ALL ipython development systems will have more than 10 aliases
27
27
28 assert len(_ip.IP.alias_table) > 10
28 yield (nt.assert_true, len(_ip.IP.alias_table) > 10)
29 for key, val in _ip.IP.alias_table.items():
29 for key, val in _ip.IP.alias_table.items():
30 # we must strip dots from alias names
30 # we must strip dots from alias names
31 assert '.' not in key
31 nt.assert_true('.' not in key)
32
32
33 # rehashx must fill up syscmdlist
33 # rehashx must fill up syscmdlist
34 scoms = _ip.db['syscmdlist']
34 scoms = _ip.db['syscmdlist']
35 assert len(scoms) > 10
35 yield (nt.assert_true, len(scoms) > 10)
36
36
37
37
38 ## def doctest_lsmagic():
39 ## """
40 ## In [15]: %lsmagic
41 ## Available magic functions:
42 ## %Exit
43 ## """
44
38 def doctest_hist_f():
45 def doctest_hist_f():
39 """Test %hist -f with temporary filename.
46 """Test %hist -f with temporary filename.
40
47
41 In [9]: import tempfile
48 In [9]: import tempfile
42
49
43 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
50 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
44
51
45 In [11]: %history -n -f $tfile 3
52 In [11]: %hist -n -f $tfile 3
53
46 """
54 """
47
55
48
56
49 def doctest_hist_r():
57 def doctest_hist_r():
50 """Test %hist -r
58 """Test %hist -r
51
59
52 XXX - This test is not recording the output correctly. Not sure why...
60 XXX - This test is not recording the output correctly. Not sure why...
53
61
62 In [20]: 'hist' in _ip.IP.lsmagic()
63 Out[20]: True
64
54 In [6]: x=1
65 In [6]: x=1
55
66
56 In [7]: hist -n -r 2
67 In [7]: %hist -n -r 2
57 x=1 # random
68 x=1 # random
58 hist -n -r 2 # random
69 hist -n -r 2 # random
59 """
70 """
60
71
61 # This test is known to fail on win32.
72 # This test is known to fail on win32.
62 # See ticket https://bugs.launchpad.net/bugs/366334
73 # See ticket https://bugs.launchpad.net/bugs/366334
63 def test_obj_del():
74 def test_obj_del():
64 """Test that object's __del__ methods are called on exit."""
75 """Test that object's __del__ methods are called on exit."""
65 test_dir = os.path.dirname(__file__)
76 test_dir = os.path.dirname(__file__)
66 del_file = os.path.join(test_dir,'obj_del.py')
77 del_file = os.path.join(test_dir,'obj_del.py')
67 ipython_cmd = find_cmd('ipython')
78 ipython_cmd = find_cmd('ipython')
68 out = _ip.IP.getoutput('%s %s' % (ipython_cmd, del_file))
79 out = _ip.IP.getoutput('%s %s' % (ipython_cmd, del_file))
69 nt.assert_equals(out,'obj_del.py: object A deleted')
80 nt.assert_equals(out,'obj_del.py: object A deleted')
70
81
71
82
72 def test_shist():
83 def test_shist():
73 # Simple tests of ShadowHist class - test generator.
84 # Simple tests of ShadowHist class - test generator.
74 import os, shutil, tempfile
85 import os, shutil, tempfile
75
86
76 from IPython.Extensions import pickleshare
87 from IPython.Extensions import pickleshare
77 from IPython.history import ShadowHist
88 from IPython.history import ShadowHist
78
89
79 tfile = tempfile.mktemp('','tmp-ipython-')
90 tfile = tempfile.mktemp('','tmp-ipython-')
80
91
81 db = pickleshare.PickleShareDB(tfile)
92 db = pickleshare.PickleShareDB(tfile)
82 s = ShadowHist(db)
93 s = ShadowHist(db)
83 s.add('hello')
94 s.add('hello')
84 s.add('world')
95 s.add('world')
85 s.add('hello')
96 s.add('hello')
86 s.add('hello')
97 s.add('hello')
87 s.add('karhu')
98 s.add('karhu')
88
99
89 yield nt.assert_equals,s.all(),[(1, 'hello'), (2, 'world'), (3, 'karhu')]
100 yield nt.assert_equals,s.all(),[(1, 'hello'), (2, 'world'), (3, 'karhu')]
90
101
91 yield nt.assert_equal,s.get(2),'world'
102 yield nt.assert_equal,s.get(2),'world'
92
103
93 shutil.rmtree(tfile)
104 shutil.rmtree(tfile)
94
105
95 @dec.skipif_not_numpy
106 @dec.skipif_not_numpy
96 def test_numpy_clear_array_undec():
107 def test_numpy_clear_array_undec():
108 from IPython.Extensions import clearcmd
109
97 _ip.ex('import numpy as np')
110 _ip.ex('import numpy as np')
98 _ip.ex('a = np.empty(2)')
111 _ip.ex('a = np.empty(2)')
99
112 yield (nt.assert_true, 'a' in _ip.user_ns)
100 yield nt.assert_true,'a' in _ip.user_ns
101 _ip.magic('clear array')
113 _ip.magic('clear array')
102 yield nt.assert_false,'a' in _ip.user_ns
114 yield (nt.assert_false, 'a' in _ip.user_ns)
103
115
104
116
105 @dec.skip()
117 @dec.skip()
106 def test_fail_dec(*a,**k):
118 def test_fail_dec(*a,**k):
107 yield nt.assert_true, False
119 yield nt.assert_true, False
108
120
109 @dec.skip('This one shouldn not run')
121 @dec.skip('This one shouldn not run')
110 def test_fail_dec2(*a,**k):
122 def test_fail_dec2(*a,**k):
111 yield nt.assert_true, False
123 yield nt.assert_true, False
112
124
113 @dec.skipknownfailure
125 @dec.skipknownfailure
114 def test_fail_dec3(*a,**k):
126 def test_fail_dec3(*a,**k):
115 yield nt.assert_true, False
127 yield nt.assert_true, False
116
128
117
129
118 def doctest_refbug():
130 def doctest_refbug():
119 """Very nasty problem with references held by multiple runs of a script.
131 """Very nasty problem with references held by multiple runs of a script.
120 See: https://bugs.launchpad.net/ipython/+bug/269966
132 See: https://bugs.launchpad.net/ipython/+bug/269966
121
133
122 In [1]: _ip.IP.clear_main_mod_cache()
134 In [1]: _ip.IP.clear_main_mod_cache()
123
135
124 In [2]: run refbug
136 In [2]: run refbug
125
137
126 In [3]: call_f()
138 In [3]: call_f()
127 lowercased: hello
139 lowercased: hello
128
140
129 In [4]: run refbug
141 In [4]: run refbug
130
142
131 In [5]: call_f()
143 In [5]: call_f()
132 lowercased: hello
144 lowercased: hello
133 lowercased: hello
145 lowercased: hello
134 """
146 """
135
147
136 #-----------------------------------------------------------------------------
148 #-----------------------------------------------------------------------------
137 # Tests for %run
149 # Tests for %run
138 #-----------------------------------------------------------------------------
150 #-----------------------------------------------------------------------------
139
151
140 # %run is critical enough that it's a good idea to have a solid collection of
152 # %run is critical enough that it's a good idea to have a solid collection of
141 # tests for it, some as doctests and some as normal tests.
153 # tests for it, some as doctests and some as normal tests.
142
154
143 def doctest_run_ns():
155 def doctest_run_ns():
144 """Classes declared %run scripts must be instantiable afterwards.
156 """Classes declared %run scripts must be instantiable afterwards.
145
157
146 In [11]: run tclass foo
158 In [11]: run tclass foo
147
159
148 In [12]: isinstance(f(),foo)
160 In [12]: isinstance(f(),foo)
149 Out[12]: True
161 Out[12]: True
150 """
162 """
151
163
152
164
153 def doctest_run_ns2():
165 def doctest_run_ns2():
154 """Classes declared %run scripts must be instantiable afterwards.
166 """Classes declared %run scripts must be instantiable afterwards.
155
167
156 In [4]: run tclass C-first_pass
168 In [4]: run tclass C-first_pass
157
169
158 In [5]: run tclass C-second_pass
170 In [5]: run tclass C-second_pass
159 tclass.py: deleting object: C-first_pass
171 tclass.py: deleting object: C-first_pass
160 """
172 """
161
173
162 @dec.skip_win32
174 @dec.skip_win32
163 def doctest_run_builtins():
175 def doctest_run_builtins():
164 """Check that %run doesn't damage __builtins__ via a doctest.
176 """Check that %run doesn't damage __builtins__ via a doctest.
165
177
166 This is similar to the test_run_builtins, but I want *both* forms of the
178 This is similar to the test_run_builtins, but I want *both* forms of the
167 test to catch any possible glitches in our testing machinery, since that
179 test to catch any possible glitches in our testing machinery, since that
168 modifies %run somewhat. So for this, we have both a normal test (below)
180 modifies %run somewhat. So for this, we have both a normal test (below)
169 and a doctest (this one).
181 and a doctest (this one).
170
182
171 In [1]: import tempfile
183 In [1]: import tempfile
172
184
173 In [2]: bid1 = id(__builtins__)
185 In [2]: bid1 = id(__builtins__)
174
186
175 In [3]: f = tempfile.NamedTemporaryFile()
187 In [3]: f = tempfile.NamedTemporaryFile()
176
188
177 In [4]: f.write('pass\\n')
189 In [4]: f.write('pass\\n')
178
190
179 In [5]: f.flush()
191 In [5]: f.flush()
180
192
181 In [6]: print 'B1:',type(__builtins__)
193 In [6]: print 'B1:',type(__builtins__)
182 B1: <type 'module'>
194 B1: <type 'module'>
183
195
184 In [7]: %run $f.name
196 In [7]: %run $f.name
185
197
186 In [8]: bid2 = id(__builtins__)
198 In [8]: bid2 = id(__builtins__)
187
199
188 In [9]: print 'B2:',type(__builtins__)
200 In [9]: print 'B2:',type(__builtins__)
189 B2: <type 'module'>
201 B2: <type 'module'>
190
202
191 In [10]: bid1 == bid2
203 In [10]: bid1 == bid2
192 Out[10]: True
204 Out[10]: True
193 """
205 """
194
206
195 # For some tests, it will be handy to organize them in a class with a common
207 # For some tests, it will be handy to organize them in a class with a common
196 # setup that makes a temp file
208 # setup that makes a temp file
197
209
198 class TestMagicRun(object):
210 class TestMagicRun(object):
199
211
200 def setup(self):
212 def setup(self):
201 """Make a valid python temp file."""
213 """Make a valid python temp file."""
202 f = tempfile.NamedTemporaryFile()
214 f = tempfile.NamedTemporaryFile()
203 f.write('pass\n')
215 f.write('pass\n')
204 f.flush()
216 f.flush()
205 self.tmpfile = f
217 self.tmpfile = f
206
218
207 def run_tmpfile(self):
219 def run_tmpfile(self):
208 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
220 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
209 # See below and ticket https://bugs.launchpad.net/bugs/366353
221 # See below and ticket https://bugs.launchpad.net/bugs/366353
210 _ip.magic('run %s' % self.tmpfile.name)
222 _ip.magic('run %s' % self.tmpfile.name)
211
223
212 # See https://bugs.launchpad.net/bugs/366353
224 # See https://bugs.launchpad.net/bugs/366353
213 @dec.skip_if_not_win32
225 @dec.skip_if_not_win32
214 def test_run_tempfile_path(self):
226 def test_run_tempfile_path(self):
215 tt.assert_equals(True,False,"%run doesn't work with tempfile paths on win32.")
227 tt.assert_equals(True,False,"%run doesn't work with tempfile paths on win32.")
216
228
217 # See https://bugs.launchpad.net/bugs/366353
229 # See https://bugs.launchpad.net/bugs/366353
218 @dec.skip_win32
230 @dec.skip_win32
219 def test_builtins_id(self):
231 def test_builtins_id(self):
220 """Check that %run doesn't damage __builtins__ """
232 """Check that %run doesn't damage __builtins__ """
221
233
222 # Test that the id of __builtins__ is not modified by %run
234 # Test that the id of __builtins__ is not modified by %run
223 bid1 = id(_ip.user_ns['__builtins__'])
235 bid1 = id(_ip.user_ns['__builtins__'])
224 self.run_tmpfile()
236 self.run_tmpfile()
225 bid2 = id(_ip.user_ns['__builtins__'])
237 bid2 = id(_ip.user_ns['__builtins__'])
226 tt.assert_equals(bid1, bid2)
238 tt.assert_equals(bid1, bid2)
227
239
228 # See https://bugs.launchpad.net/bugs/366353
240 # See https://bugs.launchpad.net/bugs/366353
229 @dec.skip_win32
241 @dec.skip_win32
230 def test_builtins_type(self):
242 def test_builtins_type(self):
231 """Check that the type of __builtins__ doesn't change with %run.
243 """Check that the type of __builtins__ doesn't change with %run.
232
244
233 However, the above could pass if __builtins__ was already modified to
245 However, the above could pass if __builtins__ was already modified to
234 be a dict (it should be a module) by a previous use of %run. So we
246 be a dict (it should be a module) by a previous use of %run. So we
235 also check explicitly that it really is a module:
247 also check explicitly that it really is a module:
236 """
248 """
237 self.run_tmpfile()
249 self.run_tmpfile()
238 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
250 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
239
251
240 # See https://bugs.launchpad.net/bugs/366353
252 # See https://bugs.launchpad.net/bugs/366353
241 @dec.skip_win32
253 @dec.skip_win32
242 def test_prompts(self):
254 def test_prompts(self):
243 """Test that prompts correctly generate after %run"""
255 """Test that prompts correctly generate after %run"""
244 self.run_tmpfile()
256 self.run_tmpfile()
245 p2 = str(_ip.IP.outputcache.prompt2).strip()
257 p2 = str(_ip.IP.outputcache.prompt2).strip()
246 nt.assert_equals(p2[:3], '...')
258 nt.assert_equals(p2[:3], '...')
247
259
248 def teardown(self):
260 def teardown(self):
249 self.tmpfile.close()
261 self.tmpfile.close()
General Comments 0
You need to be logged in to leave comments. Login now