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 | 1709 | del prog_ns['__name__'] |
|
1710 | 1710 | self.shell.user_ns.update(prog_ns) |
|
1711 | 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 | 1722 | # Ensure key global structures are restored |
|
1713 | 1723 | sys.argv = save_argv |
|
1714 | 1724 | if restore_main: |
@@ -126,9 +126,13 b' prompt_specials_color = {' | |||
|
126 | 126 | # Just the prompt counter number, WITHOUT any coloring wrappers, so users |
|
127 | 127 | # can get numbers displayed in whatever color they want. |
|
128 | 128 | r'\N': '${self.cache.prompt_count}', |
|
129 | ||
|
129 | 130 | # Prompt/history count, with the actual digits replaced by dots. Used |
|
130 | 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 | 134 | r'\D': '${"."*__builtins__.len(__builtins__.str(self.cache.prompt_count))}', |
|
135 | ||
|
132 | 136 | # Current working directory |
|
133 | 137 | r'\w': '${os.getcwd()}', |
|
134 | 138 | # Current time |
@@ -15,6 +15,8 b' __docformat__ = "restructuredtext en"' | |||
|
15 | 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 | 21 | class NotificationCenter(object): |
|
20 | 22 | """Synchronous notification center |
@@ -34,6 +34,9 b' __docformat__ = "restructuredtext en"' | |||
|
34 | 34 | # Imports |
|
35 | 35 | #------------------------------------------------------------------------------- |
|
36 | 36 | |
|
37 | # Tell nose to skip the testing of this module | |
|
38 | __test__ = {} | |
|
39 | ||
|
37 | 40 | import os, sys, copy |
|
38 | 41 | import cPickle as pickle |
|
39 | 42 | from new import instancemethod |
@@ -16,6 +16,9 b' __docformat__ = "restructuredtext en"' | |||
|
16 | 16 | # Imports |
|
17 | 17 | #----------------------------------------------------------------------------- |
|
18 | 18 | |
|
19 | # Tell nose to skip the testing of this module | |
|
20 | __test__ = {} | |
|
21 | ||
|
19 | 22 | import copy, time |
|
20 | 23 | from types import FunctionType |
|
21 | 24 |
@@ -167,7 +167,8 b' def make_runners():' | |||
|
167 | 167 | else: |
|
168 | 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 | 172 | 'testing','tests','tools','UserConfig'] |
|
172 | 173 | |
|
173 | 174 | modules = ['IPython.%s' % m[:-3] for m in top_mod ] |
@@ -176,6 +177,7 b' def make_runners():' | |||
|
176 | 177 | # Make runners |
|
177 | 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 | 181 | try: |
|
180 | 182 | import zope.interface |
|
181 | 183 | import twisted |
@@ -97,8 +97,18 b' def _run_ns_sync(self,arg_s,runner=None):' | |||
|
97 | 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 | 108 | out = _ip.IP.magic_run_ori(arg_s,runner,finder) |
|
109 | ||
|
110 | # Simliarly, there is no test_globs when a test is NOT a doctest | |
|
111 | if hasattr(_run_ns_sync,'test_globs'): | |
|
102 | 112 | _run_ns_sync.test_globs.update(_ip.user_ns) |
|
103 | 113 | return out |
|
104 | 114 | |
@@ -126,11 +136,20 b' class ipnsdict(dict):' | |||
|
126 | 136 | def update(self,other): |
|
127 | 137 | self._checkpoint() |
|
128 | 138 | dict.update(self,other) |
|
139 | ||
|
129 | 140 | # If '_' is in the namespace, python won't set it when executing code, |
|
130 | 141 | # and we have examples that test it. So we ensure that the namespace |
|
131 | 142 | # is always 'clean' of it before it's used for test code execution. |
|
132 | 143 | self.pop('_',None) |
|
133 | 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__ | |
|
152 | ||
|
134 | 153 | |
|
135 | 154 | def start_ipython(): |
|
136 | 155 | """Start a global IPython shell, which we need for IPython-specific syntax. |
@@ -6,12 +6,15 b' Needs to be run by nose (to make ipython session available).' | |||
|
6 | 6 | # Standard library imports |
|
7 | 7 | import os |
|
8 | 8 | import sys |
|
9 | import tempfile | |
|
10 | import types | |
|
9 | 11 | |
|
10 | 12 | # Third-party imports |
|
11 | 13 | import nose.tools as nt |
|
12 | 14 | |
|
13 | 15 | # From our own code |
|
14 | 16 | from IPython.testing import decorators as dec |
|
17 | from IPython.testing import tools as tt | |
|
15 | 18 | |
|
16 | 19 | #----------------------------------------------------------------------------- |
|
17 | 20 | # Test functions begin |
@@ -34,26 +37,6 b' def test_rehashx():' | |||
|
34 | 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 | 40 | def doctest_hist_f(): |
|
58 | 41 | """Test %hist -f with temporary filename. |
|
59 | 42 | |
@@ -149,3 +132,104 b' def doctest_refbug():' | |||
|
149 | 132 | lowercased: hello |
|
150 | 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