Show More
@@ -0,0 +1,88 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 | startPath : string | |
|
67 | Initial path to use as the base for the results. This path is split | |
|
68 | using os.path.split() and only its first component is kept. | |
|
69 | ||
|
70 | files : string or list | |
|
71 | One or more files. | |
|
72 | ||
|
73 | :Examples: | |
|
74 | ||
|
75 | >>> full_path('/foo/bar.py',['a.txt','b.txt']) | |
|
76 | ['/foo/a.txt', '/foo/b.txt'] | |
|
77 | ||
|
78 | >>> full_path('/foo',['a.txt','b.txt']) | |
|
79 | ['/a.txt', '/b.txt'] | |
|
80 | ||
|
81 | If a single file is given, the output is still a list: | |
|
82 | >>> full_path('/foo','a.txt') | |
|
83 | ['/a.txt'] | |
|
84 | """ | |
|
85 | ||
|
86 | files = utils.list_strings(files) | |
|
87 | base = os.path.split(startPath)[0] | |
|
88 | 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: |
@@ -123,11 +123,20 b' class ipnsdict(dict):' | |||
|
123 | 123 | def update(self,other): |
|
124 | 124 | self._checkpoint() |
|
125 | 125 | dict.update(self,other) |
|
126 | ||
|
126 | 127 | # If '_' is in the namespace, python won't set it when executing code, |
|
127 | 128 | # and we have examples that test it. So we ensure that the namespace |
|
128 | 129 | # is always 'clean' of it before it's used for test code execution. |
|
129 | 130 | self.pop('_',None) |
|
130 | 131 | |
|
132 | # The builtins namespace must *always* be the real __builtin__ module, | |
|
133 | # else weird stuff happens. The main ipython code does have provisions | |
|
134 | # to ensure this after %run, but since in this class we do some | |
|
135 | # aggressive low-level cleaning of the execution namespace, we need to | |
|
136 | # correct for that ourselves, to ensure consitency with the 'real' | |
|
137 | # ipython. | |
|
138 | self['__builtins__'] = __builtin__ | |
|
139 | ||
|
131 | 140 | |
|
132 | 141 | def start_ipython(): |
|
133 | 142 | """Start a global IPython shell, which we need for IPython-specific syntax. |
@@ -18,6 +18,25 b' def doctest_simple():' | |||
|
18 | 18 | """ |
|
19 | 19 | |
|
20 | 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 | ||
|
21 | 40 | def doctest_multiline1(): |
|
22 | 41 | """The ipdoctest machinery must handle multiline examples gracefully. |
|
23 | 42 |
@@ -6,12 +6,16 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 | |
|
18 | ||
|
15 | 19 | #----------------------------------------------------------------------------- |
|
16 | 20 | # Test functions begin |
|
17 | 21 | |
@@ -33,26 +37,6 b' def test_rehashx():' | |||
|
33 | 37 | assert len(scoms) > 10 |
|
34 | 38 | |
|
35 | 39 | |
|
36 | def doctest_run_ns(): | |
|
37 | """Classes declared %run scripts must be instantiable afterwards. | |
|
38 | ||
|
39 | In [11]: run tclass foo | |
|
40 | ||
|
41 | In [12]: isinstance(f(),foo) | |
|
42 | Out[12]: True | |
|
43 | """ | |
|
44 | ||
|
45 | ||
|
46 | def doctest_run_ns2(): | |
|
47 | """Classes declared %run scripts must be instantiable afterwards. | |
|
48 | ||
|
49 | In [4]: run tclass C-first_pass | |
|
50 | ||
|
51 | In [5]: run tclass C-second_pass | |
|
52 | tclass.py: deleting object: C-first_pass | |
|
53 | """ | |
|
54 | ||
|
55 | ||
|
56 | 40 | def doctest_hist_f(): |
|
57 | 41 | """Test %hist -f with temporary filename. |
|
58 | 42 | |
@@ -63,59 +47,6 b' def doctest_hist_f():' | |||
|
63 | 47 | In [11]: %history -n -f $tfile 3 |
|
64 | 48 | """ |
|
65 | 49 | |
|
66 | def doctest_run_builtins(): | |
|
67 | """Check that %run doesn't damage __builtins__ via a doctest. | |
|
68 | ||
|
69 | This is similar to the test_run_builtins, but I want *both* forms of the | |
|
70 | test to catch any possible glitches in our testing machinery, since that | |
|
71 | modifies %run somewhat. So for this, we have both a normal test (below) | |
|
72 | and a doctest (this one). | |
|
73 | ||
|
74 | In [1]: import tempfile | |
|
75 | ||
|
76 | In [2]: bid1 = id(__builtins__) | |
|
77 | ||
|
78 | In [3]: f = tempfile.NamedTemporaryFile() | |
|
79 | ||
|
80 | In [4]: f.write('pass\\n') | |
|
81 | ||
|
82 | In [5]: f.flush() | |
|
83 | ||
|
84 | In [6]: print 'B1:',type(__builtins__) | |
|
85 | B1: <type 'module'> | |
|
86 | ||
|
87 | In [7]: %run $f.name | |
|
88 | ||
|
89 | In [8]: bid2 = id(__builtins__) | |
|
90 | ||
|
91 | In [9]: print 'B2:',type(__builtins__) | |
|
92 | B2: <type 'module'> | |
|
93 | ||
|
94 | In [10]: bid1 == bid2 | |
|
95 | Out[10]: True | |
|
96 | """ | |
|
97 | ||
|
98 | def test_run_builtins(): | |
|
99 | """Check that %run doesn't damage __builtins__ """ | |
|
100 | import sys | |
|
101 | import tempfile | |
|
102 | import types | |
|
103 | ||
|
104 | # Make an empty file and put 'pass' in it | |
|
105 | f = tempfile.NamedTemporaryFile() | |
|
106 | f.write('pass\n') | |
|
107 | f.flush() | |
|
108 | ||
|
109 | # Our first test is that the id of __builtins__ is not modified by %run | |
|
110 | bid1 = id(__builtins__) | |
|
111 | _ip.magic('run %s' % f.name) | |
|
112 | bid2 = id(__builtins__) | |
|
113 | yield nt.assert_equals,bid1,bid2 | |
|
114 | # However, the above could pass if __builtins__ was already modified to be | |
|
115 | # a dict (it should be a module) by a previous use of %run. So we also | |
|
116 | # check explicitly that it really is a module: | |
|
117 | yield nt.assert_equals,type(__builtins__),type(sys) | |
|
118 | ||
|
119 | 50 | |
|
120 | 51 | def doctest_hist_r(): |
|
121 | 52 | """Test %hist -r |
@@ -201,3 +132,104 b' def doctest_refbug():' | |||
|
201 | 132 | lowercased: hello |
|
202 | 133 | lowercased: hello |
|
203 | 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