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,8 +97,18 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) | |
|
109 | ||||
|
110 | # Simliarly, there is no test_globs when a test is NOT a doctest | |||
|
111 | if hasattr(_run_ns_sync,'test_globs'): | |||
102 | _run_ns_sync.test_globs.update(_ip.user_ns) |
|
112 | _run_ns_sync.test_globs.update(_ip.user_ns) | |
103 | return out |
|
113 | return out | |
104 |
|
114 | |||
@@ -126,11 +136,20 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) | |
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 | def start_ipython(): |
|
154 | def start_ipython(): | |
136 | """Start a global IPython shell, which we need for IPython-specific syntax. |
|
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 | # 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