##// END OF EJS Templates
Massive amount of work to improve the test suite, restores doctests....
Fernando Perez -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -0,0 +1,185 b''
1 """Tests for code execution (%run and related), which is particularly tricky.
2
3 Because of how %run manages namespaces, and the fact that we are trying here to
4 verify subtle object deletion and reference counting issues, the %run tests
5 will be kept in this separate file. This makes it easier to aggregate in one
6 place the tricks needed to handle it; most other magics are much easier to test
7 and we do so in a common test_magic file.
8 """
9 from __future__ import absolute_import
10
11 #-----------------------------------------------------------------------------
12 # Imports
13 #-----------------------------------------------------------------------------
14
15 # stdlib
16 import os
17 import sys
18 import tempfile
19
20 # third-party
21 import nose.tools as nt
22
23 # our own
24 from IPython.utils.platutils import find_cmd
25 from IPython.utils import genutils
26 from IPython.testing import decorators as dec
27 from IPython.testing import tools as tt
28
29 #-----------------------------------------------------------------------------
30 # Test functions begin
31 #-----------------------------------------------------------------------------
32
33 def doctest_refbug():
34 """Very nasty problem with references held by multiple runs of a script.
35 See: https://bugs.launchpad.net/ipython/+bug/269966
36
37 In [1]: _ip.clear_main_mod_cache()
38 # random
39
40 In [2]: %run refbug
41
42 In [3]: call_f()
43 lowercased: hello
44
45 In [4]: %run refbug
46
47 In [5]: call_f()
48 lowercased: hello
49 lowercased: hello
50 """
51
52
53 def doctest_run_builtins():
54 r"""Check that %run doesn't damage __builtins__.
55
56 In [1]: import tempfile
57
58 In [2]: bid1 = id(__builtins__)
59
60 In [3]: fname = tempfile.mkstemp('.py')[1]
61
62 In [3]: f = open(fname,'w')
63
64 In [4]: f.write('pass\n')
65
66 In [5]: f.flush()
67
68 In [6]: t1 = type(__builtins__)
69
70 In [7]: %run "$fname"
71
72 In [7]: f.close()
73
74 In [8]: bid2 = id(__builtins__)
75
76 In [9]: t2 = type(__builtins__)
77
78 In [10]: t1 == t2
79 Out[10]: True
80
81 In [10]: bid1 == bid2
82 Out[10]: True
83
84 In [12]: try:
85 ....: os.unlink(fname)
86 ....: except:
87 ....: pass
88 ....:
89 """
90
91 # For some tests, it will be handy to organize them in a class with a common
92 # setup that makes a temp file
93
94 class TempFileMixin(object):
95 def mktmp(self, src, ext='.py'):
96 """Make a valid python temp file."""
97 fname, f = tt.temp_pyfile(src, ext)
98 self.tmpfile = f
99 self.fname = fname
100
101 def teardown(self):
102 self.tmpfile.close()
103 try:
104 os.unlink(self.fname)
105 except:
106 # On Windows, even though we close the file, we still can't delete
107 # it. I have no clue why
108 pass
109
110
111 class TestMagicRunPass(TempFileMixin):
112
113 def setup(self):
114 """Make a valid python temp file."""
115 self.mktmp('pass\n')
116
117 def run_tmpfile(self):
118 _ip = get_ipython()
119 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
120 # See below and ticket https://bugs.launchpad.net/bugs/366353
121 _ip.magic('run "%s"' % self.fname)
122
123 def test_builtins_id(self):
124 """Check that %run doesn't damage __builtins__ """
125 _ip = get_ipython()
126 # Test that the id of __builtins__ is not modified by %run
127 bid1 = id(_ip.user_ns['__builtins__'])
128 self.run_tmpfile()
129 bid2 = id(_ip.user_ns['__builtins__'])
130 tt.assert_equals(bid1, bid2)
131
132 def test_builtins_type(self):
133 """Check that the type of __builtins__ doesn't change with %run.
134
135 However, the above could pass if __builtins__ was already modified to
136 be a dict (it should be a module) by a previous use of %run. So we
137 also check explicitly that it really is a module:
138 """
139 _ip = get_ipython()
140 self.run_tmpfile()
141 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
142
143 def test_prompts(self):
144 """Test that prompts correctly generate after %run"""
145 self.run_tmpfile()
146 _ip = get_ipython()
147 p2 = str(_ip.outputcache.prompt2).strip()
148 nt.assert_equals(p2[:3], '...')
149
150
151 class TestMagicRunSimple(TempFileMixin):
152
153 def test_simpledef(self):
154 """Test that simple class definitions work."""
155 src = ("class foo: pass\n"
156 "def f(): return foo()")
157 self.mktmp(src)
158 _ip.magic('run "%s"' % self.fname)
159 _ip.runlines('t = isinstance(f(), foo)')
160 nt.assert_true(_ip.user_ns['t'])
161
162 def test_obj_del(self):
163 """Test that object's __del__ methods are called on exit."""
164
165 # This test is known to fail on win32.
166 # See ticket https://bugs.launchpad.net/bugs/366334
167 src = ("class A(object):\n"
168 " def __del__(self):\n"
169 " print 'object A deleted'\n"
170 "a = A()\n")
171 self.mktmp(src)
172 tt.ipexec_validate(self.fname, 'object A deleted')
173
174 def test_tclass(self):
175 mydir = os.path.dirname(__file__)
176 tc = os.path.join(mydir, 'tclass')
177 src = ("%%run '%s' C-first\n"
178 "%%run '%s' C-second\n") % (tc, tc)
179 self.mktmp(src, '.ipy')
180 out = """\
181 ARGV 1-: ['C-first']
182 ARGV 1-: ['C-second']
183 tclass.py: deleting object: C-first
184 """
185 tt.ipexec_validate(self.fname, out)
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,994 +1,994 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Prefiltering components.
4 Prefiltering components.
5
5
6 Prefilters transform user input before it is exec'd by Python. These
6 Prefilters transform user input before it is exec'd by Python. These
7 transforms are used to implement additional syntax such as !ls and %magic.
7 transforms are used to implement additional syntax such as !ls and %magic.
8
8
9 Authors:
9 Authors:
10
10
11 * Brian Granger
11 * Brian Granger
12 * Fernando Perez
12 * Fernando Perez
13 * Dan Milstein
13 * Dan Milstein
14 * Ville Vainio
14 * Ville Vainio
15 """
15 """
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Copyright (C) 2008-2009 The IPython Development Team
18 # Copyright (C) 2008-2009 The IPython Development Team
19 #
19 #
20 # Distributed under the terms of the BSD License. The full license is in
20 # Distributed under the terms of the BSD License. The full license is in
21 # the file COPYING, distributed as part of this software.
21 # the file COPYING, distributed as part of this software.
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Imports
25 # Imports
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 import __builtin__
28 import __builtin__
29 import codeop
29 import codeop
30 import keyword
30 import keyword
31 import os
31 import os
32 import re
32 import re
33 import sys
33 import sys
34
34
35 from IPython.core.alias import AliasManager
35 from IPython.core.alias import AliasManager
36 from IPython.core.autocall import IPyAutocall
36 from IPython.core.autocall import IPyAutocall
37 from IPython.core.component import Component
37 from IPython.core.component import Component
38 from IPython.core.splitinput import split_user_input
38 from IPython.core.splitinput import split_user_input
39 from IPython.core.page import page
39 from IPython.core.page import page
40
40
41 from IPython.utils.traitlets import List, Int, Any, Str, CBool, Bool
41 from IPython.utils.traitlets import List, Int, Any, Str, CBool, Bool
42 from IPython.utils.genutils import make_quoted_expr, Term
42 from IPython.utils.genutils import make_quoted_expr, Term
43 from IPython.utils.autoattr import auto_attr
43 from IPython.utils.autoattr import auto_attr
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Global utilities, errors and constants
46 # Global utilities, errors and constants
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 # Warning, these cannot be changed unless various regular expressions
49 # Warning, these cannot be changed unless various regular expressions
50 # are updated in a number of places. Not great, but at least we told you.
50 # are updated in a number of places. Not great, but at least we told you.
51 ESC_SHELL = '!'
51 ESC_SHELL = '!'
52 ESC_SH_CAP = '!!'
52 ESC_SH_CAP = '!!'
53 ESC_HELP = '?'
53 ESC_HELP = '?'
54 ESC_MAGIC = '%'
54 ESC_MAGIC = '%'
55 ESC_QUOTE = ','
55 ESC_QUOTE = ','
56 ESC_QUOTE2 = ';'
56 ESC_QUOTE2 = ';'
57 ESC_PAREN = '/'
57 ESC_PAREN = '/'
58
58
59
59
60 class PrefilterError(Exception):
60 class PrefilterError(Exception):
61 pass
61 pass
62
62
63
63
64 # RegExp to identify potential function names
64 # RegExp to identify potential function names
65 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
65 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
66
66
67 # RegExp to exclude strings with this start from autocalling. In
67 # RegExp to exclude strings with this start from autocalling. In
68 # particular, all binary operators should be excluded, so that if foo is
68 # particular, all binary operators should be excluded, so that if foo is
69 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
69 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
70 # characters '!=()' don't need to be checked for, as the checkPythonChars
70 # characters '!=()' don't need to be checked for, as the checkPythonChars
71 # routine explicitely does so, to catch direct calls and rebindings of
71 # routine explicitely does so, to catch direct calls and rebindings of
72 # existing names.
72 # existing names.
73
73
74 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
74 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
75 # it affects the rest of the group in square brackets.
75 # it affects the rest of the group in square brackets.
76 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
76 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
77 r'|^is |^not |^in |^and |^or ')
77 r'|^is |^not |^in |^and |^or ')
78
78
79 # try to catch also methods for stuff in lists/tuples/dicts: off
79 # try to catch also methods for stuff in lists/tuples/dicts: off
80 # (experimental). For this to work, the line_split regexp would need
80 # (experimental). For this to work, the line_split regexp would need
81 # to be modified so it wouldn't break things at '['. That line is
81 # to be modified so it wouldn't break things at '['. That line is
82 # nasty enough that I shouldn't change it until I can test it _well_.
82 # nasty enough that I shouldn't change it until I can test it _well_.
83 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
83 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
84
84
85
85
86 # Handler Check Utilities
86 # Handler Check Utilities
87 def is_shadowed(identifier, ip):
87 def is_shadowed(identifier, ip):
88 """Is the given identifier defined in one of the namespaces which shadow
88 """Is the given identifier defined in one of the namespaces which shadow
89 the alias and magic namespaces? Note that an identifier is different
89 the alias and magic namespaces? Note that an identifier is different
90 than ifun, because it can not contain a '.' character."""
90 than ifun, because it can not contain a '.' character."""
91 # This is much safer than calling ofind, which can change state
91 # This is much safer than calling ofind, which can change state
92 return (identifier in ip.user_ns \
92 return (identifier in ip.user_ns \
93 or identifier in ip.internal_ns \
93 or identifier in ip.internal_ns \
94 or identifier in ip.ns_table['builtin'])
94 or identifier in ip.ns_table['builtin'])
95
95
96
96
97 #-----------------------------------------------------------------------------
97 #-----------------------------------------------------------------------------
98 # The LineInfo class used throughout
98 # The LineInfo class used throughout
99 #-----------------------------------------------------------------------------
99 #-----------------------------------------------------------------------------
100
100
101
101
102 class LineInfo(object):
102 class LineInfo(object):
103 """A single line of input and associated info.
103 """A single line of input and associated info.
104
104
105 Includes the following as properties:
105 Includes the following as properties:
106
106
107 line
107 line
108 The original, raw line
108 The original, raw line
109
109
110 continue_prompt
110 continue_prompt
111 Is this line a continuation in a sequence of multiline input?
111 Is this line a continuation in a sequence of multiline input?
112
112
113 pre
113 pre
114 The initial esc character or whitespace.
114 The initial esc character or whitespace.
115
115
116 pre_char
116 pre_char
117 The escape character(s) in pre or the empty string if there isn't one.
117 The escape character(s) in pre or the empty string if there isn't one.
118 Note that '!!' is a possible value for pre_char. Otherwise it will
118 Note that '!!' is a possible value for pre_char. Otherwise it will
119 always be a single character.
119 always be a single character.
120
120
121 pre_whitespace
121 pre_whitespace
122 The leading whitespace from pre if it exists. If there is a pre_char,
122 The leading whitespace from pre if it exists. If there is a pre_char,
123 this is just ''.
123 this is just ''.
124
124
125 ifun
125 ifun
126 The 'function part', which is basically the maximal initial sequence
126 The 'function part', which is basically the maximal initial sequence
127 of valid python identifiers and the '.' character. This is what is
127 of valid python identifiers and the '.' character. This is what is
128 checked for alias and magic transformations, used for auto-calling,
128 checked for alias and magic transformations, used for auto-calling,
129 etc.
129 etc.
130
130
131 the_rest
131 the_rest
132 Everything else on the line.
132 Everything else on the line.
133 """
133 """
134 def __init__(self, line, continue_prompt):
134 def __init__(self, line, continue_prompt):
135 self.line = line
135 self.line = line
136 self.continue_prompt = continue_prompt
136 self.continue_prompt = continue_prompt
137 self.pre, self.ifun, self.the_rest = split_user_input(line)
137 self.pre, self.ifun, self.the_rest = split_user_input(line)
138
138
139 self.pre_char = self.pre.strip()
139 self.pre_char = self.pre.strip()
140 if self.pre_char:
140 if self.pre_char:
141 self.pre_whitespace = '' # No whitespace allowd before esc chars
141 self.pre_whitespace = '' # No whitespace allowd before esc chars
142 else:
142 else:
143 self.pre_whitespace = self.pre
143 self.pre_whitespace = self.pre
144
144
145 self._oinfo = None
145 self._oinfo = None
146
146
147 def ofind(self, ip):
147 def ofind(self, ip):
148 """Do a full, attribute-walking lookup of the ifun in the various
148 """Do a full, attribute-walking lookup of the ifun in the various
149 namespaces for the given IPython InteractiveShell instance.
149 namespaces for the given IPython InteractiveShell instance.
150
150
151 Return a dict with keys: found,obj,ospace,ismagic
151 Return a dict with keys: found,obj,ospace,ismagic
152
152
153 Note: can cause state changes because of calling getattr, but should
153 Note: can cause state changes because of calling getattr, but should
154 only be run if autocall is on and if the line hasn't matched any
154 only be run if autocall is on and if the line hasn't matched any
155 other, less dangerous handlers.
155 other, less dangerous handlers.
156
156
157 Does cache the results of the call, so can be called multiple times
157 Does cache the results of the call, so can be called multiple times
158 without worrying about *further* damaging state.
158 without worrying about *further* damaging state.
159 """
159 """
160 if not self._oinfo:
160 if not self._oinfo:
161 self._oinfo = ip.shell._ofind(self.ifun)
161 self._oinfo = ip.shell._ofind(self.ifun)
162 return self._oinfo
162 return self._oinfo
163
163
164 def __str__(self):
164 def __str__(self):
165 return "Lineinfo [%s|%s|%s]" %(self.pre,self.ifun,self.the_rest)
165 return "Lineinfo [%s|%s|%s]" %(self.pre,self.ifun,self.the_rest)
166
166
167
167
168 #-----------------------------------------------------------------------------
168 #-----------------------------------------------------------------------------
169 # Main Prefilter manager
169 # Main Prefilter manager
170 #-----------------------------------------------------------------------------
170 #-----------------------------------------------------------------------------
171
171
172
172
173 class PrefilterManager(Component):
173 class PrefilterManager(Component):
174 """Main prefilter component.
174 """Main prefilter component.
175
175
176 The IPython prefilter is run on all user input before it is run. The
176 The IPython prefilter is run on all user input before it is run. The
177 prefilter consumes lines of input and produces transformed lines of
177 prefilter consumes lines of input and produces transformed lines of
178 input.
178 input.
179
179
180 The iplementation consists of two phases:
180 The iplementation consists of two phases:
181
181
182 1. Transformers
182 1. Transformers
183 2. Checkers and handlers
183 2. Checkers and handlers
184
184
185 Over time, we plan on deprecating the checkers and handlers and doing
185 Over time, we plan on deprecating the checkers and handlers and doing
186 everything in the transformers.
186 everything in the transformers.
187
187
188 The transformers are instances of :class:`PrefilterTransformer` and have
188 The transformers are instances of :class:`PrefilterTransformer` and have
189 a single method :meth:`transform` that takes a line and returns a
189 a single method :meth:`transform` that takes a line and returns a
190 transformed line. The transformation can be accomplished using any
190 transformed line. The transformation can be accomplished using any
191 tool, but our current ones use regular expressions for speed. We also
191 tool, but our current ones use regular expressions for speed. We also
192 ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers.
192 ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers.
193
193
194 After all the transformers have been run, the line is fed to the checkers,
194 After all the transformers have been run, the line is fed to the checkers,
195 which are instances of :class:`PrefilterChecker`. The line is passed to
195 which are instances of :class:`PrefilterChecker`. The line is passed to
196 the :meth:`check` method, which either returns `None` or a
196 the :meth:`check` method, which either returns `None` or a
197 :class:`PrefilterHandler` instance. If `None` is returned, the other
197 :class:`PrefilterHandler` instance. If `None` is returned, the other
198 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
198 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
199 the line is passed to the :meth:`handle` method of the returned
199 the line is passed to the :meth:`handle` method of the returned
200 handler and no further checkers are tried.
200 handler and no further checkers are tried.
201
201
202 Both transformers and checkers have a `priority` attribute, that determines
202 Both transformers and checkers have a `priority` attribute, that determines
203 the order in which they are called. Smaller priorities are tried first.
203 the order in which they are called. Smaller priorities are tried first.
204
204
205 Both transformers and checkers also have `enabled` attribute, which is
205 Both transformers and checkers also have `enabled` attribute, which is
206 a boolean that determines if the instance is used.
206 a boolean that determines if the instance is used.
207
207
208 Users or developers can change the priority or enabled attribute of
208 Users or developers can change the priority or enabled attribute of
209 transformers or checkers, but they must call the :meth:`sort_checkers`
209 transformers or checkers, but they must call the :meth:`sort_checkers`
210 or :meth:`sort_transformers` method after changing the priority.
210 or :meth:`sort_transformers` method after changing the priority.
211 """
211 """
212
212
213 multi_line_specials = CBool(True, config=True)
213 multi_line_specials = CBool(True, config=True)
214
214
215 def __init__(self, parent, config=None):
215 def __init__(self, parent, config=None):
216 super(PrefilterManager, self).__init__(parent, config=config)
216 super(PrefilterManager, self).__init__(parent, config=config)
217 self.init_transformers()
217 self.init_transformers()
218 self.init_handlers()
218 self.init_handlers()
219 self.init_checkers()
219 self.init_checkers()
220
220
221 @auto_attr
221 @auto_attr
222 def shell(self):
222 def shell(self):
223 return Component.get_instances(
223 return Component.get_instances(
224 root=self.root,
224 root=self.root,
225 klass='IPython.core.iplib.InteractiveShell')[0]
225 klass='IPython.core.iplib.InteractiveShell')[0]
226
226
227 #-------------------------------------------------------------------------
227 #-------------------------------------------------------------------------
228 # API for managing transformers
228 # API for managing transformers
229 #-------------------------------------------------------------------------
229 #-------------------------------------------------------------------------
230
230
231 def init_transformers(self):
231 def init_transformers(self):
232 """Create the default transformers."""
232 """Create the default transformers."""
233 self._transformers = []
233 self._transformers = []
234 for transformer_cls in _default_transformers:
234 for transformer_cls in _default_transformers:
235 transformer_cls(self, config=self.config)
235 transformer_cls(self, config=self.config)
236
236
237 def sort_transformers(self):
237 def sort_transformers(self):
238 """Sort the transformers by priority.
238 """Sort the transformers by priority.
239
239
240 This must be called after the priority of a transformer is changed.
240 This must be called after the priority of a transformer is changed.
241 The :meth:`register_transformer` method calls this automatically.
241 The :meth:`register_transformer` method calls this automatically.
242 """
242 """
243 self._transformers.sort(cmp=lambda x,y: x.priority-y.priority)
243 self._transformers.sort(cmp=lambda x,y: x.priority-y.priority)
244
244
245 @property
245 @property
246 def transformers(self):
246 def transformers(self):
247 """Return a list of checkers, sorted by priority."""
247 """Return a list of checkers, sorted by priority."""
248 return self._transformers
248 return self._transformers
249
249
250 def register_transformer(self, transformer):
250 def register_transformer(self, transformer):
251 """Register a transformer instance."""
251 """Register a transformer instance."""
252 if transformer not in self._transformers:
252 if transformer not in self._transformers:
253 self._transformers.append(transformer)
253 self._transformers.append(transformer)
254 self.sort_transformers()
254 self.sort_transformers()
255
255
256 def unregister_transformer(self, transformer):
256 def unregister_transformer(self, transformer):
257 """Unregister a transformer instance."""
257 """Unregister a transformer instance."""
258 if transformer in self._transformers:
258 if transformer in self._transformers:
259 self._transformers.remove(transformer)
259 self._transformers.remove(transformer)
260
260
261 #-------------------------------------------------------------------------
261 #-------------------------------------------------------------------------
262 # API for managing checkers
262 # API for managing checkers
263 #-------------------------------------------------------------------------
263 #-------------------------------------------------------------------------
264
264
265 def init_checkers(self):
265 def init_checkers(self):
266 """Create the default checkers."""
266 """Create the default checkers."""
267 self._checkers = []
267 self._checkers = []
268 for checker in _default_checkers:
268 for checker in _default_checkers:
269 checker(self, config=self.config)
269 checker(self, config=self.config)
270
270
271 def sort_checkers(self):
271 def sort_checkers(self):
272 """Sort the checkers by priority.
272 """Sort the checkers by priority.
273
273
274 This must be called after the priority of a checker is changed.
274 This must be called after the priority of a checker is changed.
275 The :meth:`register_checker` method calls this automatically.
275 The :meth:`register_checker` method calls this automatically.
276 """
276 """
277 self._checkers.sort(cmp=lambda x,y: x.priority-y.priority)
277 self._checkers.sort(cmp=lambda x,y: x.priority-y.priority)
278
278
279 @property
279 @property
280 def checkers(self):
280 def checkers(self):
281 """Return a list of checkers, sorted by priority."""
281 """Return a list of checkers, sorted by priority."""
282 return self._checkers
282 return self._checkers
283
283
284 def register_checker(self, checker):
284 def register_checker(self, checker):
285 """Register a checker instance."""
285 """Register a checker instance."""
286 if checker not in self._checkers:
286 if checker not in self._checkers:
287 self._checkers.append(checker)
287 self._checkers.append(checker)
288 self.sort_checkers()
288 self.sort_checkers()
289
289
290 def unregister_checker(self, checker):
290 def unregister_checker(self, checker):
291 """Unregister a checker instance."""
291 """Unregister a checker instance."""
292 if checker in self._checkers:
292 if checker in self._checkers:
293 self._checkers.remove(checker)
293 self._checkers.remove(checker)
294
294
295 #-------------------------------------------------------------------------
295 #-------------------------------------------------------------------------
296 # API for managing checkers
296 # API for managing checkers
297 #-------------------------------------------------------------------------
297 #-------------------------------------------------------------------------
298
298
299 def init_handlers(self):
299 def init_handlers(self):
300 """Create the default handlers."""
300 """Create the default handlers."""
301 self._handlers = {}
301 self._handlers = {}
302 self._esc_handlers = {}
302 self._esc_handlers = {}
303 for handler in _default_handlers:
303 for handler in _default_handlers:
304 handler(self, config=self.config)
304 handler(self, config=self.config)
305
305
306 @property
306 @property
307 def handlers(self):
307 def handlers(self):
308 """Return a dict of all the handlers."""
308 """Return a dict of all the handlers."""
309 return self._handlers
309 return self._handlers
310
310
311 def register_handler(self, name, handler, esc_strings):
311 def register_handler(self, name, handler, esc_strings):
312 """Register a handler instance by name with esc_strings."""
312 """Register a handler instance by name with esc_strings."""
313 self._handlers[name] = handler
313 self._handlers[name] = handler
314 for esc_str in esc_strings:
314 for esc_str in esc_strings:
315 self._esc_handlers[esc_str] = handler
315 self._esc_handlers[esc_str] = handler
316
316
317 def unregister_handler(self, name, handler, esc_strings):
317 def unregister_handler(self, name, handler, esc_strings):
318 """Unregister a handler instance by name with esc_strings."""
318 """Unregister a handler instance by name with esc_strings."""
319 try:
319 try:
320 del self._handlers[name]
320 del self._handlers[name]
321 except KeyError:
321 except KeyError:
322 pass
322 pass
323 for esc_str in esc_strings:
323 for esc_str in esc_strings:
324 h = self._esc_handlers.get(esc_str)
324 h = self._esc_handlers.get(esc_str)
325 if h is handler:
325 if h is handler:
326 del self._esc_handlers[esc_str]
326 del self._esc_handlers[esc_str]
327
327
328 def get_handler_by_name(self, name):
328 def get_handler_by_name(self, name):
329 """Get a handler by its name."""
329 """Get a handler by its name."""
330 return self._handlers.get(name)
330 return self._handlers.get(name)
331
331
332 def get_handler_by_esc(self, esc_str):
332 def get_handler_by_esc(self, esc_str):
333 """Get a handler by its escape string."""
333 """Get a handler by its escape string."""
334 return self._esc_handlers.get(esc_str)
334 return self._esc_handlers.get(esc_str)
335
335
336 #-------------------------------------------------------------------------
336 #-------------------------------------------------------------------------
337 # Main prefiltering API
337 # Main prefiltering API
338 #-------------------------------------------------------------------------
338 #-------------------------------------------------------------------------
339
339
340 def prefilter_line_info(self, line_info):
340 def prefilter_line_info(self, line_info):
341 """Prefilter a line that has been converted to a LineInfo object.
341 """Prefilter a line that has been converted to a LineInfo object.
342
342
343 This implements the checker/handler part of the prefilter pipe.
343 This implements the checker/handler part of the prefilter pipe.
344 """
344 """
345 # print "prefilter_line_info: ", line_info
345 # print "prefilter_line_info: ", line_info
346 handler = self.find_handler(line_info)
346 handler = self.find_handler(line_info)
347 return handler.handle(line_info)
347 return handler.handle(line_info)
348
348
349 def find_handler(self, line_info):
349 def find_handler(self, line_info):
350 """Find a handler for the line_info by trying checkers."""
350 """Find a handler for the line_info by trying checkers."""
351 for checker in self.checkers:
351 for checker in self.checkers:
352 if checker.enabled:
352 if checker.enabled:
353 handler = checker.check(line_info)
353 handler = checker.check(line_info)
354 if handler:
354 if handler:
355 return handler
355 return handler
356 return self.get_handler_by_name('normal')
356 return self.get_handler_by_name('normal')
357
357
358 def transform_line(self, line, continue_prompt):
358 def transform_line(self, line, continue_prompt):
359 """Calls the enabled transformers in order of increasing priority."""
359 """Calls the enabled transformers in order of increasing priority."""
360 for transformer in self.transformers:
360 for transformer in self.transformers:
361 if transformer.enabled:
361 if transformer.enabled:
362 line = transformer.transform(line, continue_prompt)
362 line = transformer.transform(line, continue_prompt)
363 return line
363 return line
364
364
365 def prefilter_line(self, line, continue_prompt):
365 def prefilter_line(self, line, continue_prompt):
366 """Prefilter a single input line as text.
366 """Prefilter a single input line as text.
367
367
368 This method prefilters a single line of text by calling the
368 This method prefilters a single line of text by calling the
369 transformers and then the checkers/handlers.
369 transformers and then the checkers/handlers.
370 """
370 """
371
371
372 # print "prefilter_line: ", line, continue_prompt
372 # print "prefilter_line: ", line, continue_prompt
373 # All handlers *must* return a value, even if it's blank ('').
373 # All handlers *must* return a value, even if it's blank ('').
374
374
375 # Lines are NOT logged here. Handlers should process the line as
375 # Lines are NOT logged here. Handlers should process the line as
376 # needed, update the cache AND log it (so that the input cache array
376 # needed, update the cache AND log it (so that the input cache array
377 # stays synced).
377 # stays synced).
378
378
379 # save the line away in case we crash, so the post-mortem handler can
379 # save the line away in case we crash, so the post-mortem handler can
380 # record it
380 # record it
381 self.shell._last_input_line = line
381 self.shell._last_input_line = line
382
382
383 if not line:
383 if not line:
384 # Return immediately on purely empty lines, so that if the user
384 # Return immediately on purely empty lines, so that if the user
385 # previously typed some whitespace that started a continuation
385 # previously typed some whitespace that started a continuation
386 # prompt, he can break out of that loop with just an empty line.
386 # prompt, he can break out of that loop with just an empty line.
387 # This is how the default python prompt works.
387 # This is how the default python prompt works.
388
388
389 # Only return if the accumulated input buffer was just whitespace!
389 # Only return if the accumulated input buffer was just whitespace!
390 if ''.join(self.shell.buffer).isspace():
390 if ''.join(self.shell.buffer).isspace():
391 self.shell.buffer[:] = []
391 self.shell.buffer[:] = []
392 return ''
392 return ''
393
393
394 # At this point, we invoke our transformers.
394 # At this point, we invoke our transformers.
395 if not continue_prompt or (continue_prompt and self.multi_line_specials):
395 if not continue_prompt or (continue_prompt and self.multi_line_specials):
396 line = self.transform_line(line, continue_prompt)
396 line = self.transform_line(line, continue_prompt)
397
397
398 # Now we compute line_info for the checkers and handlers
398 # Now we compute line_info for the checkers and handlers
399 line_info = LineInfo(line, continue_prompt)
399 line_info = LineInfo(line, continue_prompt)
400
400
401 # the input history needs to track even empty lines
401 # the input history needs to track even empty lines
402 stripped = line.strip()
402 stripped = line.strip()
403
403
404 normal_handler = self.get_handler_by_name('normal')
404 normal_handler = self.get_handler_by_name('normal')
405 if not stripped:
405 if not stripped:
406 if not continue_prompt:
406 if not continue_prompt:
407 self.shell.outputcache.prompt_count -= 1
407 self.shell.outputcache.prompt_count -= 1
408
408
409 return normal_handler.handle(line_info)
409 return normal_handler.handle(line_info)
410
410
411 # special handlers are only allowed for single line statements
411 # special handlers are only allowed for single line statements
412 if continue_prompt and not self.multi_line_specials:
412 if continue_prompt and not self.multi_line_specials:
413 return normal_handler.handle(line_info)
413 return normal_handler.handle(line_info)
414
414
415 prefiltered = self.prefilter_line_info(line_info)
415 prefiltered = self.prefilter_line_info(line_info)
416 # print "prefiltered line: %r" % prefiltered
416 # print "prefiltered line: %r" % prefiltered
417 return prefiltered
417 return prefiltered
418
418
419 def prefilter_lines(self, lines, continue_prompt):
419 def prefilter_lines(self, lines, continue_prompt=False):
420 """Prefilter multiple input lines of text.
420 """Prefilter multiple input lines of text.
421
421
422 This is the main entry point for prefiltering multiple lines of
422 This is the main entry point for prefiltering multiple lines of
423 input. This simply calls :meth:`prefilter_line` for each line of
423 input. This simply calls :meth:`prefilter_line` for each line of
424 input.
424 input.
425
425
426 This covers cases where there are multiple lines in the user entry,
426 This covers cases where there are multiple lines in the user entry,
427 which is the case when the user goes back to a multiline history
427 which is the case when the user goes back to a multiline history
428 entry and presses enter.
428 entry and presses enter.
429 """
429 """
430 out = []
430 out = []
431 for line in lines.rstrip('\n').split('\n'):
431 for line in lines.rstrip('\n').split('\n'):
432 out.append(self.prefilter_line(line, continue_prompt))
432 out.append(self.prefilter_line(line, continue_prompt))
433 return '\n'.join(out)
433 return '\n'.join(out)
434
434
435
435
436 #-----------------------------------------------------------------------------
436 #-----------------------------------------------------------------------------
437 # Prefilter transformers
437 # Prefilter transformers
438 #-----------------------------------------------------------------------------
438 #-----------------------------------------------------------------------------
439
439
440
440
441 class PrefilterTransformer(Component):
441 class PrefilterTransformer(Component):
442 """Transform a line of user input."""
442 """Transform a line of user input."""
443
443
444 priority = Int(100, config=True)
444 priority = Int(100, config=True)
445 shell = Any
445 shell = Any
446 prefilter_manager = Any
446 prefilter_manager = Any
447 enabled = Bool(True, config=True)
447 enabled = Bool(True, config=True)
448
448
449 def __init__(self, parent, config=None):
449 def __init__(self, parent, config=None):
450 super(PrefilterTransformer, self).__init__(parent, config=config)
450 super(PrefilterTransformer, self).__init__(parent, config=config)
451 self.prefilter_manager.register_transformer(self)
451 self.prefilter_manager.register_transformer(self)
452
452
453 @auto_attr
453 @auto_attr
454 def shell(self):
454 def shell(self):
455 return Component.get_instances(
455 return Component.get_instances(
456 root=self.root,
456 root=self.root,
457 klass='IPython.core.iplib.InteractiveShell')[0]
457 klass='IPython.core.iplib.InteractiveShell')[0]
458
458
459 @auto_attr
459 @auto_attr
460 def prefilter_manager(self):
460 def prefilter_manager(self):
461 return PrefilterManager.get_instances(root=self.root)[0]
461 return PrefilterManager.get_instances(root=self.root)[0]
462
462
463 def transform(self, line, continue_prompt):
463 def transform(self, line, continue_prompt):
464 """Transform a line, returning the new one."""
464 """Transform a line, returning the new one."""
465 return None
465 return None
466
466
467 def __repr__(self):
467 def __repr__(self):
468 return "<%s(priority=%r, enabled=%r)>" % (
468 return "<%s(priority=%r, enabled=%r)>" % (
469 self.__class__.__name__, self.priority, self.enabled)
469 self.__class__.__name__, self.priority, self.enabled)
470
470
471
471
472 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
472 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
473 r'\s*=\s*!(?P<cmd>.*)')
473 r'\s*=\s*!(?P<cmd>.*)')
474
474
475
475
476 class AssignSystemTransformer(PrefilterTransformer):
476 class AssignSystemTransformer(PrefilterTransformer):
477 """Handle the `files = !ls` syntax."""
477 """Handle the `files = !ls` syntax."""
478
478
479 priority = Int(100, config=True)
479 priority = Int(100, config=True)
480
480
481 def transform(self, line, continue_prompt):
481 def transform(self, line, continue_prompt):
482 m = _assign_system_re.match(line)
482 m = _assign_system_re.match(line)
483 if m is not None:
483 if m is not None:
484 cmd = m.group('cmd')
484 cmd = m.group('cmd')
485 lhs = m.group('lhs')
485 lhs = m.group('lhs')
486 expr = make_quoted_expr("sc -l =%s" % cmd)
486 expr = make_quoted_expr("sc -l =%s" % cmd)
487 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
487 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
488 return new_line
488 return new_line
489 return line
489 return line
490
490
491
491
492 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
492 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
493 r'\s*=\s*%(?P<cmd>.*)')
493 r'\s*=\s*%(?P<cmd>.*)')
494
494
495 class AssignMagicTransformer(PrefilterTransformer):
495 class AssignMagicTransformer(PrefilterTransformer):
496 """Handle the `a = %who` syntax."""
496 """Handle the `a = %who` syntax."""
497
497
498 priority = Int(200, config=True)
498 priority = Int(200, config=True)
499
499
500 def transform(self, line, continue_prompt):
500 def transform(self, line, continue_prompt):
501 m = _assign_magic_re.match(line)
501 m = _assign_magic_re.match(line)
502 if m is not None:
502 if m is not None:
503 cmd = m.group('cmd')
503 cmd = m.group('cmd')
504 lhs = m.group('lhs')
504 lhs = m.group('lhs')
505 expr = make_quoted_expr(cmd)
505 expr = make_quoted_expr(cmd)
506 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
506 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
507 return new_line
507 return new_line
508 return line
508 return line
509
509
510
510
511 #-----------------------------------------------------------------------------
511 #-----------------------------------------------------------------------------
512 # Prefilter checkers
512 # Prefilter checkers
513 #-----------------------------------------------------------------------------
513 #-----------------------------------------------------------------------------
514
514
515
515
516 class PrefilterChecker(Component):
516 class PrefilterChecker(Component):
517 """Inspect an input line and return a handler for that line."""
517 """Inspect an input line and return a handler for that line."""
518
518
519 priority = Int(100, config=True)
519 priority = Int(100, config=True)
520 shell = Any
520 shell = Any
521 prefilter_manager = Any
521 prefilter_manager = Any
522 enabled = Bool(True, config=True)
522 enabled = Bool(True, config=True)
523
523
524 def __init__(self, parent, config=None):
524 def __init__(self, parent, config=None):
525 super(PrefilterChecker, self).__init__(parent, config=config)
525 super(PrefilterChecker, self).__init__(parent, config=config)
526 self.prefilter_manager.register_checker(self)
526 self.prefilter_manager.register_checker(self)
527
527
528 @auto_attr
528 @auto_attr
529 def shell(self):
529 def shell(self):
530 return Component.get_instances(
530 return Component.get_instances(
531 root=self.root,
531 root=self.root,
532 klass='IPython.core.iplib.InteractiveShell')[0]
532 klass='IPython.core.iplib.InteractiveShell')[0]
533
533
534 @auto_attr
534 @auto_attr
535 def prefilter_manager(self):
535 def prefilter_manager(self):
536 return PrefilterManager.get_instances(root=self.root)[0]
536 return PrefilterManager.get_instances(root=self.root)[0]
537
537
538 def check(self, line_info):
538 def check(self, line_info):
539 """Inspect line_info and return a handler instance or None."""
539 """Inspect line_info and return a handler instance or None."""
540 return None
540 return None
541
541
542 def __repr__(self):
542 def __repr__(self):
543 return "<%s(priority=%r, enabled=%r)>" % (
543 return "<%s(priority=%r, enabled=%r)>" % (
544 self.__class__.__name__, self.priority, self.enabled)
544 self.__class__.__name__, self.priority, self.enabled)
545
545
546
546
547 class EmacsChecker(PrefilterChecker):
547 class EmacsChecker(PrefilterChecker):
548
548
549 priority = Int(100, config=True)
549 priority = Int(100, config=True)
550 enabled = Bool(False, config=True)
550 enabled = Bool(False, config=True)
551
551
552 def check(self, line_info):
552 def check(self, line_info):
553 "Emacs ipython-mode tags certain input lines."
553 "Emacs ipython-mode tags certain input lines."
554 if line_info.line.endswith('# PYTHON-MODE'):
554 if line_info.line.endswith('# PYTHON-MODE'):
555 return self.prefilter_manager.get_handler_by_name('emacs')
555 return self.prefilter_manager.get_handler_by_name('emacs')
556 else:
556 else:
557 return None
557 return None
558
558
559
559
560 class ShellEscapeChecker(PrefilterChecker):
560 class ShellEscapeChecker(PrefilterChecker):
561
561
562 priority = Int(200, config=True)
562 priority = Int(200, config=True)
563
563
564 def check(self, line_info):
564 def check(self, line_info):
565 if line_info.line.lstrip().startswith(ESC_SHELL):
565 if line_info.line.lstrip().startswith(ESC_SHELL):
566 return self.prefilter_manager.get_handler_by_name('shell')
566 return self.prefilter_manager.get_handler_by_name('shell')
567
567
568
568
569 class IPyAutocallChecker(PrefilterChecker):
569 class IPyAutocallChecker(PrefilterChecker):
570
570
571 priority = Int(300, config=True)
571 priority = Int(300, config=True)
572
572
573 def check(self, line_info):
573 def check(self, line_info):
574 "Instances of IPyAutocall in user_ns get autocalled immediately"
574 "Instances of IPyAutocall in user_ns get autocalled immediately"
575 obj = self.shell.user_ns.get(line_info.ifun, None)
575 obj = self.shell.user_ns.get(line_info.ifun, None)
576 if isinstance(obj, IPyAutocall):
576 if isinstance(obj, IPyAutocall):
577 obj.set_ip(self.shell)
577 obj.set_ip(self.shell)
578 return self.prefilter_manager.get_handler_by_name('auto')
578 return self.prefilter_manager.get_handler_by_name('auto')
579 else:
579 else:
580 return None
580 return None
581
581
582
582
583 class MultiLineMagicChecker(PrefilterChecker):
583 class MultiLineMagicChecker(PrefilterChecker):
584
584
585 priority = Int(400, config=True)
585 priority = Int(400, config=True)
586
586
587 def check(self, line_info):
587 def check(self, line_info):
588 "Allow ! and !! in multi-line statements if multi_line_specials is on"
588 "Allow ! and !! in multi-line statements if multi_line_specials is on"
589 # Note that this one of the only places we check the first character of
589 # Note that this one of the only places we check the first character of
590 # ifun and *not* the pre_char. Also note that the below test matches
590 # ifun and *not* the pre_char. Also note that the below test matches
591 # both ! and !!.
591 # both ! and !!.
592 if line_info.continue_prompt \
592 if line_info.continue_prompt \
593 and self.prefilter_manager.multi_line_specials:
593 and self.prefilter_manager.multi_line_specials:
594 if line_info.ifun.startswith(ESC_MAGIC):
594 if line_info.ifun.startswith(ESC_MAGIC):
595 return self.prefilter_manager.get_handler_by_name('magic')
595 return self.prefilter_manager.get_handler_by_name('magic')
596 else:
596 else:
597 return None
597 return None
598
598
599
599
600 class EscCharsChecker(PrefilterChecker):
600 class EscCharsChecker(PrefilterChecker):
601
601
602 priority = Int(500, config=True)
602 priority = Int(500, config=True)
603
603
604 def check(self, line_info):
604 def check(self, line_info):
605 """Check for escape character and return either a handler to handle it,
605 """Check for escape character and return either a handler to handle it,
606 or None if there is no escape char."""
606 or None if there is no escape char."""
607 if line_info.line[-1] == ESC_HELP \
607 if line_info.line[-1] == ESC_HELP \
608 and line_info.pre_char != ESC_SHELL \
608 and line_info.pre_char != ESC_SHELL \
609 and line_info.pre_char != ESC_SH_CAP:
609 and line_info.pre_char != ESC_SH_CAP:
610 # the ? can be at the end, but *not* for either kind of shell escape,
610 # the ? can be at the end, but *not* for either kind of shell escape,
611 # because a ? can be a vaild final char in a shell cmd
611 # because a ? can be a vaild final char in a shell cmd
612 return self.prefilter_manager.get_handler_by_name('help')
612 return self.prefilter_manager.get_handler_by_name('help')
613 else:
613 else:
614 # This returns None like it should if no handler exists
614 # This returns None like it should if no handler exists
615 return self.prefilter_manager.get_handler_by_esc(line_info.pre_char)
615 return self.prefilter_manager.get_handler_by_esc(line_info.pre_char)
616
616
617
617
618 class AssignmentChecker(PrefilterChecker):
618 class AssignmentChecker(PrefilterChecker):
619
619
620 priority = Int(600, config=True)
620 priority = Int(600, config=True)
621
621
622 def check(self, line_info):
622 def check(self, line_info):
623 """Check to see if user is assigning to a var for the first time, in
623 """Check to see if user is assigning to a var for the first time, in
624 which case we want to avoid any sort of automagic / autocall games.
624 which case we want to avoid any sort of automagic / autocall games.
625
625
626 This allows users to assign to either alias or magic names true python
626 This allows users to assign to either alias or magic names true python
627 variables (the magic/alias systems always take second seat to true
627 variables (the magic/alias systems always take second seat to true
628 python code). E.g. ls='hi', or ls,that=1,2"""
628 python code). E.g. ls='hi', or ls,that=1,2"""
629 if line_info.the_rest:
629 if line_info.the_rest:
630 if line_info.the_rest[0] in '=,':
630 if line_info.the_rest[0] in '=,':
631 return self.prefilter_manager.get_handler_by_name('normal')
631 return self.prefilter_manager.get_handler_by_name('normal')
632 else:
632 else:
633 return None
633 return None
634
634
635
635
636 class AutoMagicChecker(PrefilterChecker):
636 class AutoMagicChecker(PrefilterChecker):
637
637
638 priority = Int(700, config=True)
638 priority = Int(700, config=True)
639
639
640 def check(self, line_info):
640 def check(self, line_info):
641 """If the ifun is magic, and automagic is on, run it. Note: normal,
641 """If the ifun is magic, and automagic is on, run it. Note: normal,
642 non-auto magic would already have been triggered via '%' in
642 non-auto magic would already have been triggered via '%' in
643 check_esc_chars. This just checks for automagic. Also, before
643 check_esc_chars. This just checks for automagic. Also, before
644 triggering the magic handler, make sure that there is nothing in the
644 triggering the magic handler, make sure that there is nothing in the
645 user namespace which could shadow it."""
645 user namespace which could shadow it."""
646 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
646 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
647 return None
647 return None
648
648
649 # We have a likely magic method. Make sure we should actually call it.
649 # We have a likely magic method. Make sure we should actually call it.
650 if line_info.continue_prompt and not self.shell.multi_line_specials:
650 if line_info.continue_prompt and not self.shell.multi_line_specials:
651 return None
651 return None
652
652
653 head = line_info.ifun.split('.',1)[0]
653 head = line_info.ifun.split('.',1)[0]
654 if is_shadowed(head, self.shell):
654 if is_shadowed(head, self.shell):
655 return None
655 return None
656
656
657 return self.prefilter_manager.get_handler_by_name('magic')
657 return self.prefilter_manager.get_handler_by_name('magic')
658
658
659
659
660 class AliasChecker(PrefilterChecker):
660 class AliasChecker(PrefilterChecker):
661
661
662 priority = Int(800, config=True)
662 priority = Int(800, config=True)
663
663
664 @auto_attr
664 @auto_attr
665 def alias_manager(self):
665 def alias_manager(self):
666 return AliasManager.get_instances(root=self.root)[0]
666 return AliasManager.get_instances(root=self.root)[0]
667
667
668 def check(self, line_info):
668 def check(self, line_info):
669 "Check if the initital identifier on the line is an alias."
669 "Check if the initital identifier on the line is an alias."
670 # Note: aliases can not contain '.'
670 # Note: aliases can not contain '.'
671 head = line_info.ifun.split('.',1)[0]
671 head = line_info.ifun.split('.',1)[0]
672 if line_info.ifun not in self.alias_manager \
672 if line_info.ifun not in self.alias_manager \
673 or head not in self.alias_manager \
673 or head not in self.alias_manager \
674 or is_shadowed(head, self.shell):
674 or is_shadowed(head, self.shell):
675 return None
675 return None
676
676
677 return self.prefilter_manager.get_handler_by_name('alias')
677 return self.prefilter_manager.get_handler_by_name('alias')
678
678
679
679
680 class PythonOpsChecker(PrefilterChecker):
680 class PythonOpsChecker(PrefilterChecker):
681
681
682 priority = Int(900, config=True)
682 priority = Int(900, config=True)
683
683
684 def check(self, line_info):
684 def check(self, line_info):
685 """If the 'rest' of the line begins with a function call or pretty much
685 """If the 'rest' of the line begins with a function call or pretty much
686 any python operator, we should simply execute the line (regardless of
686 any python operator, we should simply execute the line (regardless of
687 whether or not there's a possible autocall expansion). This avoids
687 whether or not there's a possible autocall expansion). This avoids
688 spurious (and very confusing) geattr() accesses."""
688 spurious (and very confusing) geattr() accesses."""
689 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
689 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
690 return self.prefilter_manager.get_handler_by_name('normal')
690 return self.prefilter_manager.get_handler_by_name('normal')
691 else:
691 else:
692 return None
692 return None
693
693
694
694
695 class AutocallChecker(PrefilterChecker):
695 class AutocallChecker(PrefilterChecker):
696
696
697 priority = Int(1000, config=True)
697 priority = Int(1000, config=True)
698
698
699 def check(self, line_info):
699 def check(self, line_info):
700 "Check if the initial word/function is callable and autocall is on."
700 "Check if the initial word/function is callable and autocall is on."
701 if not self.shell.autocall:
701 if not self.shell.autocall:
702 return None
702 return None
703
703
704 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
704 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
705 if not oinfo['found']:
705 if not oinfo['found']:
706 return None
706 return None
707
707
708 if callable(oinfo['obj']) \
708 if callable(oinfo['obj']) \
709 and (not re_exclude_auto.match(line_info.the_rest)) \
709 and (not re_exclude_auto.match(line_info.the_rest)) \
710 and re_fun_name.match(line_info.ifun):
710 and re_fun_name.match(line_info.ifun):
711 return self.prefilter_manager.get_handler_by_name('auto')
711 return self.prefilter_manager.get_handler_by_name('auto')
712 else:
712 else:
713 return None
713 return None
714
714
715
715
716 #-----------------------------------------------------------------------------
716 #-----------------------------------------------------------------------------
717 # Prefilter handlers
717 # Prefilter handlers
718 #-----------------------------------------------------------------------------
718 #-----------------------------------------------------------------------------
719
719
720
720
721 class PrefilterHandler(Component):
721 class PrefilterHandler(Component):
722
722
723 handler_name = Str('normal')
723 handler_name = Str('normal')
724 esc_strings = List([])
724 esc_strings = List([])
725 shell = Any
725 shell = Any
726 prefilter_manager = Any
726 prefilter_manager = Any
727
727
728 def __init__(self, parent, config=None):
728 def __init__(self, parent, config=None):
729 super(PrefilterHandler, self).__init__(parent, config=config)
729 super(PrefilterHandler, self).__init__(parent, config=config)
730 self.prefilter_manager.register_handler(
730 self.prefilter_manager.register_handler(
731 self.handler_name,
731 self.handler_name,
732 self,
732 self,
733 self.esc_strings
733 self.esc_strings
734 )
734 )
735
735
736 @auto_attr
736 @auto_attr
737 def shell(self):
737 def shell(self):
738 return Component.get_instances(
738 return Component.get_instances(
739 root=self.root,
739 root=self.root,
740 klass='IPython.core.iplib.InteractiveShell')[0]
740 klass='IPython.core.iplib.InteractiveShell')[0]
741
741
742 @auto_attr
742 @auto_attr
743 def prefilter_manager(self):
743 def prefilter_manager(self):
744 return PrefilterManager.get_instances(root=self.root)[0]
744 return PrefilterManager.get_instances(root=self.root)[0]
745
745
746 def handle(self, line_info):
746 def handle(self, line_info):
747 # print "normal: ", line_info
747 # print "normal: ", line_info
748 """Handle normal input lines. Use as a template for handlers."""
748 """Handle normal input lines. Use as a template for handlers."""
749
749
750 # With autoindent on, we need some way to exit the input loop, and I
750 # With autoindent on, we need some way to exit the input loop, and I
751 # don't want to force the user to have to backspace all the way to
751 # don't want to force the user to have to backspace all the way to
752 # clear the line. The rule will be in this case, that either two
752 # clear the line. The rule will be in this case, that either two
753 # lines of pure whitespace in a row, or a line of pure whitespace but
753 # lines of pure whitespace in a row, or a line of pure whitespace but
754 # of a size different to the indent level, will exit the input loop.
754 # of a size different to the indent level, will exit the input loop.
755 line = line_info.line
755 line = line_info.line
756 continue_prompt = line_info.continue_prompt
756 continue_prompt = line_info.continue_prompt
757
757
758 if (continue_prompt and self.shell.autoindent and line.isspace() and
758 if (continue_prompt and self.shell.autoindent and line.isspace() and
759 (0 < abs(len(line) - self.shell.indent_current_nsp) <= 2 or
759 (0 < abs(len(line) - self.shell.indent_current_nsp) <= 2 or
760 (self.shell.buffer[-1]).isspace() )):
760 (self.shell.buffer[-1]).isspace() )):
761 line = ''
761 line = ''
762
762
763 self.shell.log(line, line, continue_prompt)
763 self.shell.log(line, line, continue_prompt)
764 return line
764 return line
765
765
766 def __str__(self):
766 def __str__(self):
767 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
767 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
768
768
769
769
770 class AliasHandler(PrefilterHandler):
770 class AliasHandler(PrefilterHandler):
771
771
772 handler_name = Str('alias')
772 handler_name = Str('alias')
773
773
774 @auto_attr
774 @auto_attr
775 def alias_manager(self):
775 def alias_manager(self):
776 return AliasManager.get_instances(root=self.root)[0]
776 return AliasManager.get_instances(root=self.root)[0]
777
777
778 def handle(self, line_info):
778 def handle(self, line_info):
779 """Handle alias input lines. """
779 """Handle alias input lines. """
780 transformed = self.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
780 transformed = self.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
781 # pre is needed, because it carries the leading whitespace. Otherwise
781 # pre is needed, because it carries the leading whitespace. Otherwise
782 # aliases won't work in indented sections.
782 # aliases won't work in indented sections.
783 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
783 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
784 make_quoted_expr(transformed))
784 make_quoted_expr(transformed))
785
785
786 self.shell.log(line_info.line, line_out, line_info.continue_prompt)
786 self.shell.log(line_info.line, line_out, line_info.continue_prompt)
787 return line_out
787 return line_out
788
788
789
789
790 class ShellEscapeHandler(PrefilterHandler):
790 class ShellEscapeHandler(PrefilterHandler):
791
791
792 handler_name = Str('shell')
792 handler_name = Str('shell')
793 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
793 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
794
794
795 def handle(self, line_info):
795 def handle(self, line_info):
796 """Execute the line in a shell, empty return value"""
796 """Execute the line in a shell, empty return value"""
797 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
797 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
798
798
799 line = line_info.line
799 line = line_info.line
800 if line.lstrip().startswith(ESC_SH_CAP):
800 if line.lstrip().startswith(ESC_SH_CAP):
801 # rewrite LineInfo's line, ifun and the_rest to properly hold the
801 # rewrite LineInfo's line, ifun and the_rest to properly hold the
802 # call to %sx and the actual command to be executed, so
802 # call to %sx and the actual command to be executed, so
803 # handle_magic can work correctly. Note that this works even if
803 # handle_magic can work correctly. Note that this works even if
804 # the line is indented, so it handles multi_line_specials
804 # the line is indented, so it handles multi_line_specials
805 # properly.
805 # properly.
806 new_rest = line.lstrip()[2:]
806 new_rest = line.lstrip()[2:]
807 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
807 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
808 line_info.ifun = 'sx'
808 line_info.ifun = 'sx'
809 line_info.the_rest = new_rest
809 line_info.the_rest = new_rest
810 return magic_handler.handle(line_info)
810 return magic_handler.handle(line_info)
811 else:
811 else:
812 cmd = line.lstrip().lstrip(ESC_SHELL)
812 cmd = line.lstrip().lstrip(ESC_SHELL)
813 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
813 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
814 make_quoted_expr(cmd))
814 make_quoted_expr(cmd))
815 # update cache/log and return
815 # update cache/log and return
816 self.shell.log(line, line_out, line_info.continue_prompt)
816 self.shell.log(line, line_out, line_info.continue_prompt)
817 return line_out
817 return line_out
818
818
819
819
820 class MagicHandler(PrefilterHandler):
820 class MagicHandler(PrefilterHandler):
821
821
822 handler_name = Str('magic')
822 handler_name = Str('magic')
823 esc_strings = List([ESC_MAGIC])
823 esc_strings = List([ESC_MAGIC])
824
824
825 def handle(self, line_info):
825 def handle(self, line_info):
826 """Execute magic functions."""
826 """Execute magic functions."""
827 ifun = line_info.ifun
827 ifun = line_info.ifun
828 the_rest = line_info.the_rest
828 the_rest = line_info.the_rest
829 cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace,
829 cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace,
830 make_quoted_expr(ifun + " " + the_rest))
830 make_quoted_expr(ifun + " " + the_rest))
831 self.shell.log(line_info.line, cmd, line_info.continue_prompt)
831 self.shell.log(line_info.line, cmd, line_info.continue_prompt)
832 return cmd
832 return cmd
833
833
834
834
835 class AutoHandler(PrefilterHandler):
835 class AutoHandler(PrefilterHandler):
836
836
837 handler_name = Str('auto')
837 handler_name = Str('auto')
838 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
838 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
839
839
840 def handle(self, line_info):
840 def handle(self, line_info):
841 """Hande lines which can be auto-executed, quoting if requested."""
841 """Hande lines which can be auto-executed, quoting if requested."""
842 line = line_info.line
842 line = line_info.line
843 ifun = line_info.ifun
843 ifun = line_info.ifun
844 the_rest = line_info.the_rest
844 the_rest = line_info.the_rest
845 pre = line_info.pre
845 pre = line_info.pre
846 continue_prompt = line_info.continue_prompt
846 continue_prompt = line_info.continue_prompt
847 obj = line_info.ofind(self)['obj']
847 obj = line_info.ofind(self)['obj']
848 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
848 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
849
849
850 # This should only be active for single-line input!
850 # This should only be active for single-line input!
851 if continue_prompt:
851 if continue_prompt:
852 self.shell.log(line,line,continue_prompt)
852 self.shell.log(line,line,continue_prompt)
853 return line
853 return line
854
854
855 force_auto = isinstance(obj, IPyAutocall)
855 force_auto = isinstance(obj, IPyAutocall)
856 auto_rewrite = True
856 auto_rewrite = True
857
857
858 if pre == ESC_QUOTE:
858 if pre == ESC_QUOTE:
859 # Auto-quote splitting on whitespace
859 # Auto-quote splitting on whitespace
860 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
860 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
861 elif pre == ESC_QUOTE2:
861 elif pre == ESC_QUOTE2:
862 # Auto-quote whole string
862 # Auto-quote whole string
863 newcmd = '%s("%s")' % (ifun,the_rest)
863 newcmd = '%s("%s")' % (ifun,the_rest)
864 elif pre == ESC_PAREN:
864 elif pre == ESC_PAREN:
865 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
865 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
866 else:
866 else:
867 # Auto-paren.
867 # Auto-paren.
868 # We only apply it to argument-less calls if the autocall
868 # We only apply it to argument-less calls if the autocall
869 # parameter is set to 2. We only need to check that autocall is <
869 # parameter is set to 2. We only need to check that autocall is <
870 # 2, since this function isn't called unless it's at least 1.
870 # 2, since this function isn't called unless it's at least 1.
871 if not the_rest and (self.shell.autocall < 2) and not force_auto:
871 if not the_rest and (self.shell.autocall < 2) and not force_auto:
872 newcmd = '%s %s' % (ifun,the_rest)
872 newcmd = '%s %s' % (ifun,the_rest)
873 auto_rewrite = False
873 auto_rewrite = False
874 else:
874 else:
875 if not force_auto and the_rest.startswith('['):
875 if not force_auto and the_rest.startswith('['):
876 if hasattr(obj,'__getitem__'):
876 if hasattr(obj,'__getitem__'):
877 # Don't autocall in this case: item access for an object
877 # Don't autocall in this case: item access for an object
878 # which is BOTH callable and implements __getitem__.
878 # which is BOTH callable and implements __getitem__.
879 newcmd = '%s %s' % (ifun,the_rest)
879 newcmd = '%s %s' % (ifun,the_rest)
880 auto_rewrite = False
880 auto_rewrite = False
881 else:
881 else:
882 # if the object doesn't support [] access, go ahead and
882 # if the object doesn't support [] access, go ahead and
883 # autocall
883 # autocall
884 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
884 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
885 elif the_rest.endswith(';'):
885 elif the_rest.endswith(';'):
886 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
886 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
887 else:
887 else:
888 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
888 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
889
889
890 if auto_rewrite:
890 if auto_rewrite:
891 rw = self.shell.outputcache.prompt1.auto_rewrite() + newcmd
891 rw = self.shell.outputcache.prompt1.auto_rewrite() + newcmd
892
892
893 try:
893 try:
894 # plain ascii works better w/ pyreadline, on some machines, so
894 # plain ascii works better w/ pyreadline, on some machines, so
895 # we use it and only print uncolored rewrite if we have unicode
895 # we use it and only print uncolored rewrite if we have unicode
896 rw = str(rw)
896 rw = str(rw)
897 print >>Term.cout, rw
897 print >>Term.cout, rw
898 except UnicodeEncodeError:
898 except UnicodeEncodeError:
899 print "-------------->" + newcmd
899 print "-------------->" + newcmd
900
900
901 # log what is now valid Python, not the actual user input (without the
901 # log what is now valid Python, not the actual user input (without the
902 # final newline)
902 # final newline)
903 self.shell.log(line,newcmd,continue_prompt)
903 self.shell.log(line,newcmd,continue_prompt)
904 return newcmd
904 return newcmd
905
905
906
906
907 class HelpHandler(PrefilterHandler):
907 class HelpHandler(PrefilterHandler):
908
908
909 handler_name = Str('help')
909 handler_name = Str('help')
910 esc_strings = List([ESC_HELP])
910 esc_strings = List([ESC_HELP])
911
911
912 def handle(self, line_info):
912 def handle(self, line_info):
913 """Try to get some help for the object.
913 """Try to get some help for the object.
914
914
915 obj? or ?obj -> basic information.
915 obj? or ?obj -> basic information.
916 obj?? or ??obj -> more details.
916 obj?? or ??obj -> more details.
917 """
917 """
918 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
918 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
919 line = line_info.line
919 line = line_info.line
920 # We need to make sure that we don't process lines which would be
920 # We need to make sure that we don't process lines which would be
921 # otherwise valid python, such as "x=1 # what?"
921 # otherwise valid python, such as "x=1 # what?"
922 try:
922 try:
923 codeop.compile_command(line)
923 codeop.compile_command(line)
924 except SyntaxError:
924 except SyntaxError:
925 # We should only handle as help stuff which is NOT valid syntax
925 # We should only handle as help stuff which is NOT valid syntax
926 if line[0]==ESC_HELP:
926 if line[0]==ESC_HELP:
927 line = line[1:]
927 line = line[1:]
928 elif line[-1]==ESC_HELP:
928 elif line[-1]==ESC_HELP:
929 line = line[:-1]
929 line = line[:-1]
930 self.shell.log(line, '#?'+line, line_info.continue_prompt)
930 self.shell.log(line, '#?'+line, line_info.continue_prompt)
931 if line:
931 if line:
932 #print 'line:<%r>' % line # dbg
932 #print 'line:<%r>' % line # dbg
933 self.shell.magic_pinfo(line)
933 self.shell.magic_pinfo(line)
934 else:
934 else:
935 page(self.shell.usage, screen_lines=self.shell.usable_screen_length)
935 page(self.shell.usage, screen_lines=self.shell.usable_screen_length)
936 return '' # Empty string is needed here!
936 return '' # Empty string is needed here!
937 except:
937 except:
938 raise
938 raise
939 # Pass any other exceptions through to the normal handler
939 # Pass any other exceptions through to the normal handler
940 return normal_handler.handle(line_info)
940 return normal_handler.handle(line_info)
941 else:
941 else:
942 raise
942 raise
943 # If the code compiles ok, we should handle it normally
943 # If the code compiles ok, we should handle it normally
944 return normal_handler.handle(line_info)
944 return normal_handler.handle(line_info)
945
945
946
946
947 class EmacsHandler(PrefilterHandler):
947 class EmacsHandler(PrefilterHandler):
948
948
949 handler_name = Str('emacs')
949 handler_name = Str('emacs')
950 esc_strings = List([])
950 esc_strings = List([])
951
951
952 def handle(self, line_info):
952 def handle(self, line_info):
953 """Handle input lines marked by python-mode."""
953 """Handle input lines marked by python-mode."""
954
954
955 # Currently, nothing is done. Later more functionality can be added
955 # Currently, nothing is done. Later more functionality can be added
956 # here if needed.
956 # here if needed.
957
957
958 # The input cache shouldn't be updated
958 # The input cache shouldn't be updated
959 return line_info.line
959 return line_info.line
960
960
961
961
962 #-----------------------------------------------------------------------------
962 #-----------------------------------------------------------------------------
963 # Defaults
963 # Defaults
964 #-----------------------------------------------------------------------------
964 #-----------------------------------------------------------------------------
965
965
966
966
967 _default_transformers = [
967 _default_transformers = [
968 AssignSystemTransformer,
968 AssignSystemTransformer,
969 AssignMagicTransformer
969 AssignMagicTransformer
970 ]
970 ]
971
971
972 _default_checkers = [
972 _default_checkers = [
973 EmacsChecker,
973 EmacsChecker,
974 ShellEscapeChecker,
974 ShellEscapeChecker,
975 IPyAutocallChecker,
975 IPyAutocallChecker,
976 MultiLineMagicChecker,
976 MultiLineMagicChecker,
977 EscCharsChecker,
977 EscCharsChecker,
978 AssignmentChecker,
978 AssignmentChecker,
979 AutoMagicChecker,
979 AutoMagicChecker,
980 AliasChecker,
980 AliasChecker,
981 PythonOpsChecker,
981 PythonOpsChecker,
982 AutocallChecker
982 AutocallChecker
983 ]
983 ]
984
984
985 _default_handlers = [
985 _default_handlers = [
986 PrefilterHandler,
986 PrefilterHandler,
987 AliasHandler,
987 AliasHandler,
988 ShellEscapeHandler,
988 ShellEscapeHandler,
989 MagicHandler,
989 MagicHandler,
990 AutoHandler,
990 AutoHandler,
991 HelpHandler,
991 HelpHandler,
992 EmacsHandler
992 EmacsHandler
993 ]
993 ]
994
994
@@ -1,27 +1,29 b''
1 """Simple script to instantiate a class for testing %run"""
1 """Simple script to be run *twice*, to check reference counting bugs.
2
2
3 import sys
3 See test_run for details."""
4
5 # An external test will check that calls to f() work after %run
6 class foo: pass
7
4
8 def f():
5 import sys
9 return foo()
10
6
11 # We also want to ensure that while objects remain available for immediate
7 # We want to ensure that while objects remain available for immediate access,
12 # access, objects from *previous* runs of the same script get collected, to
8 # objects from *previous* runs of the same script get collected, to avoid
13 # avoid accumulating massive amounts of old references.
9 # accumulating massive amounts of old references.
14 class C(object):
10 class C(object):
15 def __init__(self,name):
11 def __init__(self,name):
16 self.name = name
12 self.name = name
17
13
18 def __del__(self):
14 def __del__(self):
19 print 'tclass.py: deleting object:',self.name
15 print 'tclass.py: deleting object:',self.name
20
16
17
21 try:
18 try:
22 name = sys.argv[1]
19 name = sys.argv[1]
23 except IndexError:
20 except IndexError:
24 pass
21 pass
25 else:
22 else:
26 if name.startswith('C'):
23 if name.startswith('C'):
27 c = C(name)
24 c = C(name)
25
26 #print >> sys.stderr, "ARGV:", sys.argv # dbg
27 # This print statement is NOT debugging, we're making the check on a completely
28 # separate process so we verify by capturing stdout.
29 print 'ARGV 1-:', sys.argv[1:]
@@ -1,347 +1,191 b''
1 """Tests for various magic functions.
1 """Tests for various magic functions.
2
2
3 Needs to be run by nose (to make ipython session available).
3 Needs to be run by nose (to make ipython session available).
4 """
4 """
5 from __future__ import absolute_import
5
6
7 #-----------------------------------------------------------------------------
8 # Imports
9 #-----------------------------------------------------------------------------
10
11 # stdlib
6 import os
12 import os
7 import sys
13 import sys
8 import tempfile
14 import tempfile
9 import types
15 import types
10 from cStringIO import StringIO
16 from cStringIO import StringIO
11
17
18 # third-party
12 import nose.tools as nt
19 import nose.tools as nt
13
20
21 # our own
22 from IPython.utils import genutils
14 from IPython.utils.platutils import find_cmd, get_long_path_name
23 from IPython.utils.platutils import find_cmd, get_long_path_name
15 from IPython.testing import decorators as dec
24 from IPython.testing import decorators as dec
16 from IPython.testing import tools as tt
25 from IPython.testing import tools as tt
17
26
18 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
19 # Test functions begin
28 # Test functions begin
29 #-----------------------------------------------------------------------------
20
30
21 def test_rehashx():
31 def test_rehashx():
22 # clear up everything
32 # clear up everything
23 _ip = get_ipython()
33 _ip = get_ipython()
24 _ip.alias_manager.alias_table.clear()
34 _ip.alias_manager.alias_table.clear()
25 del _ip.db['syscmdlist']
35 del _ip.db['syscmdlist']
26
36
27 _ip.magic('rehashx')
37 _ip.magic('rehashx')
28 # Practically ALL ipython development systems will have more than 10 aliases
38 # Practically ALL ipython development systems will have more than 10 aliases
29
39
30 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
40 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
31 for key, val in _ip.alias_manager.alias_table.items():
41 for key, val in _ip.alias_manager.alias_table.items():
32 # we must strip dots from alias names
42 # we must strip dots from alias names
33 nt.assert_true('.' not in key)
43 nt.assert_true('.' not in key)
34
44
35 # rehashx must fill up syscmdlist
45 # rehashx must fill up syscmdlist
36 scoms = _ip.db['syscmdlist']
46 scoms = _ip.db['syscmdlist']
37 yield (nt.assert_true, len(scoms) > 10)
47 yield (nt.assert_true, len(scoms) > 10)
38
48
39
49
40 def doctest_hist_f():
50 def doctest_hist_f():
41 """Test %hist -f with temporary filename.
51 """Test %hist -f with temporary filename.
42
52
43 In [9]: import tempfile
53 In [9]: import tempfile
44
54
45 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
55 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
46
56
47 In [11]: %hist -n -f $tfile 3
57 In [11]: %hist -n -f $tfile 3
48 """
58 """
49
59
50
60
51 def doctest_hist_r():
61 def doctest_hist_r():
52 """Test %hist -r
62 """Test %hist -r
53
63
54 XXX - This test is not recording the output correctly. Not sure why...
64 XXX - This test is not recording the output correctly. Not sure why...
55
65
56 In [20]: 'hist' in _ip.lsmagic()
66 In [20]: 'hist' in _ip.lsmagic()
57 Out[20]: True
67 Out[20]: True
58
68
59 In [6]: x=1
69 In [6]: x=1
60
70
61 In [7]: %hist -n -r 2
71 In [7]: %hist -n -r 2
62 x=1 # random
72 x=1 # random
63 hist -n -r 2 # random
73 hist -n -r 2 # random
64 """
74 """
65
75
66 # This test is known to fail on win32.
67 # See ticket https://bugs.launchpad.net/bugs/366334
68 def test_obj_del():
69 _ip = get_ipython()
70 """Test that object's __del__ methods are called on exit."""
71 test_dir = os.path.dirname(__file__)
72 del_file = os.path.join(test_dir,'obj_del.py')
73 ipython_cmd = find_cmd('ipython')
74 out = _ip.getoutput('%s %s' % (ipython_cmd, del_file))
75 nt.assert_equals(out,'obj_del.py: object A deleted')
76
77
76
78 def test_shist():
77 def test_shist():
79 # Simple tests of ShadowHist class - test generator.
78 # Simple tests of ShadowHist class - test generator.
80 import os, shutil, tempfile
79 import os, shutil, tempfile
81
80
82 from IPython.utils import pickleshare
81 from IPython.utils import pickleshare
83 from IPython.core.history import ShadowHist
82 from IPython.core.history import ShadowHist
84
83
85 tfile = tempfile.mktemp('','tmp-ipython-')
84 tfile = tempfile.mktemp('','tmp-ipython-')
86
85
87 db = pickleshare.PickleShareDB(tfile)
86 db = pickleshare.PickleShareDB(tfile)
88 s = ShadowHist(db)
87 s = ShadowHist(db)
89 s.add('hello')
88 s.add('hello')
90 s.add('world')
89 s.add('world')
91 s.add('hello')
90 s.add('hello')
92 s.add('hello')
91 s.add('hello')
93 s.add('karhu')
92 s.add('karhu')
94
93
95 yield nt.assert_equals,s.all(),[(1, 'hello'), (2, 'world'), (3, 'karhu')]
94 yield nt.assert_equals,s.all(),[(1, 'hello'), (2, 'world'), (3, 'karhu')]
96
95
97 yield nt.assert_equal,s.get(2),'world'
96 yield nt.assert_equal,s.get(2),'world'
98
97
99 shutil.rmtree(tfile)
98 shutil.rmtree(tfile)
100
99
101
100
102 # XXX failing for now, until we get clearcmd out of quarantine. But we should
101 # XXX failing for now, until we get clearcmd out of quarantine. But we should
103 # fix this and revert the skip to happen only if numpy is not around.
102 # fix this and revert the skip to happen only if numpy is not around.
104 #@dec.skipif_not_numpy
103 #@dec.skipif_not_numpy
105 @dec.skipknownfailure
104 @dec.skipknownfailure
106 def test_numpy_clear_array_undec():
105 def test_numpy_clear_array_undec():
107 from IPython.extensions import clearcmd
106 from IPython.extensions import clearcmd
108
107
109 _ip.ex('import numpy as np')
108 _ip.ex('import numpy as np')
110 _ip.ex('a = np.empty(2)')
109 _ip.ex('a = np.empty(2)')
111 yield (nt.assert_true, 'a' in _ip.user_ns)
110 yield (nt.assert_true, 'a' in _ip.user_ns)
112 _ip.magic('clear array')
111 _ip.magic('clear array')
113 yield (nt.assert_false, 'a' in _ip.user_ns)
112 yield (nt.assert_false, 'a' in _ip.user_ns)
114
113
115
114
116 @dec.skip()
117 def test_fail_dec(*a,**k):
118 yield nt.assert_true, False
119
120 @dec.skip('This one shouldn not run')
121 def test_fail_dec2(*a,**k):
122 yield nt.assert_true, False
123
124 @dec.skipknownfailure
125 def test_fail_dec3(*a,**k):
126 yield nt.assert_true, False
127
128
129 def doctest_refbug():
130 """Very nasty problem with references held by multiple runs of a script.
131 See: https://bugs.launchpad.net/ipython/+bug/269966
132
133 In [1]: _ip.clear_main_mod_cache()
134
135 In [2]: run refbug
136
137 In [3]: call_f()
138 lowercased: hello
139
140 In [4]: run refbug
141
142 In [5]: call_f()
143 lowercased: hello
144 lowercased: hello
145 """
146
147 #-----------------------------------------------------------------------------
148 # Tests for %run
149 #-----------------------------------------------------------------------------
150
151 # %run is critical enough that it's a good idea to have a solid collection of
152 # tests for it, some as doctests and some as normal tests.
153
154 def doctest_run_ns():
155 """Classes declared %run scripts must be instantiable afterwards.
156
157 In [11]: run tclass foo
158
159 In [12]: isinstance(f(),foo)
160 Out[12]: True
161 """
162
163
164 def doctest_run_ns2():
165 """Classes declared %run scripts must be instantiable afterwards.
166
167 In [4]: run tclass C-first_pass
168
169 In [5]: run tclass C-second_pass
170 tclass.py: deleting object: C-first_pass
171 """
172
173 def doctest_run_builtins():
174 """Check that %run doesn't damage __builtins__ via a doctest.
175
176 This is similar to the test_run_builtins, but I want *both* forms of the
177 test to catch any possible glitches in our testing machinery, since that
178 modifies %run somewhat. So for this, we have both a normal test (below)
179 and a doctest (this one).
180
181 In [1]: import tempfile
182
183 In [2]: bid1 = id(__builtins__)
184
185 In [3]: fname = tempfile.mkstemp()[1]
186
187 In [3]: f = open(fname,'w')
188
189 In [4]: f.write('pass\\n')
190
191 In [5]: f.flush()
192
193 In [6]: print type(__builtins__)
194 <type 'module'>
195
196 In [7]: %run "$fname"
197
198 In [7]: f.close()
199
200 In [8]: bid2 = id(__builtins__)
201
202 In [9]: print type(__builtins__)
203 <type 'module'>
204
205 In [10]: bid1 == bid2
206 Out[10]: True
207
208 In [12]: try:
209 ....: os.unlink(fname)
210 ....: except:
211 ....: pass
212 ....:
213 """
214
215 # For some tests, it will be handy to organize them in a class with a common
216 # setup that makes a temp file
217
218 class TestMagicRun(object):
219
220 def setup(self):
221 """Make a valid python temp file."""
222 fname = tempfile.mkstemp('.py')[1]
223 f = open(fname,'w')
224 f.write('pass\n')
225 f.flush()
226 self.tmpfile = f
227 self.fname = fname
228
229 def run_tmpfile(self):
230 _ip = get_ipython()
231 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
232 # See below and ticket https://bugs.launchpad.net/bugs/366353
233 _ip.magic('run "%s"' % self.fname)
234
235 def test_builtins_id(self):
236 """Check that %run doesn't damage __builtins__ """
237 _ip = get_ipython()
238 # Test that the id of __builtins__ is not modified by %run
239 bid1 = id(_ip.user_ns['__builtins__'])
240 self.run_tmpfile()
241 bid2 = id(_ip.user_ns['__builtins__'])
242 tt.assert_equals(bid1, bid2)
243
244 def test_builtins_type(self):
245 """Check that the type of __builtins__ doesn't change with %run.
246
247 However, the above could pass if __builtins__ was already modified to
248 be a dict (it should be a module) by a previous use of %run. So we
249 also check explicitly that it really is a module:
250 """
251 _ip = get_ipython()
252 self.run_tmpfile()
253 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
254
255 def test_prompts(self):
256 """Test that prompts correctly generate after %run"""
257 self.run_tmpfile()
258 _ip = get_ipython()
259 p2 = str(_ip.outputcache.prompt2).strip()
260 nt.assert_equals(p2[:3], '...')
261
262 def teardown(self):
263 self.tmpfile.close()
264 try:
265 os.unlink(self.fname)
266 except:
267 # On Windows, even though we close the file, we still can't delete
268 # it. I have no clue why
269 pass
270
271 # Multiple tests for clipboard pasting
115 # Multiple tests for clipboard pasting
272 @dec.parametric
116 @dec.parametric
273 def test_paste():
117 def test_paste():
274 _ip = get_ipython()
118 _ip = get_ipython()
275 def paste(txt, flags='-q'):
119 def paste(txt, flags='-q'):
276 """Paste input text, by default in quiet mode"""
120 """Paste input text, by default in quiet mode"""
277 hooks.clipboard_get = lambda : txt
121 hooks.clipboard_get = lambda : txt
278 _ip.magic('paste '+flags)
122 _ip.magic('paste '+flags)
279
123
280 # Inject fake clipboard hook but save original so we can restore it later
124 # Inject fake clipboard hook but save original so we can restore it later
281 hooks = _ip.hooks
125 hooks = _ip.hooks
282 user_ns = _ip.user_ns
126 user_ns = _ip.user_ns
283 original_clip = hooks.clipboard_get
127 original_clip = hooks.clipboard_get
284
128
285 try:
129 try:
286 # This try/except with an emtpy except clause is here only because
130 # This try/except with an emtpy except clause is here only because
287 # try/yield/finally is invalid syntax in Python 2.4. This will be
131 # try/yield/finally is invalid syntax in Python 2.4. This will be
288 # removed when we drop 2.4-compatibility, and the emtpy except below
132 # removed when we drop 2.4-compatibility, and the emtpy except below
289 # will be changed to a finally.
133 # will be changed to a finally.
290
134
291 # Run tests with fake clipboard function
135 # Run tests with fake clipboard function
292 user_ns.pop('x', None)
136 user_ns.pop('x', None)
293 paste('x=1')
137 paste('x=1')
294 yield nt.assert_equal(user_ns['x'], 1)
138 yield nt.assert_equal(user_ns['x'], 1)
295
139
296 user_ns.pop('x', None)
140 user_ns.pop('x', None)
297 paste('>>> x=2')
141 paste('>>> x=2')
298 yield nt.assert_equal(user_ns['x'], 2)
142 yield nt.assert_equal(user_ns['x'], 2)
299
143
300 paste("""
144 paste("""
301 >>> x = [1,2,3]
145 >>> x = [1,2,3]
302 >>> y = []
146 >>> y = []
303 >>> for i in x:
147 >>> for i in x:
304 ... y.append(i**2)
148 ... y.append(i**2)
305 ...
149 ...
306 """)
150 """)
307 yield nt.assert_equal(user_ns['x'], [1,2,3])
151 yield nt.assert_equal(user_ns['x'], [1,2,3])
308 yield nt.assert_equal(user_ns['y'], [1,4,9])
152 yield nt.assert_equal(user_ns['y'], [1,4,9])
309
153
310 # Now, test that paste -r works
154 # Now, test that paste -r works
311 user_ns.pop('x', None)
155 user_ns.pop('x', None)
312 yield nt.assert_false('x' in user_ns)
156 yield nt.assert_false('x' in user_ns)
313 _ip.magic('paste -r')
157 _ip.magic('paste -r')
314 yield nt.assert_equal(user_ns['x'], [1,2,3])
158 yield nt.assert_equal(user_ns['x'], [1,2,3])
315
159
316 # Also test paste echoing, by temporarily faking the writer
160 # Also test paste echoing, by temporarily faking the writer
317 w = StringIO()
161 w = StringIO()
318 writer = _ip.write
162 writer = _ip.write
319 _ip.write = w.write
163 _ip.write = w.write
320 code = """
164 code = """
321 a = 100
165 a = 100
322 b = 200"""
166 b = 200"""
323 try:
167 try:
324 paste(code,'')
168 paste(code,'')
325 out = w.getvalue()
169 out = w.getvalue()
326 finally:
170 finally:
327 _ip.write = writer
171 _ip.write = writer
328 yield nt.assert_equal(user_ns['a'], 100)
172 yield nt.assert_equal(user_ns['a'], 100)
329 yield nt.assert_equal(user_ns['b'], 200)
173 yield nt.assert_equal(user_ns['b'], 200)
330 yield nt.assert_equal(out, code+"\n## -- End pasted text --\n")
174 yield nt.assert_equal(out, code+"\n## -- End pasted text --\n")
331
175
332 finally:
176 finally:
333 # This should be in a finally clause, instead of the bare except above.
177 # This should be in a finally clause, instead of the bare except above.
334 # Restore original hook
178 # Restore original hook
335 hooks.clipboard_get = original_clip
179 hooks.clipboard_get = original_clip
336
180
337
181
338 def test_time():
182 def test_time():
339 _ip.magic('time None')
183 _ip.magic('time None')
340
184
341
185
342 def doctest_time():
186 def doctest_time():
343 """
187 """
344 In [10]: %time None
188 In [10]: %time None
345 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
189 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
346 Wall time: 0.00 s
190 Wall time: 0.00 s
347 """
191 """
@@ -1,310 +1,313 b''
1 """Decorators for labeling test objects.
1 """Decorators for labeling test objects.
2
2
3 Decorators that merely return a modified version of the original function
3 Decorators that merely return a modified version of the original function
4 object are straightforward. Decorators that return a new function object need
4 object are straightforward. Decorators that return a new function object need
5 to use nose.tools.make_decorator(original_function)(decorator) in returning the
5 to use nose.tools.make_decorator(original_function)(decorator) in returning the
6 decorator, in order to preserve metadata such as function name, setup and
6 decorator, in order to preserve metadata such as function name, setup and
7 teardown functions and so on - see nose.tools for more information.
7 teardown functions and so on - see nose.tools for more information.
8
8
9 This module provides a set of useful decorators meant to be ready to use in
9 This module provides a set of useful decorators meant to be ready to use in
10 your own tests. See the bottom of the file for the ready-made ones, and if you
10 your own tests. See the bottom of the file for the ready-made ones, and if you
11 find yourself writing a new one that may be of generic use, add it here.
11 find yourself writing a new one that may be of generic use, add it here.
12
12
13 Included decorators:
13 Included decorators:
14
14
15
15
16 Lightweight testing that remains unittest-compatible.
16 Lightweight testing that remains unittest-compatible.
17
17
18 - @parametric, for parametric test support that is vastly easier to use than
18 - @parametric, for parametric test support that is vastly easier to use than
19 nose's for debugging. With ours, if a test fails, the stack under inspection
19 nose's for debugging. With ours, if a test fails, the stack under inspection
20 is that of the test and not that of the test framework.
20 is that of the test and not that of the test framework.
21
21
22 - An @as_unittest decorator can be used to tag any normal parameter-less
22 - An @as_unittest decorator can be used to tag any normal parameter-less
23 function as a unittest TestCase. Then, both nose and normal unittest will
23 function as a unittest TestCase. Then, both nose and normal unittest will
24 recognize it as such. This will make it easier to migrate away from Nose if
24 recognize it as such. This will make it easier to migrate away from Nose if
25 we ever need/want to while maintaining very lightweight tests.
25 we ever need/want to while maintaining very lightweight tests.
26
26
27 NOTE: This file contains IPython-specific decorators and imports the
27 NOTE: This file contains IPython-specific decorators and imports the
28 numpy.testing.decorators file, which we've copied verbatim. Any of our own
28 numpy.testing.decorators file, which we've copied verbatim. Any of our own
29 code will be added at the bottom if we end up extending this.
29 code will be added at the bottom if we end up extending this.
30
30
31 Authors
31 Authors
32 -------
32 -------
33
33
34 - Fernando Perez <Fernando.Perez@berkeley.edu>
34 - Fernando Perez <Fernando.Perez@berkeley.edu>
35 """
35 """
36
36
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38 # Copyright (C) 2009-2010 The IPython Development Team
38 # Copyright (C) 2009-2010 The IPython Development Team
39 #
39 #
40 # Distributed under the terms of the BSD License. The full license is in
40 # Distributed under the terms of the BSD License. The full license is in
41 # the file COPYING, distributed as part of this software.
41 # the file COPYING, distributed as part of this software.
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45 # Imports
45 # Imports
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47
47
48 # Stdlib imports
48 # Stdlib imports
49 import inspect
49 import inspect
50 import sys
50 import sys
51 import unittest
51 import unittest
52
52
53 # Third-party imports
53 # Third-party imports
54
54
55 # This is Michele Simionato's decorator module, kept verbatim.
55 # This is Michele Simionato's decorator module, kept verbatim.
56 from IPython.external.decorator import decorator, update_wrapper
56 from IPython.external.decorator import decorator, update_wrapper
57
57
58 # Our own modules
58 # Our own modules
59 import nosepatch # monkeypatch nose
59 import nosepatch # monkeypatch nose
60
60
61 # We already have python3-compliant code for parametric tests
61 # We already have python3-compliant code for parametric tests
62 if sys.version[0]=='2':
62 if sys.version[0]=='2':
63 from _paramtestpy2 import parametric
63 from _paramtestpy2 import parametric
64 else:
64 else:
65 from _paramtestpy3 import parametric
65 from _paramtestpy3 import parametric
66
66
67 # Expose the unittest-driven decorators
68 from ipunittest import ipdoctest, ipdocstring
69
67 # Grab the numpy-specific decorators which we keep in a file that we
70 # Grab the numpy-specific decorators which we keep in a file that we
68 # occasionally update from upstream: decorators.py is a copy of
71 # occasionally update from upstream: decorators.py is a copy of
69 # numpy.testing.decorators, we expose all of it here.
72 # numpy.testing.decorators, we expose all of it here.
70 from IPython.external.decorators import *
73 from IPython.external.decorators import *
71
74
72 #-----------------------------------------------------------------------------
75 #-----------------------------------------------------------------------------
73 # Classes and functions
76 # Classes and functions
74 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
75
78
76 # Simple example of the basic idea
79 # Simple example of the basic idea
77 def as_unittest(func):
80 def as_unittest(func):
78 """Decorator to make a simple function into a normal test via unittest."""
81 """Decorator to make a simple function into a normal test via unittest."""
79 class Tester(unittest.TestCase):
82 class Tester(unittest.TestCase):
80 def test(self):
83 def test(self):
81 func()
84 func()
82
85
83 Tester.__name__ = func.__name__
86 Tester.__name__ = func.__name__
84
87
85 return Tester
88 return Tester
86
89
87 # Utility functions
90 # Utility functions
88
91
89 def apply_wrapper(wrapper,func):
92 def apply_wrapper(wrapper,func):
90 """Apply a wrapper to a function for decoration.
93 """Apply a wrapper to a function for decoration.
91
94
92 This mixes Michele Simionato's decorator tool with nose's make_decorator,
95 This mixes Michele Simionato's decorator tool with nose's make_decorator,
93 to apply a wrapper in a decorator so that all nose attributes, as well as
96 to apply a wrapper in a decorator so that all nose attributes, as well as
94 function signature and other properties, survive the decoration cleanly.
97 function signature and other properties, survive the decoration cleanly.
95 This will ensure that wrapped functions can still be well introspected via
98 This will ensure that wrapped functions can still be well introspected via
96 IPython, for example.
99 IPython, for example.
97 """
100 """
98 import nose.tools
101 import nose.tools
99
102
100 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
103 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
101
104
102
105
103 def make_label_dec(label,ds=None):
106 def make_label_dec(label,ds=None):
104 """Factory function to create a decorator that applies one or more labels.
107 """Factory function to create a decorator that applies one or more labels.
105
108
106 Parameters
109 Parameters
107 ----------
110 ----------
108 label : string or sequence
111 label : string or sequence
109 One or more labels that will be applied by the decorator to the functions
112 One or more labels that will be applied by the decorator to the functions
110 it decorates. Labels are attributes of the decorated function with their
113 it decorates. Labels are attributes of the decorated function with their
111 value set to True.
114 value set to True.
112
115
113 ds : string
116 ds : string
114 An optional docstring for the resulting decorator. If not given, a
117 An optional docstring for the resulting decorator. If not given, a
115 default docstring is auto-generated.
118 default docstring is auto-generated.
116
119
117 Returns
120 Returns
118 -------
121 -------
119 A decorator.
122 A decorator.
120
123
121 Examples
124 Examples
122 --------
125 --------
123
126
124 A simple labeling decorator:
127 A simple labeling decorator:
125 >>> slow = make_label_dec('slow')
128 >>> slow = make_label_dec('slow')
126 >>> print slow.__doc__
129 >>> print slow.__doc__
127 Labels a test as 'slow'.
130 Labels a test as 'slow'.
128
131
129 And one that uses multiple labels and a custom docstring:
132 And one that uses multiple labels and a custom docstring:
130 >>> rare = make_label_dec(['slow','hard'],
133 >>> rare = make_label_dec(['slow','hard'],
131 ... "Mix labels 'slow' and 'hard' for rare tests.")
134 ... "Mix labels 'slow' and 'hard' for rare tests.")
132 >>> print rare.__doc__
135 >>> print rare.__doc__
133 Mix labels 'slow' and 'hard' for rare tests.
136 Mix labels 'slow' and 'hard' for rare tests.
134
137
135 Now, let's test using this one:
138 Now, let's test using this one:
136 >>> @rare
139 >>> @rare
137 ... def f(): pass
140 ... def f(): pass
138 ...
141 ...
139 >>>
142 >>>
140 >>> f.slow
143 >>> f.slow
141 True
144 True
142 >>> f.hard
145 >>> f.hard
143 True
146 True
144 """
147 """
145
148
146 if isinstance(label,basestring):
149 if isinstance(label,basestring):
147 labels = [label]
150 labels = [label]
148 else:
151 else:
149 labels = label
152 labels = label
150
153
151 # Validate that the given label(s) are OK for use in setattr() by doing a
154 # Validate that the given label(s) are OK for use in setattr() by doing a
152 # dry run on a dummy function.
155 # dry run on a dummy function.
153 tmp = lambda : None
156 tmp = lambda : None
154 for label in labels:
157 for label in labels:
155 setattr(tmp,label,True)
158 setattr(tmp,label,True)
156
159
157 # This is the actual decorator we'll return
160 # This is the actual decorator we'll return
158 def decor(f):
161 def decor(f):
159 for label in labels:
162 for label in labels:
160 setattr(f,label,True)
163 setattr(f,label,True)
161 return f
164 return f
162
165
163 # Apply the user's docstring, or autogenerate a basic one
166 # Apply the user's docstring, or autogenerate a basic one
164 if ds is None:
167 if ds is None:
165 ds = "Labels a test as %r." % label
168 ds = "Labels a test as %r." % label
166 decor.__doc__ = ds
169 decor.__doc__ = ds
167
170
168 return decor
171 return decor
169
172
170
173
171 # Inspired by numpy's skipif, but uses the full apply_wrapper utility to
174 # Inspired by numpy's skipif, but uses the full apply_wrapper utility to
172 # preserve function metadata better and allows the skip condition to be a
175 # preserve function metadata better and allows the skip condition to be a
173 # callable.
176 # callable.
174 def skipif(skip_condition, msg=None):
177 def skipif(skip_condition, msg=None):
175 ''' Make function raise SkipTest exception if skip_condition is true
178 ''' Make function raise SkipTest exception if skip_condition is true
176
179
177 Parameters
180 Parameters
178 ----------
181 ----------
179 skip_condition : bool or callable.
182 skip_condition : bool or callable.
180 Flag to determine whether to skip test. If the condition is a
183 Flag to determine whether to skip test. If the condition is a
181 callable, it is used at runtime to dynamically make the decision. This
184 callable, it is used at runtime to dynamically make the decision. This
182 is useful for tests that may require costly imports, to delay the cost
185 is useful for tests that may require costly imports, to delay the cost
183 until the test suite is actually executed.
186 until the test suite is actually executed.
184 msg : string
187 msg : string
185 Message to give on raising a SkipTest exception
188 Message to give on raising a SkipTest exception
186
189
187 Returns
190 Returns
188 -------
191 -------
189 decorator : function
192 decorator : function
190 Decorator, which, when applied to a function, causes SkipTest
193 Decorator, which, when applied to a function, causes SkipTest
191 to be raised when the skip_condition was True, and the function
194 to be raised when the skip_condition was True, and the function
192 to be called normally otherwise.
195 to be called normally otherwise.
193
196
194 Notes
197 Notes
195 -----
198 -----
196 You will see from the code that we had to further decorate the
199 You will see from the code that we had to further decorate the
197 decorator with the nose.tools.make_decorator function in order to
200 decorator with the nose.tools.make_decorator function in order to
198 transmit function name, and various other metadata.
201 transmit function name, and various other metadata.
199 '''
202 '''
200
203
201 def skip_decorator(f):
204 def skip_decorator(f):
202 # Local import to avoid a hard nose dependency and only incur the
205 # Local import to avoid a hard nose dependency and only incur the
203 # import time overhead at actual test-time.
206 # import time overhead at actual test-time.
204 import nose
207 import nose
205
208
206 # Allow for both boolean or callable skip conditions.
209 # Allow for both boolean or callable skip conditions.
207 if callable(skip_condition):
210 if callable(skip_condition):
208 skip_val = lambda : skip_condition()
211 skip_val = lambda : skip_condition()
209 else:
212 else:
210 skip_val = lambda : skip_condition
213 skip_val = lambda : skip_condition
211
214
212 def get_msg(func,msg=None):
215 def get_msg(func,msg=None):
213 """Skip message with information about function being skipped."""
216 """Skip message with information about function being skipped."""
214 if msg is None: out = 'Test skipped due to test condition.'
217 if msg is None: out = 'Test skipped due to test condition.'
215 else: out = msg
218 else: out = msg
216 return "Skipping test: %s. %s" % (func.__name__,out)
219 return "Skipping test: %s. %s" % (func.__name__,out)
217
220
218 # We need to define *two* skippers because Python doesn't allow both
221 # We need to define *two* skippers because Python doesn't allow both
219 # return with value and yield inside the same function.
222 # return with value and yield inside the same function.
220 def skipper_func(*args, **kwargs):
223 def skipper_func(*args, **kwargs):
221 """Skipper for normal test functions."""
224 """Skipper for normal test functions."""
222 if skip_val():
225 if skip_val():
223 raise nose.SkipTest(get_msg(f,msg))
226 raise nose.SkipTest(get_msg(f,msg))
224 else:
227 else:
225 return f(*args, **kwargs)
228 return f(*args, **kwargs)
226
229
227 def skipper_gen(*args, **kwargs):
230 def skipper_gen(*args, **kwargs):
228 """Skipper for test generators."""
231 """Skipper for test generators."""
229 if skip_val():
232 if skip_val():
230 raise nose.SkipTest(get_msg(f,msg))
233 raise nose.SkipTest(get_msg(f,msg))
231 else:
234 else:
232 for x in f(*args, **kwargs):
235 for x in f(*args, **kwargs):
233 yield x
236 yield x
234
237
235 # Choose the right skipper to use when building the actual generator.
238 # Choose the right skipper to use when building the actual generator.
236 if nose.util.isgenerator(f):
239 if nose.util.isgenerator(f):
237 skipper = skipper_gen
240 skipper = skipper_gen
238 else:
241 else:
239 skipper = skipper_func
242 skipper = skipper_func
240
243
241 return nose.tools.make_decorator(f)(skipper)
244 return nose.tools.make_decorator(f)(skipper)
242
245
243 return skip_decorator
246 return skip_decorator
244
247
245 # A version with the condition set to true, common case just to attacha message
248 # A version with the condition set to true, common case just to attacha message
246 # to a skip decorator
249 # to a skip decorator
247 def skip(msg=None):
250 def skip(msg=None):
248 """Decorator factory - mark a test function for skipping from test suite.
251 """Decorator factory - mark a test function for skipping from test suite.
249
252
250 Parameters
253 Parameters
251 ----------
254 ----------
252 msg : string
255 msg : string
253 Optional message to be added.
256 Optional message to be added.
254
257
255 Returns
258 Returns
256 -------
259 -------
257 decorator : function
260 decorator : function
258 Decorator, which, when applied to a function, causes SkipTest
261 Decorator, which, when applied to a function, causes SkipTest
259 to be raised, with the optional message added.
262 to be raised, with the optional message added.
260 """
263 """
261
264
262 return skipif(True,msg)
265 return skipif(True,msg)
263
266
264
267
265 #-----------------------------------------------------------------------------
268 #-----------------------------------------------------------------------------
266 # Utility functions for decorators
269 # Utility functions for decorators
267 def numpy_not_available():
270 def numpy_not_available():
268 """Can numpy be imported? Returns true if numpy does NOT import.
271 """Can numpy be imported? Returns true if numpy does NOT import.
269
272
270 This is used to make a decorator to skip tests that require numpy to be
273 This is used to make a decorator to skip tests that require numpy to be
271 available, but delay the 'import numpy' to test execution time.
274 available, but delay the 'import numpy' to test execution time.
272 """
275 """
273 try:
276 try:
274 import numpy
277 import numpy
275 np_not_avail = False
278 np_not_avail = False
276 except ImportError:
279 except ImportError:
277 np_not_avail = True
280 np_not_avail = True
278
281
279 return np_not_avail
282 return np_not_avail
280
283
281 #-----------------------------------------------------------------------------
284 #-----------------------------------------------------------------------------
282 # Decorators for public use
285 # Decorators for public use
283
286
284 skip_doctest = make_label_dec('skip_doctest',
287 skip_doctest = make_label_dec('skip_doctest',
285 """Decorator - mark a function or method for skipping its doctest.
288 """Decorator - mark a function or method for skipping its doctest.
286
289
287 This decorator allows you to mark a function whose docstring you wish to
290 This decorator allows you to mark a function whose docstring you wish to
288 omit from testing, while preserving the docstring for introspection, help,
291 omit from testing, while preserving the docstring for introspection, help,
289 etc.""")
292 etc.""")
290
293
291 # Decorators to skip certain tests on specific platforms.
294 # Decorators to skip certain tests on specific platforms.
292 skip_win32 = skipif(sys.platform == 'win32',
295 skip_win32 = skipif(sys.platform == 'win32',
293 "This test does not run under Windows")
296 "This test does not run under Windows")
294 skip_linux = skipif(sys.platform == 'linux2',
297 skip_linux = skipif(sys.platform == 'linux2',
295 "This test does not run under Linux")
298 "This test does not run under Linux")
296 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
299 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
297
300
298
301
299 # Decorators to skip tests if not on specific platforms.
302 # Decorators to skip tests if not on specific platforms.
300 skip_if_not_win32 = skipif(sys.platform != 'win32',
303 skip_if_not_win32 = skipif(sys.platform != 'win32',
301 "This test only runs under Windows")
304 "This test only runs under Windows")
302 skip_if_not_linux = skipif(sys.platform != 'linux2',
305 skip_if_not_linux = skipif(sys.platform != 'linux2',
303 "This test only runs under Linux")
306 "This test only runs under Linux")
304 skip_if_not_osx = skipif(sys.platform != 'darwin',
307 skip_if_not_osx = skipif(sys.platform != 'darwin',
305 "This test only runs under OSX")
308 "This test only runs under OSX")
306
309
307 # Other skip decorators
310 # Other skip decorators
308 skipif_not_numpy = skipif(numpy_not_available,"This test requires numpy")
311 skipif_not_numpy = skipif(numpy_not_available,"This test requires numpy")
309
312
310 skipknownfailure = skip('This test is known to fail')
313 skipknownfailure = skip('This test is known to fail')
@@ -1,383 +1,393 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """IPython Test Suite Runner.
2 """IPython Test Suite Runner.
3
3
4 This module provides a main entry point to a user script to test IPython
4 This module provides a main entry point to a user script to test IPython
5 itself from the command line. There are two ways of running this script:
5 itself from the command line. There are two ways of running this script:
6
6
7 1. With the syntax `iptest all`. This runs our entire test suite by
7 1. With the syntax `iptest all`. This runs our entire test suite by
8 calling this script (with different arguments) or trial recursively. This
8 calling this script (with different arguments) or trial recursively. This
9 causes modules and package to be tested in different processes, using nose
9 causes modules and package to be tested in different processes, using nose
10 or trial where appropriate.
10 or trial where appropriate.
11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
12 the script simply calls nose, but with special command line flags and
12 the script simply calls nose, but with special command line flags and
13 plugins loaded.
13 plugins loaded.
14
14
15 For now, this script requires that both nose and twisted are installed. This
15 For now, this script requires that both nose and twisted are installed. This
16 will change in the future.
16 will change in the future.
17 """
17 """
18
18
19 from __future__ import absolute_import
20
19 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
20 # Module imports
22 # Module imports
21 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
22
24
23 import os
25 import os
24 import os.path as path
26 import os.path as path
25 import signal
27 import signal
26 import sys
28 import sys
27 import subprocess
29 import subprocess
28 import tempfile
30 import tempfile
29 import time
31 import time
30 import warnings
32 import warnings
31
33
32 import nose.plugins.builtin
34 import nose.plugins.builtin
33 from nose.core import TestProgram
35 from nose.core import TestProgram
34
36
35 from IPython.utils import genutils
37 from IPython.utils import genutils
36 from IPython.utils.platutils import find_cmd, FindCmdError
38 from IPython.utils.platutils import find_cmd, FindCmdError
39 from . import globalipapp
40 from .plugin.ipdoctest import IPythonDoctest
37
41
38 pjoin = path.join
42 pjoin = path.join
39
43
40 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
41 # Warnings control
45 # Warnings control
42 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
43 # Twisted generates annoying warnings with Python 2.6, as will do other code
47 # Twisted generates annoying warnings with Python 2.6, as will do other code
44 # that imports 'sets' as of today
48 # that imports 'sets' as of today
45 warnings.filterwarnings('ignore', 'the sets module is deprecated',
49 warnings.filterwarnings('ignore', 'the sets module is deprecated',
46 DeprecationWarning )
50 DeprecationWarning )
47
51
48 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
49 # Logic for skipping doctests
53 # Logic for skipping doctests
50 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
51
55
52 def test_for(mod):
56 def test_for(mod):
53 """Test to see if mod is importable."""
57 """Test to see if mod is importable."""
54 try:
58 try:
55 __import__(mod)
59 __import__(mod)
56 except ImportError:
60 except ImportError:
57 return False
61 return False
58 else:
62 else:
59 return True
63 return True
60
64
61 have_curses = test_for('_curses')
65 have_curses = test_for('_curses')
62 have_wx = test_for('wx')
66 have_wx = test_for('wx')
63 have_wx_aui = test_for('wx.aui')
67 have_wx_aui = test_for('wx.aui')
64 have_zi = test_for('zope.interface')
68 have_zi = test_for('zope.interface')
65 have_twisted = test_for('twisted')
69 have_twisted = test_for('twisted')
66 have_foolscap = test_for('foolscap')
70 have_foolscap = test_for('foolscap')
67 have_objc = test_for('objc')
71 have_objc = test_for('objc')
68 have_pexpect = test_for('pexpect')
72 have_pexpect = test_for('pexpect')
69 have_gtk = test_for('gtk')
73 have_gtk = test_for('gtk')
70 have_gobject = test_for('gobject')
74 have_gobject = test_for('gobject')
71
75
72
76
73 def make_exclude():
77 def make_exclude():
74
78
75 # For the IPythonDoctest plugin, we need to exclude certain patterns that
79 # For the IPythonDoctest plugin, we need to exclude certain patterns that
76 # cause testing problems. We should strive to minimize the number of
80 # cause testing problems. We should strive to minimize the number of
77 # skipped modules, since this means untested code. As the testing
81 # skipped modules, since this means untested code. As the testing
78 # machinery solidifies, this list should eventually become empty.
82 # machinery solidifies, this list should eventually become empty.
79 EXCLUDE = [pjoin('IPython', 'external'),
83
84 # Note that these exclusions only mean that the docstrings are not analyzed
85 # for examples to be run as tests, if there are other test functions in
86 # those modules, they do get run.
87 exclusions = [pjoin('IPython', 'external'),
80 pjoin('IPython', 'frontend', 'process', 'winprocess.py'),
88 pjoin('IPython', 'frontend', 'process', 'winprocess.py'),
81 pjoin('IPython_doctest_plugin'),
89 pjoin('IPython_doctest_plugin'),
82 pjoin('IPython', 'quarantine'),
90 pjoin('IPython', 'quarantine'),
83 pjoin('IPython', 'deathrow'),
91 pjoin('IPython', 'deathrow'),
84 pjoin('IPython', 'testing', 'attic'),
92 pjoin('IPython', 'testing', 'attic'),
85 pjoin('IPython', 'testing', 'tools'),
93 pjoin('IPython', 'testing', 'tools'),
86 pjoin('IPython', 'testing', 'mkdoctests'),
94 pjoin('IPython', 'testing', 'mkdoctests'),
87 pjoin('IPython', 'lib', 'inputhook')
95 pjoin('IPython', 'lib', 'inputhook')
88 ]
96 ]
89
97
90 if not have_wx:
98 if not have_wx:
91 EXCLUDE.append(pjoin('IPython', 'gui'))
99 exclusions.append(pjoin('IPython', 'gui'))
92 EXCLUDE.append(pjoin('IPython', 'frontend', 'wx'))
100 exclusions.append(pjoin('IPython', 'frontend', 'wx'))
93 EXCLUDE.append(pjoin('IPython', 'lib', 'inputhookwx'))
101 exclusions.append(pjoin('IPython', 'lib', 'inputhookwx'))
94
102
95 if not have_gtk or not have_gobject:
103 if not have_gtk or not have_gobject:
96 EXCLUDE.append(pjoin('IPython', 'lib', 'inputhookgtk'))
104 exclusions.append(pjoin('IPython', 'lib', 'inputhookgtk'))
97
105
98 if not have_wx_aui:
106 if not have_wx_aui:
99 EXCLUDE.append(pjoin('IPython', 'gui', 'wx', 'wxIPython'))
107 exclusions.append(pjoin('IPython', 'gui', 'wx', 'wxIPython'))
100
108
101 if not have_objc:
109 if not have_objc:
102 EXCLUDE.append(pjoin('IPython', 'frontend', 'cocoa'))
110 exclusions.append(pjoin('IPython', 'frontend', 'cocoa'))
103
111
104 if not sys.platform == 'win32':
112 if not sys.platform == 'win32':
105 EXCLUDE.append(pjoin('IPython', 'utils', 'platutils_win32'))
113 exclusions.append(pjoin('IPython', 'utils', 'platutils_win32'))
106
114
107 # These have to be skipped on win32 because the use echo, rm, cd, etc.
115 # These have to be skipped on win32 because the use echo, rm, cd, etc.
108 # See ticket https://bugs.launchpad.net/bugs/366982
116 # See ticket https://bugs.launchpad.net/bugs/366982
109 if sys.platform == 'win32':
117 if sys.platform == 'win32':
110 EXCLUDE.append(pjoin('IPython', 'testing', 'plugin', 'test_exampleip'))
118 exclusions.append(pjoin('IPython', 'testing', 'plugin', 'test_exampleip'))
111 EXCLUDE.append(pjoin('IPython', 'testing', 'plugin', 'dtexample'))
119 exclusions.append(pjoin('IPython', 'testing', 'plugin', 'dtexample'))
112
120
113 if not os.name == 'posix':
121 if not os.name == 'posix':
114 EXCLUDE.append(pjoin('IPython', 'utils', 'platutils_posix'))
122 exclusions.append(pjoin('IPython', 'utils', 'platutils_posix'))
115
123
116 if not have_pexpect:
124 if not have_pexpect:
117 EXCLUDE.append(pjoin('IPython', 'scripts', 'irunner'))
125 exclusions.append(pjoin('IPython', 'scripts', 'irunner'))
118
126
119 # This is scary. We still have things in frontend and testing that
127 # This is scary. We still have things in frontend and testing that
120 # are being tested by nose that use twisted. We need to rethink
128 # are being tested by nose that use twisted. We need to rethink
121 # how we are isolating dependencies in testing.
129 # how we are isolating dependencies in testing.
122 if not (have_twisted and have_zi and have_foolscap):
130 if not (have_twisted and have_zi and have_foolscap):
123 EXCLUDE.append(pjoin('IPython', 'frontend', 'asyncfrontendbase'))
131 exclusions.append(pjoin('IPython', 'frontend', 'asyncfrontendbase'))
124 EXCLUDE.append(pjoin('IPython', 'frontend', 'prefilterfrontend'))
132 exclusions.append(pjoin('IPython', 'frontend', 'prefilterfrontend'))
125 EXCLUDE.append(pjoin('IPython', 'frontend', 'frontendbase'))
133 exclusions.append(pjoin('IPython', 'frontend', 'frontendbase'))
126 EXCLUDE.append(pjoin('IPython', 'frontend', 'linefrontendbase'))
134 exclusions.append(pjoin('IPython', 'frontend', 'linefrontendbase'))
127 EXCLUDE.append(pjoin('IPython', 'frontend', 'tests',
135 exclusions.append(pjoin('IPython', 'frontend', 'tests',
128 'test_linefrontend'))
136 'test_linefrontend'))
129 EXCLUDE.append(pjoin('IPython', 'frontend', 'tests',
137 exclusions.append(pjoin('IPython', 'frontend', 'tests',
130 'test_frontendbase'))
138 'test_frontendbase'))
131 EXCLUDE.append(pjoin('IPython', 'frontend', 'tests',
139 exclusions.append(pjoin('IPython', 'frontend', 'tests',
132 'test_prefilterfrontend'))
140 'test_prefilterfrontend'))
133 EXCLUDE.append(pjoin('IPython', 'frontend', 'tests',
141 exclusions.append(pjoin('IPython', 'frontend', 'tests',
134 'test_asyncfrontendbase')),
142 'test_asyncfrontendbase')),
135 EXCLUDE.append(pjoin('IPython', 'testing', 'parametric'))
143 exclusions.append(pjoin('IPython', 'testing', 'parametric'))
136 EXCLUDE.append(pjoin('IPython', 'testing', 'util'))
144 exclusions.append(pjoin('IPython', 'testing', 'util'))
137
145
138 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
146 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
139 if sys.platform == 'win32':
147 if sys.platform == 'win32':
140 EXCLUDE = [s.replace('\\','\\\\') for s in EXCLUDE]
148 exclusions = [s.replace('\\','\\\\') for s in exclusions]
141
149
142 return EXCLUDE
150 return exclusions
143
151
144
152
145 #-----------------------------------------------------------------------------
153 #-----------------------------------------------------------------------------
146 # Functions and classes
154 # Functions and classes
147 #-----------------------------------------------------------------------------
155 #-----------------------------------------------------------------------------
148
156
149 class IPTester(object):
157 class IPTester(object):
150 """Call that calls iptest or trial in a subprocess.
158 """Call that calls iptest or trial in a subprocess.
151 """
159 """
152 #: string, name of test runner that will be called
160 #: string, name of test runner that will be called
153 runner = None
161 runner = None
154 #: list, parameters for test runner
162 #: list, parameters for test runner
155 params = None
163 params = None
156 #: list, arguments of system call to be made to call test runner
164 #: list, arguments of system call to be made to call test runner
157 call_args = None
165 call_args = None
158 #: list, process ids of subprocesses we start (for cleanup)
166 #: list, process ids of subprocesses we start (for cleanup)
159 pids = None
167 pids = None
160
168
161 def __init__(self,runner='iptest',params=None):
169 def __init__(self,runner='iptest',params=None):
162 """Create new test runner."""
170 """Create new test runner."""
163 if runner == 'iptest':
171 if runner == 'iptest':
164 # Find our own 'iptest' script OS-level entry point
172 # Find our own 'iptest' script OS-level entry point
165 try:
173 try:
166 iptest_path = find_cmd('iptest')
174 iptest_path = os.path.abspath(find_cmd('iptest'))
167 except FindCmdError:
175 except FindCmdError:
168 # Script not installed (may be the case for testing situations
176 # Script not installed (may be the case for testing situations
169 # that are running from a source tree only), pull from internal
177 # that are running from a source tree only), pull from internal
170 # path:
178 # path:
171 iptest_path = pjoin(genutils.get_ipython_package_dir(),
179 iptest_path = pjoin(genutils.get_ipython_package_dir(),
172 'scripts','iptest')
180 'scripts','iptest')
173 self.runner = [iptest_path,'-v']
181 self.runner = ['python', iptest_path, '-v']
174 else:
182 else:
175 self.runner = [find_cmd('trial')]
183 self.runner = ['python', os.path.abspath(find_cmd('trial'))]
176 if params is None:
184 if params is None:
177 params = []
185 params = []
178 if isinstance(params,str):
186 if isinstance(params,str):
179 params = [params]
187 params = [params]
180 self.params = params
188 self.params = params
181
189
182 # Assemble call
190 # Assemble call
183 self.call_args = self.runner+self.params
191 self.call_args = self.runner+self.params
184
192
185 # Store pids of anything we start to clean up on deletion, if possible
193 # Store pids of anything we start to clean up on deletion, if possible
186 # (on posix only, since win32 has no os.kill)
194 # (on posix only, since win32 has no os.kill)
187 self.pids = []
195 self.pids = []
188
196
189 if sys.platform == 'win32':
197 if sys.platform == 'win32':
190 def _run_cmd(self):
198 def _run_cmd(self):
191 # On Windows, use os.system instead of subprocess.call, because I
199 # On Windows, use os.system instead of subprocess.call, because I
192 # was having problems with subprocess and I just don't know enough
200 # was having problems with subprocess and I just don't know enough
193 # about win32 to debug this reliably. Os.system may be the 'old
201 # about win32 to debug this reliably. Os.system may be the 'old
194 # fashioned' way to do it, but it works just fine. If someone
202 # fashioned' way to do it, but it works just fine. If someone
195 # later can clean this up that's fine, as long as the tests run
203 # later can clean this up that's fine, as long as the tests run
196 # reliably in win32.
204 # reliably in win32.
197 return os.system(' '.join(self.call_args))
205 return os.system(' '.join(self.call_args))
198 else:
206 else:
199 def _run_cmd(self):
207 def _run_cmd(self):
200 subp = subprocess.Popen(self.call_args)
208 subp = subprocess.Popen(self.call_args)
201 self.pids.append(subp.pid)
209 self.pids.append(subp.pid)
202 # If this fails, the pid will be left in self.pids and cleaned up
210 # If this fails, the pid will be left in self.pids and cleaned up
203 # later, but if the wait call succeeds, then we can clear the
211 # later, but if the wait call succeeds, then we can clear the
204 # stored pid.
212 # stored pid.
205 retcode = subp.wait()
213 retcode = subp.wait()
206 self.pids.pop()
214 self.pids.pop()
207 return retcode
215 return retcode
208
216
209 def run(self):
217 def run(self):
210 """Run the stored commands"""
218 """Run the stored commands"""
211 try:
219 try:
212 return self._run_cmd()
220 return self._run_cmd()
213 except:
221 except:
214 import traceback
222 import traceback
215 traceback.print_exc()
223 traceback.print_exc()
216 return 1 # signal failure
224 return 1 # signal failure
217
225
218 def __del__(self):
226 def __del__(self):
219 """Cleanup on exit by killing any leftover processes."""
227 """Cleanup on exit by killing any leftover processes."""
220
228
221 if not hasattr(os, 'kill'):
229 if not hasattr(os, 'kill'):
222 return
230 return
223
231
224 for pid in self.pids:
232 for pid in self.pids:
225 try:
233 try:
226 print 'Cleaning stale PID:', pid
234 print 'Cleaning stale PID:', pid
227 os.kill(pid, signal.SIGKILL)
235 os.kill(pid, signal.SIGKILL)
228 except OSError:
236 except OSError:
229 # This is just a best effort, if we fail or the process was
237 # This is just a best effort, if we fail or the process was
230 # really gone, ignore it.
238 # really gone, ignore it.
231 pass
239 pass
232
240
233
241
234 def make_runners():
242 def make_runners():
235 """Define the top-level packages that need to be tested.
243 """Define the top-level packages that need to be tested.
236 """
244 """
237
245
238 nose_packages = ['config', 'core', 'extensions', 'frontend', 'lib',
246 nose_packages = ['config', 'core', 'extensions', 'frontend', 'lib',
239 'scripts', 'testing', 'utils']
247 'scripts', 'testing', 'utils']
240 trial_packages = ['kernel']
248 trial_packages = ['kernel']
241 #trial_packages = [] # dbg
242
249
243 if have_wx:
250 if have_wx:
244 nose_packages.append('gui')
251 nose_packages.append('gui')
245
252
253 #nose_packages = ['core'] # dbg
254 #trial_packages = [] # dbg
255
246 nose_packages = ['IPython.%s' % m for m in nose_packages ]
256 nose_packages = ['IPython.%s' % m for m in nose_packages ]
247 trial_packages = ['IPython.%s' % m for m in trial_packages ]
257 trial_packages = ['IPython.%s' % m for m in trial_packages ]
248
258
249 # Make runners, most with nose
259 # Make runners, most with nose
250 nose_testers = [IPTester(params=v) for v in nose_packages]
260 nose_testers = [IPTester(params=v) for v in nose_packages]
251 runners = dict(zip(nose_packages, nose_testers))
261 runners = dict(zip(nose_packages, nose_testers))
252 # And add twisted ones if conditions are met
262 # And add twisted ones if conditions are met
253 if have_zi and have_twisted and have_foolscap:
263 if have_zi and have_twisted and have_foolscap:
254 trial_testers = [IPTester('trial',params=v) for v in trial_packages]
264 trial_testers = [IPTester('trial',params=v) for v in trial_packages]
255 runners.update(dict(zip(trial_packages,trial_testers)))
265 runners.update(dict(zip(trial_packages,trial_testers)))
256
266
257 return runners
267 return runners
258
268
259
269
260 def run_iptest():
270 def run_iptest():
261 """Run the IPython test suite using nose.
271 """Run the IPython test suite using nose.
262
272
263 This function is called when this script is **not** called with the form
273 This function is called when this script is **not** called with the form
264 `iptest all`. It simply calls nose with appropriate command line flags
274 `iptest all`. It simply calls nose with appropriate command line flags
265 and accepts all of the standard nose arguments.
275 and accepts all of the standard nose arguments.
266 """
276 """
267
277
268 warnings.filterwarnings('ignore',
278 warnings.filterwarnings('ignore',
269 'This will be removed soon. Use IPython.testing.util instead')
279 'This will be removed soon. Use IPython.testing.util instead')
270
280
271 argv = sys.argv + [
281 argv = sys.argv + [ '--detailed-errors',
272 # Loading ipdoctest causes problems with Twisted.
282 # Loading ipdoctest causes problems with Twisted, but
273 # I am removing this as a temporary fix to get the
283 # our test suite runner now separates things and runs
274 # test suite back into working shape. Our nose
284 # all Twisted tests with trial.
275 # plugin needs to be gone through with a fine
285 '--with-ipdoctest',
276 # toothed comb to find what is causing the problem.
286 '--ipdoctest-tests','--ipdoctest-extension=txt',
277 # '--with-ipdoctest',
287
278 # '--ipdoctest-tests','--ipdoctest-extension=txt',
288 #'-x','-s', # dbg
279 # '--detailed-errors',
289
280
281 # We add --exe because of setuptools' imbecility (it
290 # We add --exe because of setuptools' imbecility (it
282 # blindly does chmod +x on ALL files). Nose does the
291 # blindly does chmod +x on ALL files). Nose does the
283 # right thing and it tries to avoid executables,
292 # right thing and it tries to avoid executables,
284 # setuptools unfortunately forces our hand here. This
293 # setuptools unfortunately forces our hand here. This
285 # has been discussed on the distutils list and the
294 # has been discussed on the distutils list and the
286 # setuptools devs refuse to fix this problem!
295 # setuptools devs refuse to fix this problem!
287 '--exe',
296 '--exe',
288 ]
297 ]
289
298
290 # Detect if any tests were required by explicitly calling an IPython
299 # Detect if any tests were required by explicitly calling an IPython
291 # submodule or giving a specific path
300 # submodule or giving a specific path
292 has_tests = False
301 has_tests = False
293 for arg in sys.argv:
302 for arg in sys.argv:
294 if 'IPython' in arg or arg.endswith('.py') or \
303 if 'IPython' in arg or arg.endswith('.py') or \
295 (':' in arg and '.py' in arg):
304 (':' in arg and '.py' in arg):
296 has_tests = True
305 has_tests = True
297 break
306 break
298
307
299 # If nothing was specifically requested, test full IPython
308 # If nothing was specifically requested, test full IPython
300 if not has_tests:
309 if not has_tests:
301 argv.append('IPython')
310 argv.append('IPython')
302
311
303 # Construct list of plugins, omitting the existing doctest plugin, which
312 ## # Construct list of plugins, omitting the existing doctest plugin, which
304 # ours replaces (and extends).
313 ## # ours replaces (and extends).
305 EXCLUDE = make_exclude()
314 plugins = [IPythonDoctest(make_exclude())]
306 plugins = []
307 # plugins = [IPythonDoctest(EXCLUDE)]
308 for p in nose.plugins.builtin.plugins:
315 for p in nose.plugins.builtin.plugins:
309 plug = p()
316 plug = p()
310 if plug.name == 'doctest':
317 if plug.name == 'doctest':
311 continue
318 continue
312 plugins.append(plug)
319 plugins.append(plug)
313
320
321 # We need a global ipython running in this process
322 globalipapp.start_ipython()
323 # Now nose can run
314 TestProgram(argv=argv,plugins=plugins)
324 TestProgram(argv=argv,plugins=plugins)
315
325
316
326
317 def run_iptestall():
327 def run_iptestall():
318 """Run the entire IPython test suite by calling nose and trial.
328 """Run the entire IPython test suite by calling nose and trial.
319
329
320 This function constructs :class:`IPTester` instances for all IPython
330 This function constructs :class:`IPTester` instances for all IPython
321 modules and package and then runs each of them. This causes the modules
331 modules and package and then runs each of them. This causes the modules
322 and packages of IPython to be tested each in their own subprocess using
332 and packages of IPython to be tested each in their own subprocess using
323 nose or twisted.trial appropriately.
333 nose or twisted.trial appropriately.
324 """
334 """
325
335
326 runners = make_runners()
336 runners = make_runners()
327
337
328 # Run the test runners in a temporary dir so we can nuke it when finished
338 # Run the test runners in a temporary dir so we can nuke it when finished
329 # to clean up any junk files left over by accident. This also makes it
339 # to clean up any junk files left over by accident. This also makes it
330 # robust against being run in non-writeable directories by mistake, as the
340 # robust against being run in non-writeable directories by mistake, as the
331 # temp dir will always be user-writeable.
341 # temp dir will always be user-writeable.
332 curdir = os.getcwd()
342 curdir = os.getcwd()
333 testdir = tempfile.gettempdir()
343 testdir = tempfile.gettempdir()
334 os.chdir(testdir)
344 os.chdir(testdir)
335
345
336 # Run all test runners, tracking execution time
346 # Run all test runners, tracking execution time
337 failed = {}
347 failed = {}
338 t_start = time.time()
348 t_start = time.time()
339 try:
349 try:
340 for name,runner in runners.iteritems():
350 for name,runner in runners.iteritems():
341 print '*'*77
351 print '*'*77
342 print 'IPython test group:',name
352 print 'IPython test group:',name
343 res = runner.run()
353 res = runner.run()
344 if res:
354 if res:
345 failed[name] = res
355 failed[name] = res
346 finally:
356 finally:
347 os.chdir(curdir)
357 os.chdir(curdir)
348 t_end = time.time()
358 t_end = time.time()
349 t_tests = t_end - t_start
359 t_tests = t_end - t_start
350 nrunners = len(runners)
360 nrunners = len(runners)
351 nfail = len(failed)
361 nfail = len(failed)
352 # summarize results
362 # summarize results
353 print
363 print
354 print '*'*77
364 print '*'*77
355 print 'Ran %s test groups in %.3fs' % (nrunners, t_tests)
365 print 'Ran %s test groups in %.3fs' % (nrunners, t_tests)
356 print
366 print
357 if not failed:
367 if not failed:
358 print 'OK'
368 print 'OK'
359 else:
369 else:
360 # If anything went wrong, point out what command to rerun manually to
370 # If anything went wrong, point out what command to rerun manually to
361 # see the actual errors and individual summary
371 # see the actual errors and individual summary
362 print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners)
372 print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners)
363 for name in failed:
373 for name in failed:
364 failed_runner = runners[name]
374 failed_runner = runners[name]
365 print '-'*40
375 print '-'*40
366 print 'Runner failed:',name
376 print 'Runner failed:',name
367 print 'You may wish to rerun this one individually, with:'
377 print 'You may wish to rerun this one individually, with:'
368 print ' '.join(failed_runner.call_args)
378 print ' '.join(failed_runner.call_args)
369 print
379 print
370
380
371
381
372 def main():
382 def main():
373 if len(sys.argv) == 1:
383 if len(sys.argv) == 1:
374 run_iptestall()
384 run_iptestall()
375 else:
385 else:
376 if sys.argv[1] == 'all':
386 if sys.argv[1] == 'all':
377 run_iptestall()
387 run_iptestall()
378 else:
388 else:
379 run_iptest()
389 run_iptest()
380
390
381
391
382 if __name__ == '__main__':
392 if __name__ == '__main__':
383 main()
393 main()
@@ -1,156 +1,188 b''
1 """Experimental code for cleaner support of IPython syntax with unittest.
1 """Experimental code for cleaner support of IPython syntax with unittest.
2
2
3 In IPython up until 0.10, we've used very hacked up nose machinery for running
3 In IPython up until 0.10, we've used very hacked up nose machinery for running
4 tests with IPython special syntax, and this has proved to be extremely slow.
4 tests with IPython special syntax, and this has proved to be extremely slow.
5 This module provides decorators to try a different approach, stemming from a
5 This module provides decorators to try a different approach, stemming from a
6 conversation Brian and I (FP) had about this problem Sept/09.
6 conversation Brian and I (FP) had about this problem Sept/09.
7
7
8 The goal is to be able to easily write simple functions that can be seen by
8 The goal is to be able to easily write simple functions that can be seen by
9 unittest as tests, and ultimately for these to support doctests with full
9 unittest as tests, and ultimately for these to support doctests with full
10 IPython syntax. Nose already offers this based on naming conventions and our
10 IPython syntax. Nose already offers this based on naming conventions and our
11 hackish plugins, but we are seeking to move away from nose dependencies if
11 hackish plugins, but we are seeking to move away from nose dependencies if
12 possible.
12 possible.
13
13
14 This module follows a different approach, based on decorators.
14 This module follows a different approach, based on decorators.
15
15
16 - A decorator called @ipdoctest can mark any function as having a docstring
16 - A decorator called @ipdoctest can mark any function as having a docstring
17 that should be viewed as a doctest, but after syntax conversion.
17 that should be viewed as a doctest, but after syntax conversion.
18
18
19 Authors
19 Authors
20 -------
20 -------
21
21
22 - Fernando Perez <Fernando.Perez@berkeley.edu>
22 - Fernando Perez <Fernando.Perez@berkeley.edu>
23 """
23 """
24
24
25 from __future__ import absolute_import
26
25 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
26 # Copyright (C) 2009 The IPython Development Team
28 # Copyright (C) 2009 The IPython Development Team
27 #
29 #
28 # Distributed under the terms of the BSD License. The full license is in
30 # Distributed under the terms of the BSD License. The full license is in
29 # the file COPYING, distributed as part of this software.
31 # the file COPYING, distributed as part of this software.
30 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
31
33
32
34
33 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
34 # Imports
36 # Imports
35 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
36
38
37 # Stdlib
39 # Stdlib
38 import re
40 import re
39 import sys
41 import sys
40 import unittest
42 import unittest
41 from doctest import DocTestFinder, DocTestRunner, TestResults
43 from doctest import DocTestFinder, DocTestRunner, TestResults
42
44
43 # Our own
45 # Our own, a nose monkeypatch
44 import nosepatch
46 from . import nosepatch
45
47
46 # We already have python3-compliant code for parametric tests
48 # We already have python3-compliant code for parametric tests
47 if sys.version[0]=='2':
49 if sys.version[0]=='2':
48 from _paramtestpy2 import ParametricTestCase
50 from ._paramtestpy2 import ParametricTestCase
49 else:
51 else:
50 from _paramtestpy3 import ParametricTestCase
52 from ._paramtestpy3 import ParametricTestCase
53
54 from . import globalipapp
51
55
52 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
53 # Classes and functions
57 # Classes and functions
54 #-----------------------------------------------------------------------------
58 #-----------------------------------------------------------------------------
55
59
56 def count_failures(runner):
60 def count_failures(runner):
57 """Count number of failures in a doctest runner.
61 """Count number of failures in a doctest runner.
58
62
59 Code modeled after the summarize() method in doctest.
63 Code modeled after the summarize() method in doctest.
60 """
64 """
61 return [TestResults(f, t) for f, t in runner._name2ft.values() if f > 0 ]
65 return [TestResults(f, t) for f, t in runner._name2ft.values() if f > 0 ]
62
66
63
67
64 class IPython2PythonConverter(object):
68 class IPython2PythonConverter(object):
65 """Convert IPython 'syntax' to valid Python.
69 """Convert IPython 'syntax' to valid Python.
66
70
67 Eventually this code may grow to be the full IPython syntax conversion
71 Eventually this code may grow to be the full IPython syntax conversion
68 implementation, but for now it only does prompt convertion."""
72 implementation, but for now it only does prompt convertion."""
69
73
70 def __init__(self):
74 def __init__(self):
71 self.ps1 = re.compile(r'In\ \[\d+\]: ')
75 self.rps1 = re.compile(r'In\ \[\d+\]: ')
72 self.ps2 = re.compile(r'\ \ \ \.\.\.+: ')
76 self.rps2 = re.compile(r'\ \ \ \.\.\.+: ')
73 self.out = re.compile(r'Out\[\d+\]: \s*?\n?')
77 self.rout = re.compile(r'Out\[\d+\]: \s*?\n?')
78 self.pyps1 = '>>> '
79 self.pyps2 = '... '
80 self.rpyps1 = re.compile ('(\s*%s)(.*)$' % self.pyps1)
81 self.rpyps2 = re.compile ('(\s*%s)(.*)$' % self.pyps2)
74
82
75 def __call__(self, ds):
83 def __call__(self, ds):
76 """Convert IPython prompts to python ones in a string."""
84 """Convert IPython prompts to python ones in a string."""
77 pyps1 = '>>> '
85 pyps1 = '>>> '
78 pyps2 = '... '
86 pyps2 = '... '
79 pyout = ''
87 pyout = ''
80
88
81 dnew = ds
89 dnew = ds
82 dnew = self.ps1.sub(pyps1, dnew)
90 dnew = self.rps1.sub(pyps1, dnew)
83 dnew = self.ps2.sub(pyps2, dnew)
91 dnew = self.rps2.sub(pyps2, dnew)
84 dnew = self.out.sub(pyout, dnew)
92 dnew = self.rout.sub(pyout, dnew)
85 return dnew
93 ip = globalipapp.get_ipython()
94
95 # Convert input IPython source into valid Python.
96 out = []
97 newline = out.append
98 for line in dnew.splitlines():
99
100 mps1 = self.rpyps1.match(line)
101 if mps1 is not None:
102 prompt, text = mps1.groups()
103 newline(prompt+ip.prefilter(text, False))
104 continue
105
106 mps2 = self.rpyps2.match(line)
107 if mps2 is not None:
108 prompt, text = mps2.groups()
109 newline(prompt+ip.prefilter(text, True))
110 continue
111
112 newline(line)
113 newline('') # ensure a closing newline, needed by doctest
114 #print "PYSRC:", '\n'.join(out) # dbg
115 return '\n'.join(out)
116
117 #return dnew
86
118
87
119
88 class Doc2UnitTester(object):
120 class Doc2UnitTester(object):
89 """Class whose instances act as a decorator for docstring testing.
121 """Class whose instances act as a decorator for docstring testing.
90
122
91 In practice we're only likely to need one instance ever, made below (though
123 In practice we're only likely to need one instance ever, made below (though
92 no attempt is made at turning it into a singleton, there is no need for
124 no attempt is made at turning it into a singleton, there is no need for
93 that).
125 that).
94 """
126 """
95 def __init__(self, verbose=False):
127 def __init__(self, verbose=False):
96 """New decorator.
128 """New decorator.
97
129
98 Parameters
130 Parameters
99 ----------
131 ----------
100
132
101 verbose : boolean, optional (False)
133 verbose : boolean, optional (False)
102 Passed to the doctest finder and runner to control verbosity.
134 Passed to the doctest finder and runner to control verbosity.
103 """
135 """
104 self.verbose = verbose
136 self.verbose = verbose
105 # We can reuse the same finder for all instances
137 # We can reuse the same finder for all instances
106 self.finder = DocTestFinder(verbose=verbose, recurse=False)
138 self.finder = DocTestFinder(verbose=verbose, recurse=False)
107
139
108 def __call__(self, func):
140 def __call__(self, func):
109 """Use as a decorator: doctest a function's docstring as a unittest.
141 """Use as a decorator: doctest a function's docstring as a unittest.
110
142
111 This version runs normal doctests, but the idea is to make it later run
143 This version runs normal doctests, but the idea is to make it later run
112 ipython syntax instead."""
144 ipython syntax instead."""
113
145
114 # Capture the enclosing instance with a different name, so the new
146 # Capture the enclosing instance with a different name, so the new
115 # class below can see it without confusion regarding its own 'self'
147 # class below can see it without confusion regarding its own 'self'
116 # that will point to the test instance at runtime
148 # that will point to the test instance at runtime
117 d2u = self
149 d2u = self
118
150
119 # Rewrite the function's docstring to have python syntax
151 # Rewrite the function's docstring to have python syntax
120 if func.__doc__ is not None:
152 if func.__doc__ is not None:
121 func.__doc__ = ip2py(func.__doc__)
153 func.__doc__ = ip2py(func.__doc__)
122
154
123 # Now, create a tester object that is a real unittest instance, so
155 # Now, create a tester object that is a real unittest instance, so
124 # normal unittest machinery (or Nose, or Trial) can find it.
156 # normal unittest machinery (or Nose, or Trial) can find it.
125 class Tester(unittest.TestCase):
157 class Tester(unittest.TestCase):
126 def test(self):
158 def test(self):
127 # Make a new runner per function to be tested
159 # Make a new runner per function to be tested
128 runner = DocTestRunner(verbose=d2u.verbose)
160 runner = DocTestRunner(verbose=d2u.verbose)
129 map(runner.run, d2u.finder.find(func, func.__name__))
161 map(runner.run, d2u.finder.find(func, func.__name__))
130 failed = count_failures(runner)
162 failed = count_failures(runner)
131 if failed:
163 if failed:
132 # Since we only looked at a single function's docstring,
164 # Since we only looked at a single function's docstring,
133 # failed should contain at most one item. More than that
165 # failed should contain at most one item. More than that
134 # is a case we can't handle and should error out on
166 # is a case we can't handle and should error out on
135 if len(failed) > 1:
167 if len(failed) > 1:
136 err = "Invalid number of test results:" % failed
168 err = "Invalid number of test results:" % failed
137 raise ValueError(err)
169 raise ValueError(err)
138 # Report a normal failure.
170 # Report a normal failure.
139 self.fail('failed doctests: %s' % str(failed[0]))
171 self.fail('failed doctests: %s' % str(failed[0]))
140
172
141 # Rename it so test reports have the original signature.
173 # Rename it so test reports have the original signature.
142 Tester.__name__ = func.__name__
174 Tester.__name__ = func.__name__
143 return Tester
175 return Tester
144
176
145
177
146 def ipdocstring(func):
178 def ipdocstring(func):
147 """Change the function docstring via ip2py.
179 """Change the function docstring via ip2py.
148 """
180 """
149 if func.__doc__ is not None:
181 if func.__doc__ is not None:
150 func.__doc__ = ip2py(func.__doc__)
182 func.__doc__ = ip2py(func.__doc__)
151 return func
183 return func
152
184
153
185
154 # Make an instance of the classes for public use
186 # Make an instance of the classes for public use
155 ipdoctest = Doc2UnitTester()
187 ipdoctest = Doc2UnitTester()
156 ip2py = IPython2PythonConverter()
188 ip2py = IPython2PythonConverter()
@@ -1,940 +1,779 b''
1 """Nose Plugin that supports IPython doctests.
1 """Nose Plugin that supports IPython doctests.
2
2
3 Limitations:
3 Limitations:
4
4
5 - When generating examples for use as doctests, make sure that you have
5 - When generating examples for use as doctests, make sure that you have
6 pretty-printing OFF. This can be done either by starting ipython with the
6 pretty-printing OFF. This can be done either by starting ipython with the
7 flag '--nopprint', by setting pprint to 0 in your ipythonrc file, or by
7 flag '--nopprint', by setting pprint to 0 in your ipythonrc file, or by
8 interactively disabling it with %Pprint. This is required so that IPython
8 interactively disabling it with %Pprint. This is required so that IPython
9 output matches that of normal Python, which is used by doctest for internal
9 output matches that of normal Python, which is used by doctest for internal
10 execution.
10 execution.
11
11
12 - Do not rely on specific prompt numbers for results (such as using
12 - Do not rely on specific prompt numbers for results (such as using
13 '_34==True', for example). For IPython tests run via an external process the
13 '_34==True', for example). For IPython tests run via an external process the
14 prompt numbers may be different, and IPython tests run as normal python code
14 prompt numbers may be different, and IPython tests run as normal python code
15 won't even have these special _NN variables set at all.
15 won't even have these special _NN variables set at all.
16 """
16 """
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Module imports
19 # Module imports
20
20
21 # From the standard library
21 # From the standard library
22 import __builtin__
22 import __builtin__
23 import commands
23 import commands
24 import doctest
24 import doctest
25 import inspect
25 import inspect
26 import logging
26 import logging
27 import os
27 import os
28 import re
28 import re
29 import sys
29 import sys
30 import traceback
30 import traceback
31 import unittest
31 import unittest
32
32
33 from inspect import getmodule
33 from inspect import getmodule
34 from StringIO import StringIO
34 from StringIO import StringIO
35
35
36 # We are overriding the default doctest runner, so we need to import a few
36 # We are overriding the default doctest runner, so we need to import a few
37 # things from doctest directly
37 # things from doctest directly
38 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
38 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
39 _unittest_reportflags, DocTestRunner,
39 _unittest_reportflags, DocTestRunner,
40 _extract_future_flags, pdb, _OutputRedirectingPdb,
40 _extract_future_flags, pdb, _OutputRedirectingPdb,
41 _exception_traceback,
41 _exception_traceback,
42 linecache)
42 linecache)
43
43
44 # Third-party modules
44 # Third-party modules
45 import nose.core
45 import nose.core
46
46
47 from nose.plugins import doctests, Plugin
47 from nose.plugins import doctests, Plugin
48 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
48 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
49
49
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51 # Module globals and other constants
51 # Module globals and other constants
52 #-----------------------------------------------------------------------------
52
53
53 log = logging.getLogger(__name__)
54 log = logging.getLogger(__name__)
54
55
55 ###########################################################################
56 # *** HACK ***
57 # We must start our own ipython object and heavily muck with it so that all the
58 # modifications IPython makes to system behavior don't send the doctest
59 # machinery into a fit. This code should be considered a gross hack, but it
60 # gets the job done.
61
62 def default_argv():
63 """Return a valid default argv for creating testing instances of ipython"""
64
65 # Get the install directory for the user configuration and tell ipython to
66 # use the default profile from there.
67 from IPython.config import default
68 ipcdir = os.path.dirname(default.__file__)
69 ipconf = os.path.join(ipcdir,'ipython_config.py')
70 #print 'conf:',ipconf # dbg
71 return ['--colors=NoColor', '--no-term-title','--no-banner',
72 '--config-file=%s' % ipconf]
73
74
75 # Hack to modify the %run command so we can sync the user's namespace with the
76 # test globals. Once we move over to a clean magic system, this will be done
77 # with much less ugliness.
78
79 class py_file_finder(object):
80 def __init__(self,test_filename):
81 self.test_filename = test_filename
82
83 def __call__(self,name):
84 from IPython.utils.genutils import get_py_filename
85 try:
86 return get_py_filename(name)
87 except IOError:
88 test_dir = os.path.dirname(self.test_filename)
89 new_path = os.path.join(test_dir,name)
90 return get_py_filename(new_path)
91
92
93 def _run_ns_sync(self,arg_s,runner=None):
94 """Modified version of %run that syncs testing namespaces.
95
96 This is strictly needed for running doctests that call %run.
97 """
98
99 # When tests call %run directly (not via doctest) these function attributes
100 # are not set
101 try:
102 fname = _run_ns_sync.test_filename
103 except AttributeError:
104 fname = arg_s
105
106 finder = py_file_finder(fname)
107 out = _ip.magic_run_ori(arg_s,runner,finder)
108
109 # Simliarly, there is no test_globs when a test is NOT a doctest
110 if hasattr(_run_ns_sync,'test_globs'):
111 _run_ns_sync.test_globs.update(_ip.user_ns)
112 return out
113
114
115 class ipnsdict(dict):
116 """A special subclass of dict for use as an IPython namespace in doctests.
117
118 This subclass adds a simple checkpointing capability so that when testing
119 machinery clears it (we use it as the test execution context), it doesn't
120 get completely destroyed.
121 """
122
123 def __init__(self,*a):
124 dict.__init__(self,*a)
125 self._savedict = {}
126
127 def clear(self):
128 dict.clear(self)
129 self.update(self._savedict)
130
131 def _checkpoint(self):
132 self._savedict.clear()
133 self._savedict.update(self)
134
135 def update(self,other):
136 self._checkpoint()
137 dict.update(self,other)
138
139 # If '_' is in the namespace, python won't set it when executing code,
140 # and we have examples that test it. So we ensure that the namespace
141 # is always 'clean' of it before it's used for test code execution.
142 self.pop('_',None)
143
144 # The builtins namespace must *always* be the real __builtin__ module,
145 # else weird stuff happens. The main ipython code does have provisions
146 # to ensure this after %run, but since in this class we do some
147 # aggressive low-level cleaning of the execution namespace, we need to
148 # correct for that ourselves, to ensure consitency with the 'real'
149 # ipython.
150 self['__builtins__'] = __builtin__
151
152
153 def start_ipython():
154 """Start a global IPython shell, which we need for IPython-specific syntax.
155 """
156
157 # This function should only ever run once!
158 if hasattr(start_ipython,'already_called'):
159 return
160 start_ipython.already_called = True
161
162 # Ok, first time we're called, go ahead
163 import new
164
165 import IPython
166 from IPython.core import ipapp, iplib
167
168 def xsys(cmd):
169 """Execute a command and print its output.
170
171 This is just a convenience function to replace the IPython system call
172 with one that is more doctest-friendly.
173 """
174 cmd = _ip.var_expand(cmd,depth=1)
175 sys.stdout.write(commands.getoutput(cmd))
176 sys.stdout.flush()
177
178 # Store certain global objects that IPython modifies
179 _displayhook = sys.displayhook
180 _excepthook = sys.excepthook
181 _main = sys.modules.get('__main__')
182
183 argv = default_argv()
184
185 # Start IPython instance. We customize it to start with minimal frills.
186 user_ns,global_ns = iplib.make_user_namespaces(ipnsdict(),{})
187 ip = ipapp.IPythonApp(argv, user_ns=user_ns, user_global_ns=global_ns)
188 ip.initialize()
189 ip.shell.builtin_trap.set()
190
191 # Deactivate the various python system hooks added by ipython for
192 # interactive convenience so we don't confuse the doctest system
193 sys.modules['__main__'] = _main
194 sys.displayhook = _displayhook
195 sys.excepthook = _excepthook
196
197 # So that ipython magics and aliases can be doctested (they work by making
198 # a call into a global _ip object)
199 __builtin__._ip = ip.shell
200
201 # Modify the IPython system call with one that uses getoutput, so that we
202 # can capture subcommands and print them to Python's stdout, otherwise the
203 # doctest machinery would miss them.
204 ip.shell.system = xsys
205
206 # Also patch our %run function in.
207 im = new.instancemethod(_run_ns_sync,_ip, _ip.__class__)
208 ip.shell.magic_run_ori = _ip.magic_run
209 ip.shell.magic_run = im
210
211 # XXX - For some very bizarre reason, the loading of %history by default is
212 # failing. This needs to be fixed later, but for now at least this ensures
213 # that tests that use %hist run to completion.
214 from IPython.core import history
215 history.init_ipython(ip.shell)
216 if not hasattr(ip.shell,'magic_history'):
217 raise RuntimeError("Can't load magics, aborting")
218
219
220 # The start call MUST be made here. I'm not sure yet why it doesn't work if
221 # it is made later, at plugin initialization time, but in all my tests, that's
222 # the case.
223 start_ipython()
224
225 # *** END HACK ***
226 ###########################################################################
227
56
57 #-----------------------------------------------------------------------------
228 # Classes and functions
58 # Classes and functions
59 #-----------------------------------------------------------------------------
229
60
230 def is_extension_module(filename):
61 def is_extension_module(filename):
231 """Return whether the given filename is an extension module.
62 """Return whether the given filename is an extension module.
232
63
233 This simply checks that the extension is either .so or .pyd.
64 This simply checks that the extension is either .so or .pyd.
234 """
65 """
235 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
66 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
236
67
237
68
238 class DocTestSkip(object):
69 class DocTestSkip(object):
239 """Object wrapper for doctests to be skipped."""
70 """Object wrapper for doctests to be skipped."""
240
71
241 ds_skip = """Doctest to skip.
72 ds_skip = """Doctest to skip.
242 >>> 1 #doctest: +SKIP
73 >>> 1 #doctest: +SKIP
243 """
74 """
244
75
245 def __init__(self,obj):
76 def __init__(self,obj):
246 self.obj = obj
77 self.obj = obj
247
78
248 def __getattribute__(self,key):
79 def __getattribute__(self,key):
249 if key == '__doc__':
80 if key == '__doc__':
250 return DocTestSkip.ds_skip
81 return DocTestSkip.ds_skip
251 else:
82 else:
252 return getattr(object.__getattribute__(self,'obj'),key)
83 return getattr(object.__getattribute__(self,'obj'),key)
253
84
254 # Modified version of the one in the stdlib, that fixes a python bug (doctests
85 # Modified version of the one in the stdlib, that fixes a python bug (doctests
255 # not found in extension modules, http://bugs.python.org/issue3158)
86 # not found in extension modules, http://bugs.python.org/issue3158)
256 class DocTestFinder(doctest.DocTestFinder):
87 class DocTestFinder(doctest.DocTestFinder):
257
88
258 def _from_module(self, module, object):
89 def _from_module(self, module, object):
259 """
90 """
260 Return true if the given object is defined in the given
91 Return true if the given object is defined in the given
261 module.
92 module.
262 """
93 """
263 if module is None:
94 if module is None:
264 return True
95 return True
265 elif inspect.isfunction(object):
96 elif inspect.isfunction(object):
266 return module.__dict__ is object.func_globals
97 return module.__dict__ is object.func_globals
267 elif inspect.isbuiltin(object):
98 elif inspect.isbuiltin(object):
268 return module.__name__ == object.__module__
99 return module.__name__ == object.__module__
269 elif inspect.isclass(object):
100 elif inspect.isclass(object):
270 return module.__name__ == object.__module__
101 return module.__name__ == object.__module__
271 elif inspect.ismethod(object):
102 elif inspect.ismethod(object):
272 # This one may be a bug in cython that fails to correctly set the
103 # This one may be a bug in cython that fails to correctly set the
273 # __module__ attribute of methods, but since the same error is easy
104 # __module__ attribute of methods, but since the same error is easy
274 # to make by extension code writers, having this safety in place
105 # to make by extension code writers, having this safety in place
275 # isn't such a bad idea
106 # isn't such a bad idea
276 return module.__name__ == object.im_class.__module__
107 return module.__name__ == object.im_class.__module__
277 elif inspect.getmodule(object) is not None:
108 elif inspect.getmodule(object) is not None:
278 return module is inspect.getmodule(object)
109 return module is inspect.getmodule(object)
279 elif hasattr(object, '__module__'):
110 elif hasattr(object, '__module__'):
280 return module.__name__ == object.__module__
111 return module.__name__ == object.__module__
281 elif isinstance(object, property):
112 elif isinstance(object, property):
282 return True # [XX] no way not be sure.
113 return True # [XX] no way not be sure.
283 else:
114 else:
284 raise ValueError("object must be a class or function")
115 raise ValueError("object must be a class or function")
285
116
286 def _find(self, tests, obj, name, module, source_lines, globs, seen):
117 def _find(self, tests, obj, name, module, source_lines, globs, seen):
287 """
118 """
288 Find tests for the given object and any contained objects, and
119 Find tests for the given object and any contained objects, and
289 add them to `tests`.
120 add them to `tests`.
290 """
121 """
291
122 #print '_find for:', obj, name, module # dbg
292 if hasattr(obj,"skip_doctest"):
123 if hasattr(obj,"skip_doctest"):
293 #print 'SKIPPING DOCTEST FOR:',obj # dbg
124 #print 'SKIPPING DOCTEST FOR:',obj # dbg
294 obj = DocTestSkip(obj)
125 obj = DocTestSkip(obj)
295
126
296 doctest.DocTestFinder._find(self,tests, obj, name, module,
127 doctest.DocTestFinder._find(self,tests, obj, name, module,
297 source_lines, globs, seen)
128 source_lines, globs, seen)
298
129
299 # Below we re-run pieces of the above method with manual modifications,
130 # Below we re-run pieces of the above method with manual modifications,
300 # because the original code is buggy and fails to correctly identify
131 # because the original code is buggy and fails to correctly identify
301 # doctests in extension modules.
132 # doctests in extension modules.
302
133
303 # Local shorthands
134 # Local shorthands
304 from inspect import isroutine, isclass, ismodule
135 from inspect import isroutine, isclass, ismodule
305
136
306 # Look for tests in a module's contained objects.
137 # Look for tests in a module's contained objects.
307 if inspect.ismodule(obj) and self._recurse:
138 if inspect.ismodule(obj) and self._recurse:
308 for valname, val in obj.__dict__.items():
139 for valname, val in obj.__dict__.items():
309 valname1 = '%s.%s' % (name, valname)
140 valname1 = '%s.%s' % (name, valname)
310 if ( (isroutine(val) or isclass(val))
141 if ( (isroutine(val) or isclass(val))
311 and self._from_module(module, val) ):
142 and self._from_module(module, val) ):
312
143
313 self._find(tests, val, valname1, module, source_lines,
144 self._find(tests, val, valname1, module, source_lines,
314 globs, seen)
145 globs, seen)
315
146
316 # Look for tests in a class's contained objects.
147 # Look for tests in a class's contained objects.
317 if inspect.isclass(obj) and self._recurse:
148 if inspect.isclass(obj) and self._recurse:
318 #print 'RECURSE into class:',obj # dbg
149 #print 'RECURSE into class:',obj # dbg
319 for valname, val in obj.__dict__.items():
150 for valname, val in obj.__dict__.items():
320 # Special handling for staticmethod/classmethod.
151 # Special handling for staticmethod/classmethod.
321 if isinstance(val, staticmethod):
152 if isinstance(val, staticmethod):
322 val = getattr(obj, valname)
153 val = getattr(obj, valname)
323 if isinstance(val, classmethod):
154 if isinstance(val, classmethod):
324 val = getattr(obj, valname).im_func
155 val = getattr(obj, valname).im_func
325
156
326 # Recurse to methods, properties, and nested classes.
157 # Recurse to methods, properties, and nested classes.
327 if ((inspect.isfunction(val) or inspect.isclass(val) or
158 if ((inspect.isfunction(val) or inspect.isclass(val) or
328 inspect.ismethod(val) or
159 inspect.ismethod(val) or
329 isinstance(val, property)) and
160 isinstance(val, property)) and
330 self._from_module(module, val)):
161 self._from_module(module, val)):
331 valname = '%s.%s' % (name, valname)
162 valname = '%s.%s' % (name, valname)
332 self._find(tests, val, valname, module, source_lines,
163 self._find(tests, val, valname, module, source_lines,
333 globs, seen)
164 globs, seen)
334
165
335
166
336 class IPDoctestOutputChecker(doctest.OutputChecker):
167 class IPDoctestOutputChecker(doctest.OutputChecker):
337 """Second-chance checker with support for random tests.
168 """Second-chance checker with support for random tests.
338
169
339 If the default comparison doesn't pass, this checker looks in the expected
170 If the default comparison doesn't pass, this checker looks in the expected
340 output string for flags that tell us to ignore the output.
171 output string for flags that tell us to ignore the output.
341 """
172 """
342
173
343 random_re = re.compile(r'#\s*random\s+')
174 random_re = re.compile(r'#\s*random\s+')
344
175
345 def check_output(self, want, got, optionflags):
176 def check_output(self, want, got, optionflags):
346 """Check output, accepting special markers embedded in the output.
177 """Check output, accepting special markers embedded in the output.
347
178
348 If the output didn't pass the default validation but the special string
179 If the output didn't pass the default validation but the special string
349 '#random' is included, we accept it."""
180 '#random' is included, we accept it."""
350
181
351 # Let the original tester verify first, in case people have valid tests
182 # Let the original tester verify first, in case people have valid tests
352 # that happen to have a comment saying '#random' embedded in.
183 # that happen to have a comment saying '#random' embedded in.
353 ret = doctest.OutputChecker.check_output(self, want, got,
184 ret = doctest.OutputChecker.check_output(self, want, got,
354 optionflags)
185 optionflags)
355 if not ret and self.random_re.search(want):
186 if not ret and self.random_re.search(want):
356 #print >> sys.stderr, 'RANDOM OK:',want # dbg
187 #print >> sys.stderr, 'RANDOM OK:',want # dbg
357 return True
188 return True
358
189
359 return ret
190 return ret
360
191
361
192
362 class DocTestCase(doctests.DocTestCase):
193 class DocTestCase(doctests.DocTestCase):
363 """Proxy for DocTestCase: provides an address() method that
194 """Proxy for DocTestCase: provides an address() method that
364 returns the correct address for the doctest case. Otherwise
195 returns the correct address for the doctest case. Otherwise
365 acts as a proxy to the test case. To provide hints for address(),
196 acts as a proxy to the test case. To provide hints for address(),
366 an obj may also be passed -- this will be used as the test object
197 an obj may also be passed -- this will be used as the test object
367 for purposes of determining the test address, if it is provided.
198 for purposes of determining the test address, if it is provided.
368 """
199 """
369
200
370 # Note: this method was taken from numpy's nosetester module.
201 # Note: this method was taken from numpy's nosetester module.
371
202
372 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
203 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
373 # its constructor that blocks non-default arguments from being passed
204 # its constructor that blocks non-default arguments from being passed
374 # down into doctest.DocTestCase
205 # down into doctest.DocTestCase
375
206
376 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
207 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
377 checker=None, obj=None, result_var='_'):
208 checker=None, obj=None, result_var='_'):
378 self._result_var = result_var
209 self._result_var = result_var
379 doctests.DocTestCase.__init__(self, test,
210 doctests.DocTestCase.__init__(self, test,
380 optionflags=optionflags,
211 optionflags=optionflags,
381 setUp=setUp, tearDown=tearDown,
212 setUp=setUp, tearDown=tearDown,
382 checker=checker)
213 checker=checker)
383 # Now we must actually copy the original constructor from the stdlib
214 # Now we must actually copy the original constructor from the stdlib
384 # doctest class, because we can't call it directly and a bug in nose
215 # doctest class, because we can't call it directly and a bug in nose
385 # means it never gets passed the right arguments.
216 # means it never gets passed the right arguments.
386
217
387 self._dt_optionflags = optionflags
218 self._dt_optionflags = optionflags
388 self._dt_checker = checker
219 self._dt_checker = checker
389 self._dt_test = test
220 self._dt_test = test
390 self._dt_setUp = setUp
221 self._dt_setUp = setUp
391 self._dt_tearDown = tearDown
222 self._dt_tearDown = tearDown
392
223
393 # XXX - store this runner once in the object!
224 # XXX - store this runner once in the object!
394 runner = IPDocTestRunner(optionflags=optionflags,
225 runner = IPDocTestRunner(optionflags=optionflags,
395 checker=checker, verbose=False)
226 checker=checker, verbose=False)
396 self._dt_runner = runner
227 self._dt_runner = runner
397
228
398
229
399 # Each doctest should remember what directory it was loaded from...
230 # Each doctest should remember the directory it was loaded from, so
400 self._ori_dir = os.getcwd()
231 # things like %run work without too many contortions
232 self._ori_dir = os.path.dirname(test.filename)
401
233
402 # Modified runTest from the default stdlib
234 # Modified runTest from the default stdlib
403 def runTest(self):
235 def runTest(self):
404 test = self._dt_test
236 test = self._dt_test
405 runner = self._dt_runner
237 runner = self._dt_runner
406
238
407 old = sys.stdout
239 old = sys.stdout
408 new = StringIO()
240 new = StringIO()
409 optionflags = self._dt_optionflags
241 optionflags = self._dt_optionflags
410
242
411 if not (optionflags & REPORTING_FLAGS):
243 if not (optionflags & REPORTING_FLAGS):
412 # The option flags don't include any reporting flags,
244 # The option flags don't include any reporting flags,
413 # so add the default reporting flags
245 # so add the default reporting flags
414 optionflags |= _unittest_reportflags
246 optionflags |= _unittest_reportflags
415
247
416 try:
248 try:
417 # Save our current directory and switch out to the one where the
249 # Save our current directory and switch out to the one where the
418 # test was originally created, in case another doctest did a
250 # test was originally created, in case another doctest did a
419 # directory change. We'll restore this in the finally clause.
251 # directory change. We'll restore this in the finally clause.
420 curdir = os.getcwd()
252 curdir = os.getcwd()
253 #print 'runTest in dir:', self._ori_dir # dbg
421 os.chdir(self._ori_dir)
254 os.chdir(self._ori_dir)
422
255
423 runner.DIVIDER = "-"*70
256 runner.DIVIDER = "-"*70
424 failures, tries = runner.run(test,out=new.write,
257 failures, tries = runner.run(test,out=new.write,
425 clear_globs=False)
258 clear_globs=False)
426 finally:
259 finally:
427 sys.stdout = old
260 sys.stdout = old
428 os.chdir(curdir)
261 os.chdir(curdir)
429
262
430 if failures:
263 if failures:
431 raise self.failureException(self.format_failure(new.getvalue()))
264 raise self.failureException(self.format_failure(new.getvalue()))
432
265
433 def setUp(self):
266 def setUp(self):
434 """Modified test setup that syncs with ipython namespace"""
267 """Modified test setup that syncs with ipython namespace"""
435
268 #print "setUp test", self._dt_test.examples # dbg
436 if isinstance(self._dt_test.examples[0],IPExample):
269 if isinstance(self._dt_test.examples[0],IPExample):
437 # for IPython examples *only*, we swap the globals with the ipython
270 # for IPython examples *only*, we swap the globals with the ipython
438 # namespace, after updating it with the globals (which doctest
271 # namespace, after updating it with the globals (which doctest
439 # fills with the necessary info from the module being tested).
272 # fills with the necessary info from the module being tested).
440 _ip.user_ns.update(self._dt_test.globs)
273 _ip.user_ns.update(self._dt_test.globs)
441 self._dt_test.globs = _ip.user_ns
274 self._dt_test.globs = _ip.user_ns
442
275
443 super(DocTestCase, self).setUp()
276 super(DocTestCase, self).setUp()
444
277
445 def tearDown(self):
278 def tearDown(self):
446 # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
279 # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
447 # it does look like one to me: its tearDown method tries to run
280 # it does look like one to me: its tearDown method tries to run
448 #
281 #
449 # delattr(__builtin__, self._result_var)
282 # delattr(__builtin__, self._result_var)
450 #
283 #
451 # without checking that the attribute really is there; it implicitly
284 # without checking that the attribute really is there; it implicitly
452 # assumes it should have been set via displayhook. But if the
285 # assumes it should have been set via displayhook. But if the
453 # displayhook was never called, this doesn't necessarily happen. I
286 # displayhook was never called, this doesn't necessarily happen. I
454 # haven't been able to find a little self-contained example outside of
287 # haven't been able to find a little self-contained example outside of
455 # ipython that would show the problem so I can report it to the nose
288 # ipython that would show the problem so I can report it to the nose
456 # team, but it does happen a lot in our code.
289 # team, but it does happen a lot in our code.
457 #
290 #
458 # So here, we just protect as narrowly as possible by trapping an
291 # So here, we just protect as narrowly as possible by trapping an
459 # attribute error whose message would be the name of self._result_var,
292 # attribute error whose message would be the name of self._result_var,
460 # and letting any other error propagate.
293 # and letting any other error propagate.
461 try:
294 try:
462 super(DocTestCase, self).tearDown()
295 super(DocTestCase, self).tearDown()
463 except AttributeError, exc:
296 except AttributeError, exc:
464 if exc.args[0] != self._result_var:
297 if exc.args[0] != self._result_var:
465 raise
298 raise
466
299
467
300
468 # A simple subclassing of the original with a different class name, so we can
301 # A simple subclassing of the original with a different class name, so we can
469 # distinguish and treat differently IPython examples from pure python ones.
302 # distinguish and treat differently IPython examples from pure python ones.
470 class IPExample(doctest.Example): pass
303 class IPExample(doctest.Example): pass
471
304
472
305
473 class IPExternalExample(doctest.Example):
306 class IPExternalExample(doctest.Example):
474 """Doctest examples to be run in an external process."""
307 """Doctest examples to be run in an external process."""
475
308
476 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
309 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
477 options=None):
310 options=None):
478 # Parent constructor
311 # Parent constructor
479 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
312 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
480
313
481 # An EXTRA newline is needed to prevent pexpect hangs
314 # An EXTRA newline is needed to prevent pexpect hangs
482 self.source += '\n'
315 self.source += '\n'
483
316
484
317
485 class IPDocTestParser(doctest.DocTestParser):
318 class IPDocTestParser(doctest.DocTestParser):
486 """
319 """
487 A class used to parse strings containing doctest examples.
320 A class used to parse strings containing doctest examples.
488
321
489 Note: This is a version modified to properly recognize IPython input and
322 Note: This is a version modified to properly recognize IPython input and
490 convert any IPython examples into valid Python ones.
323 convert any IPython examples into valid Python ones.
491 """
324 """
492 # This regular expression is used to find doctest examples in a
325 # This regular expression is used to find doctest examples in a
493 # string. It defines three groups: `source` is the source code
326 # string. It defines three groups: `source` is the source code
494 # (including leading indentation and prompts); `indent` is the
327 # (including leading indentation and prompts); `indent` is the
495 # indentation of the first (PS1) line of the source code; and
328 # indentation of the first (PS1) line of the source code; and
496 # `want` is the expected output (including leading indentation).
329 # `want` is the expected output (including leading indentation).
497
330
498 # Classic Python prompts or default IPython ones
331 # Classic Python prompts or default IPython ones
499 _PS1_PY = r'>>>'
332 _PS1_PY = r'>>>'
500 _PS2_PY = r'\.\.\.'
333 _PS2_PY = r'\.\.\.'
501
334
502 _PS1_IP = r'In\ \[\d+\]:'
335 _PS1_IP = r'In\ \[\d+\]:'
503 _PS2_IP = r'\ \ \ \.\.\.+:'
336 _PS2_IP = r'\ \ \ \.\.\.+:'
504
337
505 _RE_TPL = r'''
338 _RE_TPL = r'''
506 # Source consists of a PS1 line followed by zero or more PS2 lines.
339 # Source consists of a PS1 line followed by zero or more PS2 lines.
507 (?P<source>
340 (?P<source>
508 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
341 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
509 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
342 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
510 \n? # a newline
343 \n? # a newline
511 # Want consists of any non-blank lines that do not start with PS1.
344 # Want consists of any non-blank lines that do not start with PS1.
512 (?P<want> (?:(?![ ]*$) # Not a blank line
345 (?P<want> (?:(?![ ]*$) # Not a blank line
513 (?![ ]*%s) # Not a line starting with PS1
346 (?![ ]*%s) # Not a line starting with PS1
514 (?![ ]*%s) # Not a line starting with PS2
347 (?![ ]*%s) # Not a line starting with PS2
515 .*$\n? # But any other line
348 .*$\n? # But any other line
516 )*)
349 )*)
517 '''
350 '''
518
351
519 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
352 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
520 re.MULTILINE | re.VERBOSE)
353 re.MULTILINE | re.VERBOSE)
521
354
522 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
355 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
523 re.MULTILINE | re.VERBOSE)
356 re.MULTILINE | re.VERBOSE)
524
357
525 # Mark a test as being fully random. In this case, we simply append the
358 # Mark a test as being fully random. In this case, we simply append the
526 # random marker ('#random') to each individual example's output. This way
359 # random marker ('#random') to each individual example's output. This way
527 # we don't need to modify any other code.
360 # we don't need to modify any other code.
528 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
361 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
529
362
530 # Mark tests to be executed in an external process - currently unsupported.
363 # Mark tests to be executed in an external process - currently unsupported.
531 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
364 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
532
365
533 def ip2py(self,source):
366 def ip2py(self,source):
534 """Convert input IPython source into valid Python."""
367 """Convert input IPython source into valid Python."""
535 out = []
368 out = []
536 newline = out.append
369 newline = out.append
537 #print 'IPSRC:\n',source,'\n###' # dbg
370 #print 'IPSRC:\n',source,'\n###' # dbg
538 # The input source must be first stripped of all bracketing whitespace
371 # The input source must be first stripped of all bracketing whitespace
539 # and turned into lines, so it looks to the parser like regular user
372 # and turned into lines, so it looks to the parser like regular user
540 # input
373 # input
541 for lnum,line in enumerate(source.strip().splitlines()):
374 for lnum,line in enumerate(source.strip().splitlines()):
542 newline(_ip.prefilter(line,lnum>0))
375 newline(_ip.prefilter(line,lnum>0))
543 newline('') # ensure a closing newline, needed by doctest
376 newline('') # ensure a closing newline, needed by doctest
544 #print "PYSRC:", '\n'.join(out) # dbg
377 #print "PYSRC:", '\n'.join(out) # dbg
545 return '\n'.join(out)
378 return '\n'.join(out)
546
379
547 def parse(self, string, name='<string>'):
380 def parse(self, string, name='<string>'):
548 """
381 """
549 Divide the given string into examples and intervening text,
382 Divide the given string into examples and intervening text,
550 and return them as a list of alternating Examples and strings.
383 and return them as a list of alternating Examples and strings.
551 Line numbers for the Examples are 0-based. The optional
384 Line numbers for the Examples are 0-based. The optional
552 argument `name` is a name identifying this string, and is only
385 argument `name` is a name identifying this string, and is only
553 used for error messages.
386 used for error messages.
554 """
387 """
555
388
556 #print 'Parse string:\n',string # dbg
389 #print 'Parse string:\n',string # dbg
557
390
558 string = string.expandtabs()
391 string = string.expandtabs()
559 # If all lines begin with the same indentation, then strip it.
392 # If all lines begin with the same indentation, then strip it.
560 min_indent = self._min_indent(string)
393 min_indent = self._min_indent(string)
561 if min_indent > 0:
394 if min_indent > 0:
562 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
395 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
563
396
564 output = []
397 output = []
565 charno, lineno = 0, 0
398 charno, lineno = 0, 0
566
399
567 # We make 'all random' tests by adding the '# random' mark to every
400 # We make 'all random' tests by adding the '# random' mark to every
568 # block of output in the test.
401 # block of output in the test.
569 if self._RANDOM_TEST.search(string):
402 if self._RANDOM_TEST.search(string):
570 random_marker = '\n# random'
403 random_marker = '\n# random'
571 else:
404 else:
572 random_marker = ''
405 random_marker = ''
573
406
574 # Whether to convert the input from ipython to python syntax
407 # Whether to convert the input from ipython to python syntax
575 ip2py = False
408 ip2py = False
576 # Find all doctest examples in the string. First, try them as Python
409 # Find all doctest examples in the string. First, try them as Python
577 # examples, then as IPython ones
410 # examples, then as IPython ones
578 terms = list(self._EXAMPLE_RE_PY.finditer(string))
411 terms = list(self._EXAMPLE_RE_PY.finditer(string))
579 if terms:
412 if terms:
580 # Normal Python example
413 # Normal Python example
581 #print '-'*70 # dbg
414 #print '-'*70 # dbg
582 #print 'PyExample, Source:\n',string # dbg
415 #print 'PyExample, Source:\n',string # dbg
583 #print '-'*70 # dbg
416 #print '-'*70 # dbg
584 Example = doctest.Example
417 Example = doctest.Example
585 else:
418 else:
586 # It's an ipython example. Note that IPExamples are run
419 # It's an ipython example. Note that IPExamples are run
587 # in-process, so their syntax must be turned into valid python.
420 # in-process, so their syntax must be turned into valid python.
588 # IPExternalExamples are run out-of-process (via pexpect) so they
421 # IPExternalExamples are run out-of-process (via pexpect) so they
589 # don't need any filtering (a real ipython will be executing them).
422 # don't need any filtering (a real ipython will be executing them).
590 terms = list(self._EXAMPLE_RE_IP.finditer(string))
423 terms = list(self._EXAMPLE_RE_IP.finditer(string))
591 if self._EXTERNAL_IP.search(string):
424 if self._EXTERNAL_IP.search(string):
592 #print '-'*70 # dbg
425 #print '-'*70 # dbg
593 #print 'IPExternalExample, Source:\n',string # dbg
426 #print 'IPExternalExample, Source:\n',string # dbg
594 #print '-'*70 # dbg
427 #print '-'*70 # dbg
595 Example = IPExternalExample
428 Example = IPExternalExample
596 else:
429 else:
597 #print '-'*70 # dbg
430 #print '-'*70 # dbg
598 #print 'IPExample, Source:\n',string # dbg
431 #print 'IPExample, Source:\n',string # dbg
599 #print '-'*70 # dbg
432 #print '-'*70 # dbg
600 Example = IPExample
433 Example = IPExample
601 ip2py = True
434 ip2py = True
602
435
603 for m in terms:
436 for m in terms:
604 # Add the pre-example text to `output`.
437 # Add the pre-example text to `output`.
605 output.append(string[charno:m.start()])
438 output.append(string[charno:m.start()])
606 # Update lineno (lines before this example)
439 # Update lineno (lines before this example)
607 lineno += string.count('\n', charno, m.start())
440 lineno += string.count('\n', charno, m.start())
608 # Extract info from the regexp match.
441 # Extract info from the regexp match.
609 (source, options, want, exc_msg) = \
442 (source, options, want, exc_msg) = \
610 self._parse_example(m, name, lineno,ip2py)
443 self._parse_example(m, name, lineno,ip2py)
611
444
612 # Append the random-output marker (it defaults to empty in most
445 # Append the random-output marker (it defaults to empty in most
613 # cases, it's only non-empty for 'all-random' tests):
446 # cases, it's only non-empty for 'all-random' tests):
614 want += random_marker
447 want += random_marker
615
448
616 if Example is IPExternalExample:
449 if Example is IPExternalExample:
617 options[doctest.NORMALIZE_WHITESPACE] = True
450 options[doctest.NORMALIZE_WHITESPACE] = True
618 want += '\n'
451 want += '\n'
619
452
620 # Create an Example, and add it to the list.
453 # Create an Example, and add it to the list.
621 if not self._IS_BLANK_OR_COMMENT(source):
454 if not self._IS_BLANK_OR_COMMENT(source):
622 output.append(Example(source, want, exc_msg,
455 output.append(Example(source, want, exc_msg,
623 lineno=lineno,
456 lineno=lineno,
624 indent=min_indent+len(m.group('indent')),
457 indent=min_indent+len(m.group('indent')),
625 options=options))
458 options=options))
626 # Update lineno (lines inside this example)
459 # Update lineno (lines inside this example)
627 lineno += string.count('\n', m.start(), m.end())
460 lineno += string.count('\n', m.start(), m.end())
628 # Update charno.
461 # Update charno.
629 charno = m.end()
462 charno = m.end()
630 # Add any remaining post-example text to `output`.
463 # Add any remaining post-example text to `output`.
631 output.append(string[charno:])
464 output.append(string[charno:])
632 return output
465 return output
633
466
634 def _parse_example(self, m, name, lineno,ip2py=False):
467 def _parse_example(self, m, name, lineno,ip2py=False):
635 """
468 """
636 Given a regular expression match from `_EXAMPLE_RE` (`m`),
469 Given a regular expression match from `_EXAMPLE_RE` (`m`),
637 return a pair `(source, want)`, where `source` is the matched
470 return a pair `(source, want)`, where `source` is the matched
638 example's source code (with prompts and indentation stripped);
471 example's source code (with prompts and indentation stripped);
639 and `want` is the example's expected output (with indentation
472 and `want` is the example's expected output (with indentation
640 stripped).
473 stripped).
641
474
642 `name` is the string's name, and `lineno` is the line number
475 `name` is the string's name, and `lineno` is the line number
643 where the example starts; both are used for error messages.
476 where the example starts; both are used for error messages.
644
477
645 Optional:
478 Optional:
646 `ip2py`: if true, filter the input via IPython to convert the syntax
479 `ip2py`: if true, filter the input via IPython to convert the syntax
647 into valid python.
480 into valid python.
648 """
481 """
649
482
650 # Get the example's indentation level.
483 # Get the example's indentation level.
651 indent = len(m.group('indent'))
484 indent = len(m.group('indent'))
652
485
653 # Divide source into lines; check that they're properly
486 # Divide source into lines; check that they're properly
654 # indented; and then strip their indentation & prompts.
487 # indented; and then strip their indentation & prompts.
655 source_lines = m.group('source').split('\n')
488 source_lines = m.group('source').split('\n')
656
489
657 # We're using variable-length input prompts
490 # We're using variable-length input prompts
658 ps1 = m.group('ps1')
491 ps1 = m.group('ps1')
659 ps2 = m.group('ps2')
492 ps2 = m.group('ps2')
660 ps1_len = len(ps1)
493 ps1_len = len(ps1)
661
494
662 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
495 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
663 if ps2:
496 if ps2:
664 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
497 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
665
498
666 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
499 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
667
500
668 if ip2py:
501 if ip2py:
669 # Convert source input from IPython into valid Python syntax
502 # Convert source input from IPython into valid Python syntax
670 source = self.ip2py(source)
503 source = self.ip2py(source)
671
504
672 # Divide want into lines; check that it's properly indented; and
505 # Divide want into lines; check that it's properly indented; and
673 # then strip the indentation. Spaces before the last newline should
506 # then strip the indentation. Spaces before the last newline should
674 # be preserved, so plain rstrip() isn't good enough.
507 # be preserved, so plain rstrip() isn't good enough.
675 want = m.group('want')
508 want = m.group('want')
676 want_lines = want.split('\n')
509 want_lines = want.split('\n')
677 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
510 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
678 del want_lines[-1] # forget final newline & spaces after it
511 del want_lines[-1] # forget final newline & spaces after it
679 self._check_prefix(want_lines, ' '*indent, name,
512 self._check_prefix(want_lines, ' '*indent, name,
680 lineno + len(source_lines))
513 lineno + len(source_lines))
681
514
682 # Remove ipython output prompt that might be present in the first line
515 # Remove ipython output prompt that might be present in the first line
683 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
516 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
684
517
685 want = '\n'.join([wl[indent:] for wl in want_lines])
518 want = '\n'.join([wl[indent:] for wl in want_lines])
686
519
687 # If `want` contains a traceback message, then extract it.
520 # If `want` contains a traceback message, then extract it.
688 m = self._EXCEPTION_RE.match(want)
521 m = self._EXCEPTION_RE.match(want)
689 if m:
522 if m:
690 exc_msg = m.group('msg')
523 exc_msg = m.group('msg')
691 else:
524 else:
692 exc_msg = None
525 exc_msg = None
693
526
694 # Extract options from the source.
527 # Extract options from the source.
695 options = self._find_options(source, name, lineno)
528 options = self._find_options(source, name, lineno)
696
529
697 return source, options, want, exc_msg
530 return source, options, want, exc_msg
698
531
699 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
532 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
700 """
533 """
701 Given the lines of a source string (including prompts and
534 Given the lines of a source string (including prompts and
702 leading indentation), check to make sure that every prompt is
535 leading indentation), check to make sure that every prompt is
703 followed by a space character. If any line is not followed by
536 followed by a space character. If any line is not followed by
704 a space character, then raise ValueError.
537 a space character, then raise ValueError.
705
538
706 Note: IPython-modified version which takes the input prompt length as a
539 Note: IPython-modified version which takes the input prompt length as a
707 parameter, so that prompts of variable length can be dealt with.
540 parameter, so that prompts of variable length can be dealt with.
708 """
541 """
709 space_idx = indent+ps1_len
542 space_idx = indent+ps1_len
710 min_len = space_idx+1
543 min_len = space_idx+1
711 for i, line in enumerate(lines):
544 for i, line in enumerate(lines):
712 if len(line) >= min_len and line[space_idx] != ' ':
545 if len(line) >= min_len and line[space_idx] != ' ':
713 raise ValueError('line %r of the docstring for %s '
546 raise ValueError('line %r of the docstring for %s '
714 'lacks blank after %s: %r' %
547 'lacks blank after %s: %r' %
715 (lineno+i+1, name,
548 (lineno+i+1, name,
716 line[indent:space_idx], line))
549 line[indent:space_idx], line))
717
550
718
551
719 SKIP = doctest.register_optionflag('SKIP')
552 SKIP = doctest.register_optionflag('SKIP')
720
553
721
554
722 class IPDocTestRunner(doctest.DocTestRunner,object):
555 class IPDocTestRunner(doctest.DocTestRunner,object):
723 """Test runner that synchronizes the IPython namespace with test globals.
556 """Test runner that synchronizes the IPython namespace with test globals.
724 """
557 """
725
558
726 def run(self, test, compileflags=None, out=None, clear_globs=True):
559 def run(self, test, compileflags=None, out=None, clear_globs=True):
727
560
728 # Hack: ipython needs access to the execution context of the example,
561 # Hack: ipython needs access to the execution context of the example,
729 # so that it can propagate user variables loaded by %run into
562 # so that it can propagate user variables loaded by %run into
730 # test.globs. We put them here into our modified %run as a function
563 # test.globs. We put them here into our modified %run as a function
731 # attribute. Our new %run will then only make the namespace update
564 # attribute. Our new %run will then only make the namespace update
732 # when called (rather than unconconditionally updating test.globs here
565 # when called (rather than unconconditionally updating test.globs here
733 # for all examples, most of which won't be calling %run anyway).
566 # for all examples, most of which won't be calling %run anyway).
734 _run_ns_sync.test_globs = test.globs
567 #_ip._ipdoctest_test_globs = test.globs
735 _run_ns_sync.test_filename = test.filename
568 #_ip._ipdoctest_test_filename = test.filename
569
570 test.globs.update(_ip.user_ns)
736
571
737 return super(IPDocTestRunner,self).run(test,
572 return super(IPDocTestRunner,self).run(test,
738 compileflags,out,clear_globs)
573 compileflags,out,clear_globs)
739
574
740
575
741 class DocFileCase(doctest.DocFileCase):
576 class DocFileCase(doctest.DocFileCase):
742 """Overrides to provide filename
577 """Overrides to provide filename
743 """
578 """
744 def address(self):
579 def address(self):
745 return (self._dt_test.filename, None, None)
580 return (self._dt_test.filename, None, None)
746
581
747
582
748 class ExtensionDoctest(doctests.Doctest):
583 class ExtensionDoctest(doctests.Doctest):
749 """Nose Plugin that supports doctests in extension modules.
584 """Nose Plugin that supports doctests in extension modules.
750 """
585 """
751 name = 'extdoctest' # call nosetests with --with-extdoctest
586 name = 'extdoctest' # call nosetests with --with-extdoctest
752 enabled = True
587 enabled = True
753
588
754 def __init__(self,exclude_patterns=None):
589 def __init__(self,exclude_patterns=None):
755 """Create a new ExtensionDoctest plugin.
590 """Create a new ExtensionDoctest plugin.
756
591
757 Parameters
592 Parameters
758 ----------
593 ----------
759
594
760 exclude_patterns : sequence of strings, optional
595 exclude_patterns : sequence of strings, optional
761 These patterns are compiled as regular expressions, subsequently used
596 These patterns are compiled as regular expressions, subsequently used
762 to exclude any filename which matches them from inclusion in the test
597 to exclude any filename which matches them from inclusion in the test
763 suite (using pattern.search(), NOT pattern.match() ).
598 suite (using pattern.search(), NOT pattern.match() ).
764 """
599 """
765
600
766 if exclude_patterns is None:
601 if exclude_patterns is None:
767 exclude_patterns = []
602 exclude_patterns = []
768 self.exclude_patterns = map(re.compile,exclude_patterns)
603 self.exclude_patterns = map(re.compile,exclude_patterns)
769 doctests.Doctest.__init__(self)
604 doctests.Doctest.__init__(self)
770
605
771 def options(self, parser, env=os.environ):
606 def options(self, parser, env=os.environ):
772 Plugin.options(self, parser, env)
607 Plugin.options(self, parser, env)
773 parser.add_option('--doctest-tests', action='store_true',
608 parser.add_option('--doctest-tests', action='store_true',
774 dest='doctest_tests',
609 dest='doctest_tests',
775 default=env.get('NOSE_DOCTEST_TESTS',True),
610 default=env.get('NOSE_DOCTEST_TESTS',True),
776 help="Also look for doctests in test modules. "
611 help="Also look for doctests in test modules. "
777 "Note that classes, methods and functions should "
612 "Note that classes, methods and functions should "
778 "have either doctests or non-doctest tests, "
613 "have either doctests or non-doctest tests, "
779 "not both. [NOSE_DOCTEST_TESTS]")
614 "not both. [NOSE_DOCTEST_TESTS]")
780 parser.add_option('--doctest-extension', action="append",
615 parser.add_option('--doctest-extension', action="append",
781 dest="doctestExtension",
616 dest="doctestExtension",
782 help="Also look for doctests in files with "
617 help="Also look for doctests in files with "
783 "this extension [NOSE_DOCTEST_EXTENSION]")
618 "this extension [NOSE_DOCTEST_EXTENSION]")
784 # Set the default as a list, if given in env; otherwise
619 # Set the default as a list, if given in env; otherwise
785 # an additional value set on the command line will cause
620 # an additional value set on the command line will cause
786 # an error.
621 # an error.
787 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
622 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
788 if env_setting is not None:
623 if env_setting is not None:
789 parser.set_defaults(doctestExtension=tolist(env_setting))
624 parser.set_defaults(doctestExtension=tolist(env_setting))
790
625
791
626
792 def configure(self, options, config):
627 def configure(self, options, config):
793 Plugin.configure(self, options, config)
628 Plugin.configure(self, options, config)
794 self.doctest_tests = options.doctest_tests
629 self.doctest_tests = options.doctest_tests
795 self.extension = tolist(options.doctestExtension)
630 self.extension = tolist(options.doctestExtension)
796
631
797 self.parser = doctest.DocTestParser()
632 self.parser = doctest.DocTestParser()
798 self.finder = DocTestFinder()
633 self.finder = DocTestFinder()
799 self.checker = IPDoctestOutputChecker()
634 self.checker = IPDoctestOutputChecker()
800 self.globs = None
635 self.globs = None
801 self.extraglobs = None
636 self.extraglobs = None
802
637
803
638
804 def loadTestsFromExtensionModule(self,filename):
639 def loadTestsFromExtensionModule(self,filename):
805 bpath,mod = os.path.split(filename)
640 bpath,mod = os.path.split(filename)
806 modname = os.path.splitext(mod)[0]
641 modname = os.path.splitext(mod)[0]
807 try:
642 try:
808 sys.path.append(bpath)
643 sys.path.append(bpath)
809 module = __import__(modname)
644 module = __import__(modname)
810 tests = list(self.loadTestsFromModule(module))
645 tests = list(self.loadTestsFromModule(module))
811 finally:
646 finally:
812 sys.path.pop()
647 sys.path.pop()
813 return tests
648 return tests
814
649
815 # NOTE: the method below is almost a copy of the original one in nose, with
650 # NOTE: the method below is almost a copy of the original one in nose, with
816 # a few modifications to control output checking.
651 # a few modifications to control output checking.
817
652
818 def loadTestsFromModule(self, module):
653 def loadTestsFromModule(self, module):
819 #print '*** ipdoctest - lTM',module # dbg
654 #print '*** ipdoctest - lTM',module # dbg
820
655
821 if not self.matches(module.__name__):
656 if not self.matches(module.__name__):
822 log.debug("Doctest doesn't want module %s", module)
657 log.debug("Doctest doesn't want module %s", module)
823 return
658 return
824
659
825 tests = self.finder.find(module,globs=self.globs,
660 tests = self.finder.find(module,globs=self.globs,
826 extraglobs=self.extraglobs)
661 extraglobs=self.extraglobs)
827 if not tests:
662 if not tests:
828 return
663 return
829
664
830 # always use whitespace and ellipsis options
665 # always use whitespace and ellipsis options
831 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
666 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
832
667
833 tests.sort()
668 tests.sort()
834 module_file = module.__file__
669 module_file = module.__file__
835 if module_file[-4:] in ('.pyc', '.pyo'):
670 if module_file[-4:] in ('.pyc', '.pyo'):
836 module_file = module_file[:-1]
671 module_file = module_file[:-1]
837 for test in tests:
672 for test in tests:
838 if not test.examples:
673 if not test.examples:
839 continue
674 continue
840 if not test.filename:
675 if not test.filename:
841 test.filename = module_file
676 test.filename = module_file
842
677
843 yield DocTestCase(test,
678 yield DocTestCase(test,
844 optionflags=optionflags,
679 optionflags=optionflags,
845 checker=self.checker)
680 checker=self.checker)
846
681
847
682
848 def loadTestsFromFile(self, filename):
683 def loadTestsFromFile(self, filename):
684 #print "ipdoctest - from file", filename # dbg
849 if is_extension_module(filename):
685 if is_extension_module(filename):
850 for t in self.loadTestsFromExtensionModule(filename):
686 for t in self.loadTestsFromExtensionModule(filename):
851 yield t
687 yield t
852 else:
688 else:
853 if self.extension and anyp(filename.endswith, self.extension):
689 if self.extension and anyp(filename.endswith, self.extension):
854 name = os.path.basename(filename)
690 name = os.path.basename(filename)
855 dh = open(filename)
691 dh = open(filename)
856 try:
692 try:
857 doc = dh.read()
693 doc = dh.read()
858 finally:
694 finally:
859 dh.close()
695 dh.close()
860 test = self.parser.get_doctest(
696 test = self.parser.get_doctest(
861 doc, globs={'__file__': filename}, name=name,
697 doc, globs={'__file__': filename}, name=name,
862 filename=filename, lineno=0)
698 filename=filename, lineno=0)
863 if test.examples:
699 if test.examples:
864 #print 'FileCase:',test.examples # dbg
700 #print 'FileCase:',test.examples # dbg
865 yield DocFileCase(test)
701 yield DocFileCase(test)
866 else:
702 else:
867 yield False # no tests to load
703 yield False # no tests to load
868
704
869 def wantFile(self,filename):
705 def wantFile(self,filename):
870 """Return whether the given filename should be scanned for tests.
706 """Return whether the given filename should be scanned for tests.
871
707
872 Modified version that accepts extension modules as valid containers for
708 Modified version that accepts extension modules as valid containers for
873 doctests.
709 doctests.
874 """
710 """
875 # print '*** ipdoctest- wantFile:',filename # dbg
711 #print '*** ipdoctest- wantFile:',filename # dbg
876
712
877 for pat in self.exclude_patterns:
713 for pat in self.exclude_patterns:
878 if pat.search(filename):
714 if pat.search(filename):
879 # print '###>>> SKIP:',filename # dbg
715 # print '###>>> SKIP:',filename # dbg
880 return False
716 return False
881
717
882 if is_extension_module(filename):
718 if is_extension_module(filename):
883 return True
719 return True
884 else:
720 else:
885 return doctests.Doctest.wantFile(self,filename)
721 return doctests.Doctest.wantFile(self,filename)
886
722
887
723
888 class IPythonDoctest(ExtensionDoctest):
724 class IPythonDoctest(ExtensionDoctest):
889 """Nose Plugin that supports doctests in extension modules.
725 """Nose Plugin that supports doctests in extension modules.
890 """
726 """
891 name = 'ipdoctest' # call nosetests with --with-ipdoctest
727 name = 'ipdoctest' # call nosetests with --with-ipdoctest
892 enabled = True
728 enabled = True
893
729
894 def makeTest(self, obj, parent):
730 def makeTest(self, obj, parent):
895 """Look for doctests in the given object, which will be a
731 """Look for doctests in the given object, which will be a
896 function, method or class.
732 function, method or class.
897 """
733 """
734 #print 'Plugin analyzing:', obj, parent # dbg
898 # always use whitespace and ellipsis options
735 # always use whitespace and ellipsis options
899 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
736 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
900
737
901 doctests = self.finder.find(obj, module=getmodule(parent))
738 doctests = self.finder.find(obj, module=getmodule(parent))
902 if doctests:
739 if doctests:
903 for test in doctests:
740 for test in doctests:
904 if len(test.examples) == 0:
741 if len(test.examples) == 0:
905 continue
742 continue
906
743
907 yield DocTestCase(test, obj=obj,
744 yield DocTestCase(test, obj=obj,
908 optionflags=optionflags,
745 optionflags=optionflags,
909 checker=self.checker)
746 checker=self.checker)
910
747
911 def options(self, parser, env=os.environ):
748 def options(self, parser, env=os.environ):
749 #print "Options for nose plugin:", self.name # dbg
912 Plugin.options(self, parser, env)
750 Plugin.options(self, parser, env)
913 parser.add_option('--ipdoctest-tests', action='store_true',
751 parser.add_option('--ipdoctest-tests', action='store_true',
914 dest='ipdoctest_tests',
752 dest='ipdoctest_tests',
915 default=env.get('NOSE_IPDOCTEST_TESTS',True),
753 default=env.get('NOSE_IPDOCTEST_TESTS',True),
916 help="Also look for doctests in test modules. "
754 help="Also look for doctests in test modules. "
917 "Note that classes, methods and functions should "
755 "Note that classes, methods and functions should "
918 "have either doctests or non-doctest tests, "
756 "have either doctests or non-doctest tests, "
919 "not both. [NOSE_IPDOCTEST_TESTS]")
757 "not both. [NOSE_IPDOCTEST_TESTS]")
920 parser.add_option('--ipdoctest-extension', action="append",
758 parser.add_option('--ipdoctest-extension', action="append",
921 dest="ipdoctest_extension",
759 dest="ipdoctest_extension",
922 help="Also look for doctests in files with "
760 help="Also look for doctests in files with "
923 "this extension [NOSE_IPDOCTEST_EXTENSION]")
761 "this extension [NOSE_IPDOCTEST_EXTENSION]")
924 # Set the default as a list, if given in env; otherwise
762 # Set the default as a list, if given in env; otherwise
925 # an additional value set on the command line will cause
763 # an additional value set on the command line will cause
926 # an error.
764 # an error.
927 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
765 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
928 if env_setting is not None:
766 if env_setting is not None:
929 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
767 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
930
768
931 def configure(self, options, config):
769 def configure(self, options, config):
770 #print "Configuring nose plugin:", self.name # dbg
932 Plugin.configure(self, options, config)
771 Plugin.configure(self, options, config)
933 self.doctest_tests = options.ipdoctest_tests
772 self.doctest_tests = options.ipdoctest_tests
934 self.extension = tolist(options.ipdoctest_extension)
773 self.extension = tolist(options.ipdoctest_extension)
935
774
936 self.parser = IPDocTestParser()
775 self.parser = IPDocTestParser()
937 self.finder = DocTestFinder(parser=self.parser)
776 self.finder = DocTestFinder(parser=self.parser)
938 self.checker = IPDoctestOutputChecker()
777 self.checker = IPDoctestOutputChecker()
939 self.globs = None
778 self.globs = None
940 self.extraglobs = None
779 self.extraglobs = None
@@ -1,132 +1,221 b''
1 """Generic testing tools that do NOT depend on Twisted.
1 """Generic testing tools that do NOT depend on Twisted.
2
2
3 In particular, this module exposes a set of top-level assert* functions that
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
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).
5 nose can not, at least as of nose 0.10.4).
6
6
7 Note: our testing package contains testing.util, which does depend on Twisted
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
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
9 tools that only depend on nose, IPython or the standard library should go here
10 instead.
10 instead.
11
11
12
12
13 Authors
13 Authors
14 -------
14 -------
15 - Fernando Perez <Fernando.Perez@berkeley.edu>
15 - Fernando Perez <Fernando.Perez@berkeley.edu>
16 """
16 """
17
17
18 #*****************************************************************************
18 #*****************************************************************************
19 # Copyright (C) 2009 The IPython Development Team
19 # Copyright (C) 2009 The IPython Development Team
20 #
20 #
21 # Distributed under the terms of the BSD License. The full license is in
21 # Distributed under the terms of the BSD License. The full license is in
22 # the file COPYING, distributed as part of this software.
22 # the file COPYING, distributed as part of this software.
23 #*****************************************************************************
23 #*****************************************************************************
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Required modules and packages
26 # Required modules and packages
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28
28
29 import os
29 import os
30 import re
30 import re
31 import sys
31 import sys
32 import tempfile
32
33
33 import nose.tools as nt
34 import nose.tools as nt
34
35
35 from IPython.utils import genutils
36 from IPython.utils import genutils, platutils
36
37
37 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
38 # Globals
39 # Globals
39 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
40
41
41 # Make a bunch of nose.tools assert wrappers that can be used in test
42 # Make a bunch of nose.tools assert wrappers that can be used in test
42 # generators. This will expose an assert* function for each one in nose.tools.
43 # generators. This will expose an assert* function for each one in nose.tools.
43
44
44 _tpl = """
45 _tpl = """
45 def %(name)s(*a,**kw):
46 def %(name)s(*a,**kw):
46 return nt.%(name)s(*a,**kw)
47 return nt.%(name)s(*a,**kw)
47 """
48 """
48
49
49 for _x in [a for a in dir(nt) if a.startswith('assert')]:
50 for _x in [a for a in dir(nt) if a.startswith('assert')]:
50 exec _tpl % dict(name=_x)
51 exec _tpl % dict(name=_x)
51
52
52 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
53 # Functions and classes
54 # Functions and classes
54 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
55
56
56
57
57 def full_path(startPath,files):
58 def full_path(startPath,files):
58 """Make full paths for all the listed files, based on startPath.
59 """Make full paths for all the listed files, based on startPath.
59
60
60 Only the base part of startPath is kept, since this routine is typically
61 Only the base part of startPath is kept, since this routine is typically
61 used with a script's __file__ variable as startPath. The base of startPath
62 used with a script's __file__ variable as startPath. The base of startPath
62 is then prepended to all the listed files, forming the output list.
63 is then prepended to all the listed files, forming the output list.
63
64
64 Parameters
65 Parameters
65 ----------
66 ----------
66 startPath : string
67 startPath : string
67 Initial path to use as the base for the results. This path is split
68 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 using os.path.split() and only its first component is kept.
69
70
70 files : string or list
71 files : string or list
71 One or more files.
72 One or more files.
72
73
73 Examples
74 Examples
74 --------
75 --------
75
76
76 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
77 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
77 ['/foo/a.txt', '/foo/b.txt']
78 ['/foo/a.txt', '/foo/b.txt']
78
79
79 >>> full_path('/foo',['a.txt','b.txt'])
80 >>> full_path('/foo',['a.txt','b.txt'])
80 ['/a.txt', '/b.txt']
81 ['/a.txt', '/b.txt']
81
82
82 If a single file is given, the output is still a list:
83 If a single file is given, the output is still a list:
83 >>> full_path('/foo','a.txt')
84 >>> full_path('/foo','a.txt')
84 ['/a.txt']
85 ['/a.txt']
85 """
86 """
86
87
87 files = genutils.list_strings(files)
88 files = genutils.list_strings(files)
88 base = os.path.split(startPath)[0]
89 base = os.path.split(startPath)[0]
89 return [ os.path.join(base,f) for f in files ]
90 return [ os.path.join(base,f) for f in files ]
90
91
91
92
92 def parse_test_output(txt):
93 def parse_test_output(txt):
93 """Parse the output of a test run and return errors, failures.
94 """Parse the output of a test run and return errors, failures.
94
95
95 Parameters
96 Parameters
96 ----------
97 ----------
97 txt : str
98 txt : str
98 Text output of a test run, assumed to contain a line of one of the
99 Text output of a test run, assumed to contain a line of one of the
99 following forms::
100 following forms::
100 'FAILED (errors=1)'
101 'FAILED (errors=1)'
101 'FAILED (failures=1)'
102 'FAILED (failures=1)'
102 'FAILED (errors=1, failures=1)'
103 'FAILED (errors=1, failures=1)'
103
104
104 Returns
105 Returns
105 -------
106 -------
106 nerr, nfail: number of errors and failures.
107 nerr, nfail: number of errors and failures.
107 """
108 """
108
109
109 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
110 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
110 if err_m:
111 if err_m:
111 nerr = int(err_m.group(1))
112 nerr = int(err_m.group(1))
112 nfail = 0
113 nfail = 0
113 return nerr, nfail
114 return nerr, nfail
114
115
115 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
116 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
116 if fail_m:
117 if fail_m:
117 nerr = 0
118 nerr = 0
118 nfail = int(fail_m.group(1))
119 nfail = int(fail_m.group(1))
119 return nerr, nfail
120 return nerr, nfail
120
121
121 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
122 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
122 re.MULTILINE)
123 re.MULTILINE)
123 if both_m:
124 if both_m:
124 nerr = int(both_m.group(1))
125 nerr = int(both_m.group(1))
125 nfail = int(both_m.group(2))
126 nfail = int(both_m.group(2))
126 return nerr, nfail
127 return nerr, nfail
127
128
128 # If the input didn't match any of these forms, assume no error/failures
129 # If the input didn't match any of these forms, assume no error/failures
129 return 0, 0
130 return 0, 0
130
131
132
131 # So nose doesn't think this is a test
133 # So nose doesn't think this is a test
132 parse_test_output.__test__ = False
134 parse_test_output.__test__ = False
135
136
137 def temp_pyfile(src, ext='.py'):
138 """Make a temporary python file, return filename and filehandle.
139
140 Parameters
141 ----------
142 src : string or list of strings (no need for ending newlines if list)
143 Source code to be written to the file.
144
145 ext : optional, string
146 Extension for the generated file.
147
148 Returns
149 -------
150 (filename, open filehandle)
151 It is the caller's responsibility to close the open file and unlink it.
152 """
153 fname = tempfile.mkstemp(ext)[1]
154 f = open(fname,'w')
155 f.write(src)
156 f.flush()
157 return fname, f
158
159
160 def default_argv():
161 """Return a valid default argv for creating testing instances of ipython"""
162
163 # Get the install directory for the user configuration and tell ipython to
164 # use the default profile from there.
165 from IPython.config import default
166 ipcdir = os.path.dirname(default.__file__)
167 ipconf = os.path.join(ipcdir,'ipython_config.py')
168 #print 'conf:',ipconf # dbg
169 return ['--colors=NoColor', '--no-term-title','--no-banner',
170 '--config-file=%s' % ipconf, '--autocall=0', '--quick']
171
172
173 def ipexec(fname):
174 """Utility to call 'ipython filename'.
175
176 Starts IPython witha minimal and safe configuration to make startup as fast
177 as possible.
178
179 Note that this starts IPython in a subprocess!
180
181 Parameters
182 ----------
183 fname : str
184 Name of file to be executed (should have .py or .ipy extension).
185
186 Returns
187 -------
188 (stdout, stderr) of ipython subprocess.
189 """
190 _ip = get_ipython()
191 test_dir = os.path.dirname(__file__)
192 full_fname = os.path.join(test_dir, fname)
193 ipython_cmd = platutils.find_cmd('ipython')
194 cmdargs = ' '.join(default_argv())
195 return genutils.getoutputerror('%s %s' % (ipython_cmd, full_fname))
196
197
198 def ipexec_validate(fname, expected_out, expected_err=None):
199 """Utility to call 'ipython filename' and validate output/error.
200
201 This function raises an AssertionError if the validation fails.
202
203 Note that this starts IPython in a subprocess!
204
205 Parameters
206 ----------
207 fname : str
208 Name of the file to be executed (should have .py or .ipy extension).
209
210 expected_out : str
211 Expected stdout of the process.
212
213 Returns
214 -------
215 None
216 """
217
218 out, err = ipexec(fname)
219 nt.assert_equals(out.strip(), expected_out.strip())
220 if expected_err:
221 nt.assert_equals(err.strip(), expected_err.strip())
General Comments 0
You need to be logged in to leave comments. Login now