Show More
@@ -0,0 +1,185 b'' | |||||
|
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 b' 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 b' 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 b'' | |||||
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 |
|
7 | # We want to ensure that while objects remain available for immediate access, | |
12 |
# |
|
8 | # objects from *previous* runs of the same script get collected, to avoid | |
13 |
# a |
|
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 b' 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 b' 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 b'' | |||||
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 b' 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 b' 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 b" 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 b' 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 b' 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 b' 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 b' def make_exclude():' | |||||
88 | ] |
|
96 | ] | |
89 |
|
97 | |||
90 | if not have_wx: |
|
98 | if not have_wx: | |
91 |
|
|
99 | exclusions.append(pjoin('IPython', 'gui')) | |
92 |
|
|
100 | exclusions.append(pjoin('IPython', 'frontend', 'wx')) | |
93 |
|
|
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 |
|
|
104 | exclusions.append(pjoin('IPython', 'lib', 'inputhookgtk')) | |
97 |
|
105 | |||
98 | if not have_wx_aui: |
|
106 | if not have_wx_aui: | |
99 |
|
|
107 | exclusions.append(pjoin('IPython', 'gui', 'wx', 'wxIPython')) | |
100 |
|
108 | |||
101 | if not have_objc: |
|
109 | if not have_objc: | |
102 |
|
|
110 | exclusions.append(pjoin('IPython', 'frontend', 'cocoa')) | |
103 |
|
111 | |||
104 | if not sys.platform == 'win32': |
|
112 | if not sys.platform == 'win32': | |
105 |
|
|
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 |
|
|
118 | exclusions.append(pjoin('IPython', 'testing', 'plugin', 'test_exampleip')) | |
111 |
|
|
119 | exclusions.append(pjoin('IPython', 'testing', 'plugin', 'dtexample')) | |
112 |
|
120 | |||
113 | if not os.name == 'posix': |
|
121 | if not os.name == 'posix': | |
114 |
|
|
122 | exclusions.append(pjoin('IPython', 'utils', 'platutils_posix')) | |
115 |
|
123 | |||
116 | if not have_pexpect: |
|
124 | if not have_pexpect: | |
117 |
|
|
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 |
|
|
131 | exclusions.append(pjoin('IPython', 'frontend', 'asyncfrontendbase')) | |
124 |
|
|
132 | exclusions.append(pjoin('IPython', 'frontend', 'prefilterfrontend')) | |
125 |
|
|
133 | exclusions.append(pjoin('IPython', 'frontend', 'frontendbase')) | |
126 |
|
|
134 | exclusions.append(pjoin('IPython', 'frontend', 'linefrontendbase')) | |
127 |
|
|
135 | exclusions.append(pjoin('IPython', 'frontend', 'tests', | |
128 | 'test_linefrontend')) |
|
136 | 'test_linefrontend')) | |
129 |
|
|
137 | exclusions.append(pjoin('IPython', 'frontend', 'tests', | |
130 | 'test_frontendbase')) |
|
138 | 'test_frontendbase')) | |
131 |
|
|
139 | exclusions.append(pjoin('IPython', 'frontend', 'tests', | |
132 | 'test_prefilterfrontend')) |
|
140 | 'test_prefilterfrontend')) | |
133 |
|
|
141 | exclusions.append(pjoin('IPython', 'frontend', 'tests', | |
134 | 'test_asyncfrontendbase')), |
|
142 | 'test_asyncfrontendbase')), | |
135 |
|
|
143 | exclusions.append(pjoin('IPython', 'testing', 'parametric')) | |
136 |
|
|
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 |
|
|
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 b' 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 b' 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,16 +278,15 b' 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 |
|
|
287 | ||
278 | # '--ipdoctest-tests','--ipdoctest-extension=txt', |
|
288 | #'-x','-s', # dbg | |
279 |
|
|
289 | ||
280 |
|
||||
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 | |
283 | # right thing and it tries to avoid executables, |
|
292 | # right thing and it tries to avoid executables, | |
@@ -300,17 +309,18 b' 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 b' 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 b' 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 b' 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 b' 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 b' 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 |