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