##// END OF EJS Templates
Merging Fernando's fixes from his trunk-dev and fixing testing things....
Brian Granger -
r1973:5d4c3105 merge
parent child Browse files
Show More
@@ -0,0 +1,94 b''
1 """Tests for the ipdoctest machinery itself.
2
3 Note: in a file named test_X, functions whose only test is their docstring (as
4 a doctest) and which have no test functionality of their own, should be called
5 'doctest_foo' instead of 'test_foo', otherwise they get double-counted (the
6 empty function call is counted as a test, which just inflates tests numbers
7 artificially).
8 """
9
10 def doctest_simple():
11 """ipdoctest must handle simple inputs
12
13 In [1]: 1
14 Out[1]: 1
15
16 In [2]: print 1
17 1
18 """
19
20
21 def doctest_run_builtins():
22 """Check that %run doesn't damage __builtins__ via a doctest.
23
24 This is similar to the test_run_builtins, but I want *both* forms of the
25 test to catch any possible glitches in our testing machinery, since that
26 modifies %run somewhat. So for this, we have both a normal test (below)
27 and a doctest (this one).
28
29 In [1]: import tempfile
30
31 In [3]: f = tempfile.NamedTemporaryFile()
32
33 In [4]: f.write('pass\\n')
34
35 In [5]: f.flush()
36
37 In [7]: %run $f.name
38 """
39
40 def doctest_multiline1():
41 """The ipdoctest machinery must handle multiline examples gracefully.
42
43 In [2]: for i in range(10):
44 ...: print i,
45 ...:
46 0 1 2 3 4 5 6 7 8 9
47 """
48
49
50 def doctest_multiline2():
51 """Multiline examples that define functions and print output.
52
53 In [7]: def f(x):
54 ...: return x+1
55 ...:
56
57 In [8]: f(1)
58 Out[8]: 2
59
60 In [9]: def g(x):
61 ...: print 'x is:',x
62 ...:
63
64 In [10]: g(1)
65 x is: 1
66
67 In [11]: g('hello')
68 x is: hello
69 """
70
71
72 def doctest_multiline3():
73 """Multiline examples with blank lines.
74
75 In [12]: def h(x):
76 ....: if x>1:
77 ....: return x**2
78 ....: # To leave a blank line in the input, you must mark it
79 ....: # with a comment character:
80 ....: #
81 ....: # otherwise the doctest parser gets confused.
82 ....: else:
83 ....: return -1
84 ....:
85
86 In [13]: h(5)
87 Out[13]: 25
88
89 In [14]: h(1)
90 Out[14]: -1
91
92 In [15]: h(0)
93 Out[15]: -1
94 """
@@ -0,0 +1,90 b''
1 """Generic testing tools that do NOT depend on Twisted.
2
3 In particular, this module exposes a set of top-level assert* functions that
4 can be used in place of nose.tools.assert* in method generators (the ones in
5 nose can not, at least as of nose 0.10.4).
6
7 Note: our testing package contains testing.util, which does depend on Twisted
8 and provides utilities for tests that manage Deferreds. All testing support
9 tools that only depend on nose, IPython or the standard library should go here
10 instead.
11
12
13 Authors
14 -------
15 - Fernando Perez <Fernando.Perez@berkeley.edu>
16 """
17
18 #*****************************************************************************
19 # Copyright (C) 2009 The IPython Development Team
20 #
21 # Distributed under the terms of the BSD License. The full license is in
22 # the file COPYING, distributed as part of this software.
23 #*****************************************************************************
24
25 #-----------------------------------------------------------------------------
26 # Required modules and packages
27 #-----------------------------------------------------------------------------
28
29 # Standard Python lib
30 import os
31 import sys
32
33 # Third-party
34 import nose.tools as nt
35
36 # From this project
37 from IPython.tools import utils
38
39 #-----------------------------------------------------------------------------
40 # Globals
41 #-----------------------------------------------------------------------------
42
43 # Make a bunch of nose.tools assert wrappers that can be used in test
44 # generators. This will expose an assert* function for each one in nose.tools.
45
46 _tpl = """
47 def %(name)s(*a,**kw):
48 return nt.%(name)s(*a,**kw)
49 """
50
51 for _x in [a for a in dir(nt) if a.startswith('assert')]:
52 exec _tpl % dict(name=_x)
53
54 #-----------------------------------------------------------------------------
55 # Functions and classes
56 #-----------------------------------------------------------------------------
57
58 def full_path(startPath,files):
59 """Make full paths for all the listed files, based on startPath.
60
61 Only the base part of startPath is kept, since this routine is typically
62 used with a script's __file__ variable as startPath. The base of startPath
63 is then prepended to all the listed files, forming the output list.
64
65 Parameters
66 ----------
67 startPath : string
68 Initial path to use as the base for the results. This path is split
69 using os.path.split() and only its first component is kept.
70
71 files : string or list
72 One or more files.
73
74 Examples
75 --------
76
77 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
78 ['/foo/a.txt', '/foo/b.txt']
79
80 >>> full_path('/foo',['a.txt','b.txt'])
81 ['/a.txt', '/b.txt']
82
83 If a single file is given, the output is still a list:
84 >>> full_path('/foo','a.txt')
85 ['/a.txt']
86 """
87
88 files = utils.list_strings(files)
89 base = os.path.split(startPath)[0]
90 return [ os.path.join(base,f) for f in files ]
@@ -1709,6 +1709,16 b' Currently the magic system has the following functions:\\n"""'
1709 del prog_ns['__name__']
1709 del prog_ns['__name__']
1710 self.shell.user_ns.update(prog_ns)
1710 self.shell.user_ns.update(prog_ns)
1711 finally:
1711 finally:
1712 # It's a bit of a mystery why, but __builtins__ can change from
1713 # being a module to becoming a dict missing some key data after
1714 # %run. As best I can see, this is NOT something IPython is doing
1715 # at all, and similar problems have been reported before:
1716 # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
1717 # Since this seems to be done by the interpreter itself, the best
1718 # we can do is to at least restore __builtins__ for the user on
1719 # exit.
1720 self.shell.user_ns['__builtins__'] = __builtin__
1721
1712 # Ensure key global structures are restored
1722 # Ensure key global structures are restored
1713 sys.argv = save_argv
1723 sys.argv = save_argv
1714 if restore_main:
1724 if restore_main:
@@ -126,9 +126,13 b' prompt_specials_color = {'
126 # Just the prompt counter number, WITHOUT any coloring wrappers, so users
126 # Just the prompt counter number, WITHOUT any coloring wrappers, so users
127 # can get numbers displayed in whatever color they want.
127 # can get numbers displayed in whatever color they want.
128 r'\N': '${self.cache.prompt_count}',
128 r'\N': '${self.cache.prompt_count}',
129
129 # Prompt/history count, with the actual digits replaced by dots. Used
130 # Prompt/history count, with the actual digits replaced by dots. Used
130 # mainly in continuation prompts (prompt_in2)
131 # mainly in continuation prompts (prompt_in2)
132 #r'\D': '${"."*len(str(self.cache.prompt_count))}',
133 # More robust form of the above expression, that uses __builtins__
131 r'\D': '${"."*__builtins__.len(__builtins__.str(self.cache.prompt_count))}',
134 r'\D': '${"."*__builtins__.len(__builtins__.str(self.cache.prompt_count))}',
135
132 # Current working directory
136 # Current working directory
133 r'\w': '${os.getcwd()}',
137 r'\w': '${os.getcwd()}',
134 # Current time
138 # Current time
@@ -15,6 +15,8 b' __docformat__ = "restructuredtext en"'
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 # Tell nose to skip the testing of this module
19 __test__ = {}
18
20
19 class NotificationCenter(object):
21 class NotificationCenter(object):
20 """Synchronous notification center
22 """Synchronous notification center
@@ -34,6 +34,9 b' __docformat__ = "restructuredtext en"'
34 # Imports
34 # Imports
35 #-------------------------------------------------------------------------------
35 #-------------------------------------------------------------------------------
36
36
37 # Tell nose to skip the testing of this module
38 __test__ = {}
39
37 import os, sys, copy
40 import os, sys, copy
38 import cPickle as pickle
41 import cPickle as pickle
39 from new import instancemethod
42 from new import instancemethod
@@ -16,6 +16,9 b' __docformat__ = "restructuredtext en"'
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 # Tell nose to skip the testing of this module
20 __test__ = {}
21
19 import copy, time
22 import copy, time
20 from types import FunctionType
23 from types import FunctionType
21
24
@@ -167,7 +167,8 b' def make_runners():'
167 else:
167 else:
168 top_mod.append('platutils_dummy.py')
168 top_mod.append('platutils_dummy.py')
169
169
170 top_pack = ['config','Extensions','frontend','gui','kernel',
170 # These are tested by nose, so skip IPython.kernel
171 top_pack = ['config','Extensions','frontend','gui',
171 'testing','tests','tools','UserConfig']
172 'testing','tests','tools','UserConfig']
172
173
173 modules = ['IPython.%s' % m[:-3] for m in top_mod ]
174 modules = ['IPython.%s' % m[:-3] for m in top_mod ]
@@ -176,6 +177,7 b' def make_runners():'
176 # Make runners
177 # Make runners
177 runners = dict(zip(top_pack, [IPTester(params=v) for v in packages]))
178 runners = dict(zip(top_pack, [IPTester(params=v) for v in packages]))
178
179
180 # Test IPython.kernel using trial if twisted is installed
179 try:
181 try:
180 import zope.interface
182 import zope.interface
181 import twisted
183 import twisted
@@ -97,9 +97,19 b' def _run_ns_sync(self,arg_s,runner=None):'
97 This is strictly needed for running doctests that call %run.
97 This is strictly needed for running doctests that call %run.
98 """
98 """
99
99
100 finder = py_file_finder(_run_ns_sync.test_filename)
100 # When tests call %run directly (not via doctest) these function attributes
101 # are not set
102 try:
103 fname = _run_ns_sync.test_filename
104 except AttributeError:
105 fname = arg_s
106
107 finder = py_file_finder(fname)
101 out = _ip.IP.magic_run_ori(arg_s,runner,finder)
108 out = _ip.IP.magic_run_ori(arg_s,runner,finder)
102 _run_ns_sync.test_globs.update(_ip.user_ns)
109
110 # Simliarly, there is no test_globs when a test is NOT a doctest
111 if hasattr(_run_ns_sync,'test_globs'):
112 _run_ns_sync.test_globs.update(_ip.user_ns)
103 return out
113 return out
104
114
105
115
@@ -126,10 +136,19 b' class ipnsdict(dict):'
126 def update(self,other):
136 def update(self,other):
127 self._checkpoint()
137 self._checkpoint()
128 dict.update(self,other)
138 dict.update(self,other)
139
129 # If '_' is in the namespace, python won't set it when executing code,
140 # If '_' is in the namespace, python won't set it when executing code,
130 # and we have examples that test it. So we ensure that the namespace
141 # and we have examples that test it. So we ensure that the namespace
131 # is always 'clean' of it before it's used for test code execution.
142 # is always 'clean' of it before it's used for test code execution.
132 self.pop('_',None)
143 self.pop('_',None)
144
145 # The builtins namespace must *always* be the real __builtin__ module,
146 # else weird stuff happens. The main ipython code does have provisions
147 # to ensure this after %run, but since in this class we do some
148 # aggressive low-level cleaning of the execution namespace, we need to
149 # correct for that ourselves, to ensure consitency with the 'real'
150 # ipython.
151 self['__builtins__'] = __builtin__
133
152
134
153
135 def start_ipython():
154 def start_ipython():
@@ -6,12 +6,15 b' Needs to be run by nose (to make ipython session available).'
6 # Standard library imports
6 # Standard library imports
7 import os
7 import os
8 import sys
8 import sys
9 import tempfile
10 import types
9
11
10 # Third-party imports
12 # Third-party imports
11 import nose.tools as nt
13 import nose.tools as nt
12
14
13 # From our own code
15 # From our own code
14 from IPython.testing import decorators as dec
16 from IPython.testing import decorators as dec
17 from IPython.testing import tools as tt
15
18
16 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
17 # Test functions begin
20 # Test functions begin
@@ -34,26 +37,6 b' def test_rehashx():'
34 assert len(scoms) > 10
37 assert len(scoms) > 10
35
38
36
39
37 def doctest_run_ns():
38 """Classes declared %run scripts must be instantiable afterwards.
39
40 In [11]: run tclass foo
41
42 In [12]: isinstance(f(),foo)
43 Out[12]: True
44 """
45
46
47 def doctest_run_ns2():
48 """Classes declared %run scripts must be instantiable afterwards.
49
50 In [4]: run tclass C-first_pass
51
52 In [5]: run tclass C-second_pass
53 tclass.py: deleting object: C-first_pass
54 """
55
56
57 def doctest_hist_f():
40 def doctest_hist_f():
58 """Test %hist -f with temporary filename.
41 """Test %hist -f with temporary filename.
59
42
@@ -149,3 +132,104 b' def doctest_refbug():'
149 lowercased: hello
132 lowercased: hello
150 lowercased: hello
133 lowercased: hello
151 """
134 """
135
136 #-----------------------------------------------------------------------------
137 # Tests for %run
138 #-----------------------------------------------------------------------------
139
140 # %run is critical enough that it's a good idea to have a solid collection of
141 # tests for it, some as doctests and some as normal tests.
142
143 def doctest_run_ns():
144 """Classes declared %run scripts must be instantiable afterwards.
145
146 In [11]: run tclass foo
147
148 In [12]: isinstance(f(),foo)
149 Out[12]: True
150 """
151
152
153 def doctest_run_ns2():
154 """Classes declared %run scripts must be instantiable afterwards.
155
156 In [4]: run tclass C-first_pass
157
158 In [5]: run tclass C-second_pass
159 tclass.py: deleting object: C-first_pass
160 """
161
162 def doctest_run_builtins():
163 """Check that %run doesn't damage __builtins__ via a doctest.
164
165 This is similar to the test_run_builtins, but I want *both* forms of the
166 test to catch any possible glitches in our testing machinery, since that
167 modifies %run somewhat. So for this, we have both a normal test (below)
168 and a doctest (this one).
169
170 In [1]: import tempfile
171
172 In [2]: bid1 = id(__builtins__)
173
174 In [3]: f = tempfile.NamedTemporaryFile()
175
176 In [4]: f.write('pass\\n')
177
178 In [5]: f.flush()
179
180 In [6]: print 'B1:',type(__builtins__)
181 B1: <type 'module'>
182
183 In [7]: %run $f.name
184
185 In [8]: bid2 = id(__builtins__)
186
187 In [9]: print 'B2:',type(__builtins__)
188 B2: <type 'module'>
189
190 In [10]: bid1 == bid2
191 Out[10]: True
192 """
193
194 # For some tests, it will be handy to organize them in a class with a common
195 # setup that makes a temp file
196
197 class TestMagicRun(object):
198
199 def setup(self):
200 """Make a valid python temp file."""
201 f = tempfile.NamedTemporaryFile()
202 f.write('pass\n')
203 f.flush()
204 self.tmpfile = f
205
206 def run_tmpfile(self):
207 _ip.magic('run %s' % self.tmpfile.name)
208
209 def test_builtins_id(self):
210 """Check that %run doesn't damage __builtins__ """
211
212 # Test that the id of __builtins__ is not modified by %run
213 bid1 = id(_ip.user_ns['__builtins__'])
214 self.run_tmpfile()
215 bid2 = id(_ip.user_ns['__builtins__'])
216 tt.assert_equals(bid1, bid2)
217
218 def test_builtins_type(self):
219 """Check that the type of __builtins__ doesn't change with %run.
220
221 However, the above could pass if __builtins__ was already modified to
222 be a dict (it should be a module) by a previous use of %run. So we
223 also check explicitly that it really is a module:
224 """
225 self.run_tmpfile()
226 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
227
228 def test_prompts(self):
229 """Test that prompts correctly generate after %run"""
230 self.run_tmpfile()
231 p2 = str(_ip.IP.outputcache.prompt2).strip()
232 nt.assert_equals(p2[:3], '...')
233
234 def teardown(self):
235 self.tmpfile.close()
General Comments 0
You need to be logged in to leave comments. Login now