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 | 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: |
@@ -123,11 +123,20 b' class ipnsdict(dict):' | |||||
123 | def update(self,other): |
|
123 | def update(self,other): | |
124 | self._checkpoint() |
|
124 | self._checkpoint() | |
125 | dict.update(self,other) |
|
125 | dict.update(self,other) | |
|
126 | ||||
126 | # If '_' is in the namespace, python won't set it when executing code, |
|
127 | # If '_' is in the namespace, python won't set it when executing code, | |
127 | # and we have examples that test it. So we ensure that the namespace |
|
128 | # and we have examples that test it. So we ensure that the namespace | |
128 | # is always 'clean' of it before it's used for test code execution. |
|
129 | # is always 'clean' of it before it's used for test code execution. | |
129 | self.pop('_',None) |
|
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 | def start_ipython(): |
|
141 | def start_ipython(): | |
133 | """Start a global IPython shell, which we need for IPython-specific syntax. |
|
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 | def doctest_multiline1(): |
|
40 | def doctest_multiline1(): | |
22 | """The ipdoctest machinery must handle multiline examples gracefully. |
|
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 | # 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 | |||
|
18 | ||||
15 | #----------------------------------------------------------------------------- |
|
19 | #----------------------------------------------------------------------------- | |
16 | # Test functions begin |
|
20 | # Test functions begin | |
17 |
|
21 | |||
@@ -33,26 +37,6 b' def test_rehashx():' | |||||
33 | assert len(scoms) > 10 |
|
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 | def doctest_hist_f(): |
|
40 | def doctest_hist_f(): | |
57 | """Test %hist -f with temporary filename. |
|
41 | """Test %hist -f with temporary filename. | |
58 |
|
42 | |||
@@ -63,59 +47,6 b' def doctest_hist_f():' | |||||
63 | In [11]: %history -n -f $tfile 3 |
|
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 | def doctest_hist_r(): |
|
51 | def doctest_hist_r(): | |
121 | """Test %hist -r |
|
52 | """Test %hist -r | |
@@ -201,3 +132,104 b' def doctest_refbug():' | |||||
201 | lowercased: hello |
|
132 | lowercased: hello | |
202 | lowercased: hello |
|
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