##// END OF EJS Templates
Massive amount of work to improve the test suite, restores doctests....
Fernando Perez -
r2414:7fce7ae8
parent child
Show More
@@ -0,0 +1,185
1 """Tests for code execution (%run and related), which is particularly tricky.
2
3 Because of how %run manages namespaces, and the fact that we are trying here to
4 verify subtle object deletion and reference counting issues, the %run tests
5 will be kept in this separate file. This makes it easier to aggregate in one
6 place the tricks needed to handle it; most other magics are much easier to test
7 and we do so in a common test_magic file.
8 """
9 from __future__ import absolute_import
10
11 #-----------------------------------------------------------------------------
12 # Imports
13 #-----------------------------------------------------------------------------
14
15 # stdlib
16 import os
17 import sys
18 import tempfile
19
20 # third-party
21 import nose.tools as nt
22
23 # our own
24 from IPython.utils.platutils import find_cmd
25 from IPython.utils import genutils
26 from IPython.testing import decorators as dec
27 from IPython.testing import tools as tt
28
29 #-----------------------------------------------------------------------------
30 # Test functions begin
31 #-----------------------------------------------------------------------------
32
33 def doctest_refbug():
34 """Very nasty problem with references held by multiple runs of a script.
35 See: https://bugs.launchpad.net/ipython/+bug/269966
36
37 In [1]: _ip.clear_main_mod_cache()
38 # random
39
40 In [2]: %run refbug
41
42 In [3]: call_f()
43 lowercased: hello
44
45 In [4]: %run refbug
46
47 In [5]: call_f()
48 lowercased: hello
49 lowercased: hello
50 """
51
52
53 def doctest_run_builtins():
54 r"""Check that %run doesn't damage __builtins__.
55
56 In [1]: import tempfile
57
58 In [2]: bid1 = id(__builtins__)
59
60 In [3]: fname = tempfile.mkstemp('.py')[1]
61
62 In [3]: f = open(fname,'w')
63
64 In [4]: f.write('pass\n')
65
66 In [5]: f.flush()
67
68 In [6]: t1 = type(__builtins__)
69
70 In [7]: %run "$fname"
71
72 In [7]: f.close()
73
74 In [8]: bid2 = id(__builtins__)
75
76 In [9]: t2 = type(__builtins__)
77
78 In [10]: t1 == t2
79 Out[10]: True
80
81 In [10]: bid1 == bid2
82 Out[10]: True
83
84 In [12]: try:
85 ....: os.unlink(fname)
86 ....: except:
87 ....: pass
88 ....:
89 """
90
91 # For some tests, it will be handy to organize them in a class with a common
92 # setup that makes a temp file
93
94 class TempFileMixin(object):
95 def mktmp(self, src, ext='.py'):
96 """Make a valid python temp file."""
97 fname, f = tt.temp_pyfile(src, ext)
98 self.tmpfile = f
99 self.fname = fname
100
101 def teardown(self):
102 self.tmpfile.close()
103 try:
104 os.unlink(self.fname)
105 except:
106 # On Windows, even though we close the file, we still can't delete
107 # it. I have no clue why
108 pass
109
110
111 class TestMagicRunPass(TempFileMixin):
112
113 def setup(self):
114 """Make a valid python temp file."""
115 self.mktmp('pass\n')
116
117 def run_tmpfile(self):
118 _ip = get_ipython()
119 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
120 # See below and ticket https://bugs.launchpad.net/bugs/366353
121 _ip.magic('run "%s"' % self.fname)
122
123 def test_builtins_id(self):
124 """Check that %run doesn't damage __builtins__ """
125 _ip = get_ipython()
126 # Test that the id of __builtins__ is not modified by %run
127 bid1 = id(_ip.user_ns['__builtins__'])
128 self.run_tmpfile()
129 bid2 = id(_ip.user_ns['__builtins__'])
130 tt.assert_equals(bid1, bid2)
131
132 def test_builtins_type(self):
133 """Check that the type of __builtins__ doesn't change with %run.
134
135 However, the above could pass if __builtins__ was already modified to
136 be a dict (it should be a module) by a previous use of %run. So we
137 also check explicitly that it really is a module:
138 """
139 _ip = get_ipython()
140 self.run_tmpfile()
141 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
142
143 def test_prompts(self):
144 """Test that prompts correctly generate after %run"""
145 self.run_tmpfile()
146 _ip = get_ipython()
147 p2 = str(_ip.outputcache.prompt2).strip()
148 nt.assert_equals(p2[:3], '...')
149
150
151 class TestMagicRunSimple(TempFileMixin):
152
153 def test_simpledef(self):
154 """Test that simple class definitions work."""
155 src = ("class foo: pass\n"
156 "def f(): return foo()")
157 self.mktmp(src)
158 _ip.magic('run "%s"' % self.fname)
159 _ip.runlines('t = isinstance(f(), foo)')
160 nt.assert_true(_ip.user_ns['t'])
161
162 def test_obj_del(self):
163 """Test that object's __del__ methods are called on exit."""
164
165 # This test is known to fail on win32.
166 # See ticket https://bugs.launchpad.net/bugs/366334
167 src = ("class A(object):\n"
168 " def __del__(self):\n"
169 " print 'object A deleted'\n"
170 "a = A()\n")
171 self.mktmp(src)
172 tt.ipexec_validate(self.fname, 'object A deleted')
173
174 def test_tclass(self):
175 mydir = os.path.dirname(__file__)
176 tc = os.path.join(mydir, 'tclass')
177 src = ("%%run '%s' C-first\n"
178 "%%run '%s' C-second\n") % (tc, tc)
179 self.mktmp(src, '.ipy')
180 out = """\
181 ARGV 1-: ['C-first']
182 ARGV 1-: ['C-second']
183 tclass.py: deleting object: C-first
184 """
185 tt.ipexec_validate(self.fname, out)
@@ -3506,6 +3506,7 Defaulting color scheme to 'NoColor'"""
3506 """Reload an IPython extension by its module name."""
3506 """Reload an IPython extension by its module name."""
3507 self.reload_extension(module_str)
3507 self.reload_extension(module_str)
3508
3508
3509 @testdec.skip_doctest
3509 def magic_install_profiles(self, s):
3510 def magic_install_profiles(self, s):
3510 """Install the default IPython profiles into the .ipython dir.
3511 """Install the default IPython profiles into the .ipython dir.
3511
3512
@@ -416,7 +416,7 class PrefilterManager(Component):
416 # print "prefiltered line: %r" % prefiltered
416 # print "prefiltered line: %r" % prefiltered
417 return prefiltered
417 return prefiltered
418
418
419 def prefilter_lines(self, lines, continue_prompt):
419 def prefilter_lines(self, lines, continue_prompt=False):
420 """Prefilter multiple input lines of text.
420 """Prefilter multiple input lines of text.
421
421
422 This is the main entry point for prefiltering multiple lines of
422 This is the main entry point for prefiltering multiple lines of
@@ -1,16 +1,12
1 """Simple script to instantiate a class for testing %run"""
1 """Simple script to be run *twice*, to check reference counting bugs.
2
2
3 import sys
3 See test_run for details."""
4
5 # An external test will check that calls to f() work after %run
6 class foo: pass
7
4
8 def f():
5 import sys
9 return foo()
10
6
11 # We also want to ensure that while objects remain available for immediate
7 # We want to ensure that while objects remain available for immediate access,
12 # access, objects from *previous* runs of the same script get collected, to
8 # objects from *previous* runs of the same script get collected, to avoid
13 # avoid accumulating massive amounts of old references.
9 # accumulating massive amounts of old references.
14 class C(object):
10 class C(object):
15 def __init__(self,name):
11 def __init__(self,name):
16 self.name = name
12 self.name = name
@@ -18,6 +14,7 class C(object):
18 def __del__(self):
14 def __del__(self):
19 print 'tclass.py: deleting object:',self.name
15 print 'tclass.py: deleting object:',self.name
20
16
17
21 try:
18 try:
22 name = sys.argv[1]
19 name = sys.argv[1]
23 except IndexError:
20 except IndexError:
@@ -25,3 +22,8 except IndexError:
25 else:
22 else:
26 if name.startswith('C'):
23 if name.startswith('C'):
27 c = C(name)
24 c = C(name)
25
26 #print >> sys.stderr, "ARGV:", sys.argv # dbg
27 # This print statement is NOT debugging, we're making the check on a completely
28 # separate process so we verify by capturing stdout.
29 print 'ARGV 1-:', sys.argv[1:]
@@ -2,21 +2,31
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 from __future__ import absolute_import
5
6
7 #-----------------------------------------------------------------------------
8 # Imports
9 #-----------------------------------------------------------------------------
10
11 # stdlib
6 import os
12 import os
7 import sys
13 import sys
8 import tempfile
14 import tempfile
9 import types
15 import types
10 from cStringIO import StringIO
16 from cStringIO import StringIO
11
17
18 # third-party
12 import nose.tools as nt
19 import nose.tools as nt
13
20
21 # our own
22 from IPython.utils import genutils
14 from IPython.utils.platutils import find_cmd, get_long_path_name
23 from IPython.utils.platutils import find_cmd, get_long_path_name
15 from IPython.testing import decorators as dec
24 from IPython.testing import decorators as dec
16 from IPython.testing import tools as tt
25 from IPython.testing import tools as tt
17
26
18 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
19 # Test functions begin
28 # Test functions begin
29 #-----------------------------------------------------------------------------
20
30
21 def test_rehashx():
31 def test_rehashx():
22 # clear up everything
32 # clear up everything
@@ -63,17 +73,6 def doctest_hist_r():
63 hist -n -r 2 # random
73 hist -n -r 2 # random
64 """
74 """
65
75
66 # This test is known to fail on win32.
67 # See ticket https://bugs.launchpad.net/bugs/366334
68 def test_obj_del():
69 _ip = get_ipython()
70 """Test that object's __del__ methods are called on exit."""
71 test_dir = os.path.dirname(__file__)
72 del_file = os.path.join(test_dir,'obj_del.py')
73 ipython_cmd = find_cmd('ipython')
74 out = _ip.getoutput('%s %s' % (ipython_cmd, del_file))
75 nt.assert_equals(out,'obj_del.py: object A deleted')
76
77
76
78 def test_shist():
77 def test_shist():
79 # Simple tests of ShadowHist class - test generator.
78 # Simple tests of ShadowHist class - test generator.
@@ -113,161 +112,6 def test_numpy_clear_array_undec():
113 yield (nt.assert_false, 'a' in _ip.user_ns)
112 yield (nt.assert_false, 'a' in _ip.user_ns)
114
113
115
114
116 @dec.skip()
117 def test_fail_dec(*a,**k):
118 yield nt.assert_true, False
119
120 @dec.skip('This one shouldn not run')
121 def test_fail_dec2(*a,**k):
122 yield nt.assert_true, False
123
124 @dec.skipknownfailure
125 def test_fail_dec3(*a,**k):
126 yield nt.assert_true, False
127
128
129 def doctest_refbug():
130 """Very nasty problem with references held by multiple runs of a script.
131 See: https://bugs.launchpad.net/ipython/+bug/269966
132
133 In [1]: _ip.clear_main_mod_cache()
134
135 In [2]: run refbug
136
137 In [3]: call_f()
138 lowercased: hello
139
140 In [4]: run refbug
141
142 In [5]: call_f()
143 lowercased: hello
144 lowercased: hello
145 """
146
147 #-----------------------------------------------------------------------------
148 # Tests for %run
149 #-----------------------------------------------------------------------------
150
151 # %run is critical enough that it's a good idea to have a solid collection of
152 # tests for it, some as doctests and some as normal tests.
153
154 def doctest_run_ns():
155 """Classes declared %run scripts must be instantiable afterwards.
156
157 In [11]: run tclass foo
158
159 In [12]: isinstance(f(),foo)
160 Out[12]: True
161 """
162
163
164 def doctest_run_ns2():
165 """Classes declared %run scripts must be instantiable afterwards.
166
167 In [4]: run tclass C-first_pass
168
169 In [5]: run tclass C-second_pass
170 tclass.py: deleting object: C-first_pass
171 """
172
173 def doctest_run_builtins():
174 """Check that %run doesn't damage __builtins__ via a doctest.
175
176 This is similar to the test_run_builtins, but I want *both* forms of the
177 test to catch any possible glitches in our testing machinery, since that
178 modifies %run somewhat. So for this, we have both a normal test (below)
179 and a doctest (this one).
180
181 In [1]: import tempfile
182
183 In [2]: bid1 = id(__builtins__)
184
185 In [3]: fname = tempfile.mkstemp()[1]
186
187 In [3]: f = open(fname,'w')
188
189 In [4]: f.write('pass\\n')
190
191 In [5]: f.flush()
192
193 In [6]: print type(__builtins__)
194 <type 'module'>
195
196 In [7]: %run "$fname"
197
198 In [7]: f.close()
199
200 In [8]: bid2 = id(__builtins__)
201
202 In [9]: print type(__builtins__)
203 <type 'module'>
204
205 In [10]: bid1 == bid2
206 Out[10]: True
207
208 In [12]: try:
209 ....: os.unlink(fname)
210 ....: except:
211 ....: pass
212 ....:
213 """
214
215 # For some tests, it will be handy to organize them in a class with a common
216 # setup that makes a temp file
217
218 class TestMagicRun(object):
219
220 def setup(self):
221 """Make a valid python temp file."""
222 fname = tempfile.mkstemp('.py')[1]
223 f = open(fname,'w')
224 f.write('pass\n')
225 f.flush()
226 self.tmpfile = f
227 self.fname = fname
228
229 def run_tmpfile(self):
230 _ip = get_ipython()
231 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
232 # See below and ticket https://bugs.launchpad.net/bugs/366353
233 _ip.magic('run "%s"' % self.fname)
234
235 def test_builtins_id(self):
236 """Check that %run doesn't damage __builtins__ """
237 _ip = get_ipython()
238 # Test that the id of __builtins__ is not modified by %run
239 bid1 = id(_ip.user_ns['__builtins__'])
240 self.run_tmpfile()
241 bid2 = id(_ip.user_ns['__builtins__'])
242 tt.assert_equals(bid1, bid2)
243
244 def test_builtins_type(self):
245 """Check that the type of __builtins__ doesn't change with %run.
246
247 However, the above could pass if __builtins__ was already modified to
248 be a dict (it should be a module) by a previous use of %run. So we
249 also check explicitly that it really is a module:
250 """
251 _ip = get_ipython()
252 self.run_tmpfile()
253 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
254
255 def test_prompts(self):
256 """Test that prompts correctly generate after %run"""
257 self.run_tmpfile()
258 _ip = get_ipython()
259 p2 = str(_ip.outputcache.prompt2).strip()
260 nt.assert_equals(p2[:3], '...')
261
262 def teardown(self):
263 self.tmpfile.close()
264 try:
265 os.unlink(self.fname)
266 except:
267 # On Windows, even though we close the file, we still can't delete
268 # it. I have no clue why
269 pass
270
271 # Multiple tests for clipboard pasting
115 # Multiple tests for clipboard pasting
272 @dec.parametric
116 @dec.parametric
273 def test_paste():
117 def test_paste():
@@ -64,6 +64,9 if sys.version[0]=='2':
64 else:
64 else:
65 from _paramtestpy3 import parametric
65 from _paramtestpy3 import parametric
66
66
67 # Expose the unittest-driven decorators
68 from ipunittest import ipdoctest, ipdocstring
69
67 # Grab the numpy-specific decorators which we keep in a file that we
70 # Grab the numpy-specific decorators which we keep in a file that we
68 # occasionally update from upstream: decorators.py is a copy of
71 # occasionally update from upstream: decorators.py is a copy of
69 # numpy.testing.decorators, we expose all of it here.
72 # numpy.testing.decorators, we expose all of it here.
@@ -16,6 +16,8 For now, this script requires that both nose and twisted are installed. This
16 will change in the future.
16 will change in the future.
17 """
17 """
18
18
19 from __future__ import absolute_import
20
19 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
20 # Module imports
22 # Module imports
21 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
@@ -34,6 +36,8 from nose.core import TestProgram
34
36
35 from IPython.utils import genutils
37 from IPython.utils import genutils
36 from IPython.utils.platutils import find_cmd, FindCmdError
38 from IPython.utils.platutils import find_cmd, FindCmdError
39 from . import globalipapp
40 from .plugin.ipdoctest import IPythonDoctest
37
41
38 pjoin = path.join
42 pjoin = path.join
39
43
@@ -76,7 +80,11 def make_exclude():
76 # cause testing problems. We should strive to minimize the number of
80 # cause testing problems. We should strive to minimize the number of
77 # skipped modules, since this means untested code. As the testing
81 # skipped modules, since this means untested code. As the testing
78 # machinery solidifies, this list should eventually become empty.
82 # machinery solidifies, this list should eventually become empty.
79 EXCLUDE = [pjoin('IPython', 'external'),
83
84 # Note that these exclusions only mean that the docstrings are not analyzed
85 # for examples to be run as tests, if there are other test functions in
86 # those modules, they do get run.
87 exclusions = [pjoin('IPython', 'external'),
80 pjoin('IPython', 'frontend', 'process', 'winprocess.py'),
88 pjoin('IPython', 'frontend', 'process', 'winprocess.py'),
81 pjoin('IPython_doctest_plugin'),
89 pjoin('IPython_doctest_plugin'),
82 pjoin('IPython', 'quarantine'),
90 pjoin('IPython', 'quarantine'),
@@ -88,58 +96,58 def make_exclude():
88 ]
96 ]
89
97
90 if not have_wx:
98 if not have_wx:
91 EXCLUDE.append(pjoin('IPython', 'gui'))
99 exclusions.append(pjoin('IPython', 'gui'))
92 EXCLUDE.append(pjoin('IPython', 'frontend', 'wx'))
100 exclusions.append(pjoin('IPython', 'frontend', 'wx'))
93 EXCLUDE.append(pjoin('IPython', 'lib', 'inputhookwx'))
101 exclusions.append(pjoin('IPython', 'lib', 'inputhookwx'))
94
102
95 if not have_gtk or not have_gobject:
103 if not have_gtk or not have_gobject:
96 EXCLUDE.append(pjoin('IPython', 'lib', 'inputhookgtk'))
104 exclusions.append(pjoin('IPython', 'lib', 'inputhookgtk'))
97
105
98 if not have_wx_aui:
106 if not have_wx_aui:
99 EXCLUDE.append(pjoin('IPython', 'gui', 'wx', 'wxIPython'))
107 exclusions.append(pjoin('IPython', 'gui', 'wx', 'wxIPython'))
100
108
101 if not have_objc:
109 if not have_objc:
102 EXCLUDE.append(pjoin('IPython', 'frontend', 'cocoa'))
110 exclusions.append(pjoin('IPython', 'frontend', 'cocoa'))
103
111
104 if not sys.platform == 'win32':
112 if not sys.platform == 'win32':
105 EXCLUDE.append(pjoin('IPython', 'utils', 'platutils_win32'))
113 exclusions.append(pjoin('IPython', 'utils', 'platutils_win32'))
106
114
107 # These have to be skipped on win32 because the use echo, rm, cd, etc.
115 # These have to be skipped on win32 because the use echo, rm, cd, etc.
108 # See ticket https://bugs.launchpad.net/bugs/366982
116 # See ticket https://bugs.launchpad.net/bugs/366982
109 if sys.platform == 'win32':
117 if sys.platform == 'win32':
110 EXCLUDE.append(pjoin('IPython', 'testing', 'plugin', 'test_exampleip'))
118 exclusions.append(pjoin('IPython', 'testing', 'plugin', 'test_exampleip'))
111 EXCLUDE.append(pjoin('IPython', 'testing', 'plugin', 'dtexample'))
119 exclusions.append(pjoin('IPython', 'testing', 'plugin', 'dtexample'))
112
120
113 if not os.name == 'posix':
121 if not os.name == 'posix':
114 EXCLUDE.append(pjoin('IPython', 'utils', 'platutils_posix'))
122 exclusions.append(pjoin('IPython', 'utils', 'platutils_posix'))
115
123
116 if not have_pexpect:
124 if not have_pexpect:
117 EXCLUDE.append(pjoin('IPython', 'scripts', 'irunner'))
125 exclusions.append(pjoin('IPython', 'scripts', 'irunner'))
118
126
119 # This is scary. We still have things in frontend and testing that
127 # This is scary. We still have things in frontend and testing that
120 # are being tested by nose that use twisted. We need to rethink
128 # are being tested by nose that use twisted. We need to rethink
121 # how we are isolating dependencies in testing.
129 # how we are isolating dependencies in testing.
122 if not (have_twisted and have_zi and have_foolscap):
130 if not (have_twisted and have_zi and have_foolscap):
123 EXCLUDE.append(pjoin('IPython', 'frontend', 'asyncfrontendbase'))
131 exclusions.append(pjoin('IPython', 'frontend', 'asyncfrontendbase'))
124 EXCLUDE.append(pjoin('IPython', 'frontend', 'prefilterfrontend'))
132 exclusions.append(pjoin('IPython', 'frontend', 'prefilterfrontend'))
125 EXCLUDE.append(pjoin('IPython', 'frontend', 'frontendbase'))
133 exclusions.append(pjoin('IPython', 'frontend', 'frontendbase'))
126 EXCLUDE.append(pjoin('IPython', 'frontend', 'linefrontendbase'))
134 exclusions.append(pjoin('IPython', 'frontend', 'linefrontendbase'))
127 EXCLUDE.append(pjoin('IPython', 'frontend', 'tests',
135 exclusions.append(pjoin('IPython', 'frontend', 'tests',
128 'test_linefrontend'))
136 'test_linefrontend'))
129 EXCLUDE.append(pjoin('IPython', 'frontend', 'tests',
137 exclusions.append(pjoin('IPython', 'frontend', 'tests',
130 'test_frontendbase'))
138 'test_frontendbase'))
131 EXCLUDE.append(pjoin('IPython', 'frontend', 'tests',
139 exclusions.append(pjoin('IPython', 'frontend', 'tests',
132 'test_prefilterfrontend'))
140 'test_prefilterfrontend'))
133 EXCLUDE.append(pjoin('IPython', 'frontend', 'tests',
141 exclusions.append(pjoin('IPython', 'frontend', 'tests',
134 'test_asyncfrontendbase')),
142 'test_asyncfrontendbase')),
135 EXCLUDE.append(pjoin('IPython', 'testing', 'parametric'))
143 exclusions.append(pjoin('IPython', 'testing', 'parametric'))
136 EXCLUDE.append(pjoin('IPython', 'testing', 'util'))
144 exclusions.append(pjoin('IPython', 'testing', 'util'))
137
145
138 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
146 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
139 if sys.platform == 'win32':
147 if sys.platform == 'win32':
140 EXCLUDE = [s.replace('\\','\\\\') for s in EXCLUDE]
148 exclusions = [s.replace('\\','\\\\') for s in exclusions]
141
149
142 return EXCLUDE
150 return exclusions
143
151
144
152
145 #-----------------------------------------------------------------------------
153 #-----------------------------------------------------------------------------
@@ -163,16 +171,16 class IPTester(object):
163 if runner == 'iptest':
171 if runner == 'iptest':
164 # Find our own 'iptest' script OS-level entry point
172 # Find our own 'iptest' script OS-level entry point
165 try:
173 try:
166 iptest_path = find_cmd('iptest')
174 iptest_path = os.path.abspath(find_cmd('iptest'))
167 except FindCmdError:
175 except FindCmdError:
168 # Script not installed (may be the case for testing situations
176 # Script not installed (may be the case for testing situations
169 # that are running from a source tree only), pull from internal
177 # that are running from a source tree only), pull from internal
170 # path:
178 # path:
171 iptest_path = pjoin(genutils.get_ipython_package_dir(),
179 iptest_path = pjoin(genutils.get_ipython_package_dir(),
172 'scripts','iptest')
180 'scripts','iptest')
173 self.runner = [iptest_path,'-v']
181 self.runner = ['python', iptest_path, '-v']
174 else:
182 else:
175 self.runner = [find_cmd('trial')]
183 self.runner = ['python', os.path.abspath(find_cmd('trial'))]
176 if params is None:
184 if params is None:
177 params = []
185 params = []
178 if isinstance(params,str):
186 if isinstance(params,str):
@@ -238,11 +246,13 def make_runners():
238 nose_packages = ['config', 'core', 'extensions', 'frontend', 'lib',
246 nose_packages = ['config', 'core', 'extensions', 'frontend', 'lib',
239 'scripts', 'testing', 'utils']
247 'scripts', 'testing', 'utils']
240 trial_packages = ['kernel']
248 trial_packages = ['kernel']
241 #trial_packages = [] # dbg
242
249
243 if have_wx:
250 if have_wx:
244 nose_packages.append('gui')
251 nose_packages.append('gui')
245
252
253 #nose_packages = ['core'] # dbg
254 #trial_packages = [] # dbg
255
246 nose_packages = ['IPython.%s' % m for m in nose_packages ]
256 nose_packages = ['IPython.%s' % m for m in nose_packages ]
247 trial_packages = ['IPython.%s' % m for m in trial_packages ]
257 trial_packages = ['IPython.%s' % m for m in trial_packages ]
248
258
@@ -268,15 +278,14 def run_iptest():
268 warnings.filterwarnings('ignore',
278 warnings.filterwarnings('ignore',
269 'This will be removed soon. Use IPython.testing.util instead')
279 'This will be removed soon. Use IPython.testing.util instead')
270
280
271 argv = sys.argv + [
281 argv = sys.argv + [ '--detailed-errors',
272 # Loading ipdoctest causes problems with Twisted.
282 # Loading ipdoctest causes problems with Twisted, but
273 # I am removing this as a temporary fix to get the
283 # our test suite runner now separates things and runs
274 # test suite back into working shape. Our nose
284 # all Twisted tests with trial.
275 # plugin needs to be gone through with a fine
285 '--with-ipdoctest',
276 # toothed comb to find what is causing the problem.
286 '--ipdoctest-tests','--ipdoctest-extension=txt',
277 # '--with-ipdoctest',
287
278 # '--ipdoctest-tests','--ipdoctest-extension=txt',
288 #'-x','-s', # dbg
279 # '--detailed-errors',
280
289
281 # We add --exe because of setuptools' imbecility (it
290 # We add --exe because of setuptools' imbecility (it
282 # blindly does chmod +x on ALL files). Nose does the
291 # blindly does chmod +x on ALL files). Nose does the
@@ -300,17 +309,18 def run_iptest():
300 if not has_tests:
309 if not has_tests:
301 argv.append('IPython')
310 argv.append('IPython')
302
311
303 # Construct list of plugins, omitting the existing doctest plugin, which
312 ## # Construct list of plugins, omitting the existing doctest plugin, which
304 # ours replaces (and extends).
313 ## # ours replaces (and extends).
305 EXCLUDE = make_exclude()
314 plugins = [IPythonDoctest(make_exclude())]
306 plugins = []
307 # plugins = [IPythonDoctest(EXCLUDE)]
308 for p in nose.plugins.builtin.plugins:
315 for p in nose.plugins.builtin.plugins:
309 plug = p()
316 plug = p()
310 if plug.name == 'doctest':
317 if plug.name == 'doctest':
311 continue
318 continue
312 plugins.append(plug)
319 plugins.append(plug)
313
320
321 # We need a global ipython running in this process
322 globalipapp.start_ipython()
323 # Now nose can run
314 TestProgram(argv=argv,plugins=plugins)
324 TestProgram(argv=argv,plugins=plugins)
315
325
316
326
@@ -22,6 +22,8 Authors
22 - Fernando Perez <Fernando.Perez@berkeley.edu>
22 - Fernando Perez <Fernando.Perez@berkeley.edu>
23 """
23 """
24
24
25 from __future__ import absolute_import
26
25 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
26 # Copyright (C) 2009 The IPython Development Team
28 # Copyright (C) 2009 The IPython Development Team
27 #
29 #
@@ -40,14 +42,16 import sys
40 import unittest
42 import unittest
41 from doctest import DocTestFinder, DocTestRunner, TestResults
43 from doctest import DocTestFinder, DocTestRunner, TestResults
42
44
43 # Our own
45 # Our own, a nose monkeypatch
44 import nosepatch
46 from . import nosepatch
45
47
46 # We already have python3-compliant code for parametric tests
48 # We already have python3-compliant code for parametric tests
47 if sys.version[0]=='2':
49 if sys.version[0]=='2':
48 from _paramtestpy2 import ParametricTestCase
50 from ._paramtestpy2 import ParametricTestCase
49 else:
51 else:
50 from _paramtestpy3 import ParametricTestCase
52 from ._paramtestpy3 import ParametricTestCase
53
54 from . import globalipapp
51
55
52 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
53 # Classes and functions
57 # Classes and functions
@@ -68,9 +72,13 class IPython2PythonConverter(object):
68 implementation, but for now it only does prompt convertion."""
72 implementation, but for now it only does prompt convertion."""
69
73
70 def __init__(self):
74 def __init__(self):
71 self.ps1 = re.compile(r'In\ \[\d+\]: ')
75 self.rps1 = re.compile(r'In\ \[\d+\]: ')
72 self.ps2 = re.compile(r'\ \ \ \.\.\.+: ')
76 self.rps2 = re.compile(r'\ \ \ \.\.\.+: ')
73 self.out = re.compile(r'Out\[\d+\]: \s*?\n?')
77 self.rout = re.compile(r'Out\[\d+\]: \s*?\n?')
78 self.pyps1 = '>>> '
79 self.pyps2 = '... '
80 self.rpyps1 = re.compile ('(\s*%s)(.*)$' % self.pyps1)
81 self.rpyps2 = re.compile ('(\s*%s)(.*)$' % self.pyps2)
74
82
75 def __call__(self, ds):
83 def __call__(self, ds):
76 """Convert IPython prompts to python ones in a string."""
84 """Convert IPython prompts to python ones in a string."""
@@ -79,10 +87,34 class IPython2PythonConverter(object):
79 pyout = ''
87 pyout = ''
80
88
81 dnew = ds
89 dnew = ds
82 dnew = self.ps1.sub(pyps1, dnew)
90 dnew = self.rps1.sub(pyps1, dnew)
83 dnew = self.ps2.sub(pyps2, dnew)
91 dnew = self.rps2.sub(pyps2, dnew)
84 dnew = self.out.sub(pyout, dnew)
92 dnew = self.rout.sub(pyout, dnew)
85 return dnew
93 ip = globalipapp.get_ipython()
94
95 # Convert input IPython source into valid Python.
96 out = []
97 newline = out.append
98 for line in dnew.splitlines():
99
100 mps1 = self.rpyps1.match(line)
101 if mps1 is not None:
102 prompt, text = mps1.groups()
103 newline(prompt+ip.prefilter(text, False))
104 continue
105
106 mps2 = self.rpyps2.match(line)
107 if mps2 is not None:
108 prompt, text = mps2.groups()
109 newline(prompt+ip.prefilter(text, True))
110 continue
111
112 newline(line)
113 newline('') # ensure a closing newline, needed by doctest
114 #print "PYSRC:", '\n'.join(out) # dbg
115 return '\n'.join(out)
116
117 #return dnew
86
118
87
119
88 class Doc2UnitTester(object):
120 class Doc2UnitTester(object):
@@ -49,183 +49,14 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
53 log = logging.getLogger(__name__)
54 log = logging.getLogger(__name__)
54
55
55 ###########################################################################
56 # *** HACK ***
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
59 # machinery into a fit. This code should be considered a gross hack, but it
60 # gets the job done.
61
62 def default_argv():
63 """Return a valid default argv for creating testing instances of ipython"""
64
65 # Get the install directory for the user configuration and tell ipython to
66 # use the default profile from there.
67 from IPython.config import default
68 ipcdir = os.path.dirname(default.__file__)