##// END OF EJS Templates
Fix small bug in test suite for calling ipython's getoutput.x
Fernando Perez -
Show More
@@ -1,182 +1,182 b''
1 """Global IPython app to support test running.
1 """Global IPython app to support test running.
2
2
3 We must start our own ipython object and heavily muck with it so that all the
3 We must start our own ipython object and heavily muck with it so that all the
4 modifications IPython makes to system behavior don't send the doctest machinery
4 modifications IPython makes to system behavior don't send the doctest machinery
5 into a fit. This code should be considered a gross hack, but it gets the job
5 into a fit. This code should be considered a gross hack, but it gets the job
6 done.
6 done.
7 """
7 """
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9 from __future__ import print_function
9 from __future__ import print_function
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2009-2010 The IPython Development Team
12 # Copyright (C) 2009-2010 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 # stdlib
22 # stdlib
23 import __builtin__
23 import __builtin__
24 import os
24 import os
25 import sys
25 import sys
26 from types import MethodType
26 from types import MethodType
27
27
28 # our own
28 # our own
29 from . import tools
29 from . import tools
30
30
31 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
31 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Functions
34 # Functions
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36
36
37 # Hack to modify the %run command so we can sync the user's namespace with the
37 # Hack to modify the %run command so we can sync the user's namespace with the
38 # test globals. Once we move over to a clean magic system, this will be done
38 # test globals. Once we move over to a clean magic system, this will be done
39 # with much less ugliness.
39 # with much less ugliness.
40
40
41 class py_file_finder(object):
41 class py_file_finder(object):
42 def __init__(self,test_filename):
42 def __init__(self,test_filename):
43 self.test_filename = test_filename
43 self.test_filename = test_filename
44
44
45 def __call__(self,name):
45 def __call__(self,name):
46 from IPython.utils.path import get_py_filename
46 from IPython.utils.path import get_py_filename
47 try:
47 try:
48 return get_py_filename(name)
48 return get_py_filename(name)
49 except IOError:
49 except IOError:
50 test_dir = os.path.dirname(self.test_filename)
50 test_dir = os.path.dirname(self.test_filename)
51 new_path = os.path.join(test_dir,name)
51 new_path = os.path.join(test_dir,name)
52 return get_py_filename(new_path)
52 return get_py_filename(new_path)
53
53
54
54
55 def _run_ns_sync(self,arg_s,runner=None):
55 def _run_ns_sync(self,arg_s,runner=None):
56 """Modified version of %run that syncs testing namespaces.
56 """Modified version of %run that syncs testing namespaces.
57
57
58 This is strictly needed for running doctests that call %run.
58 This is strictly needed for running doctests that call %run.
59 """
59 """
60 #print('in run_ns_sync', arg_s, file=sys.stderr) # dbg
60 #print('in run_ns_sync', arg_s, file=sys.stderr) # dbg
61 finder = py_file_finder(arg_s)
61 finder = py_file_finder(arg_s)
62 return get_ipython().magic_run_ori(arg_s, runner, finder)
62 return get_ipython().magic_run_ori(arg_s, runner, finder)
63
63
64
64
65 class ipnsdict(dict):
65 class ipnsdict(dict):
66 """A special subclass of dict for use as an IPython namespace in doctests.
66 """A special subclass of dict for use as an IPython namespace in doctests.
67
67
68 This subclass adds a simple checkpointing capability so that when testing
68 This subclass adds a simple checkpointing capability so that when testing
69 machinery clears it (we use it as the test execution context), it doesn't
69 machinery clears it (we use it as the test execution context), it doesn't
70 get completely destroyed.
70 get completely destroyed.
71 """
71 """
72
72
73 def __init__(self,*a):
73 def __init__(self,*a):
74 dict.__init__(self,*a)
74 dict.__init__(self,*a)
75 self._savedict = {}
75 self._savedict = {}
76
76
77 def clear(self):
77 def clear(self):
78 dict.clear(self)
78 dict.clear(self)
79 self.update(self._savedict)
79 self.update(self._savedict)
80
80
81 def _checkpoint(self):
81 def _checkpoint(self):
82 self._savedict.clear()
82 self._savedict.clear()
83 self._savedict.update(self)
83 self._savedict.update(self)
84
84
85 def update(self,other):
85 def update(self,other):
86 self._checkpoint()
86 self._checkpoint()
87 dict.update(self,other)
87 dict.update(self,other)
88
88
89 # If '_' is in the namespace, python won't set it when executing code,
89 # If '_' is in the namespace, python won't set it when executing code,
90 # and we have examples that test it. So we ensure that the namespace
90 # and we have examples that test it. So we ensure that the namespace
91 # is always 'clean' of it before it's used for test code execution.
91 # is always 'clean' of it before it's used for test code execution.
92 self.pop('_',None)
92 self.pop('_',None)
93
93
94 # The builtins namespace must *always* be the real __builtin__ module,
94 # The builtins namespace must *always* be the real __builtin__ module,
95 # else weird stuff happens. The main ipython code does have provisions
95 # else weird stuff happens. The main ipython code does have provisions
96 # to ensure this after %run, but since in this class we do some
96 # to ensure this after %run, but since in this class we do some
97 # aggressive low-level cleaning of the execution namespace, we need to
97 # aggressive low-level cleaning of the execution namespace, we need to
98 # correct for that ourselves, to ensure consitency with the 'real'
98 # correct for that ourselves, to ensure consitency with the 'real'
99 # ipython.
99 # ipython.
100 self['__builtins__'] = __builtin__
100 self['__builtins__'] = __builtin__
101
101
102
102
103 def get_ipython():
103 def get_ipython():
104 # This will get replaced by the real thing once we start IPython below
104 # This will get replaced by the real thing once we start IPython below
105 return start_ipython()
105 return start_ipython()
106
106
107
107
108 # A couple of methods to override those in the running IPython to interact
108 # A couple of methods to override those in the running IPython to interact
109 # better with doctest (doctest captures on raw stdout, so we need to direct
109 # better with doctest (doctest captures on raw stdout, so we need to direct
110 # various types of output there otherwise it will miss them).
110 # various types of output there otherwise it will miss them).
111
111
112 def xsys(self, cmd):
112 def xsys(self, cmd):
113 """Replace the default system call with a capturing one for doctest.
113 """Replace the default system call with a capturing one for doctest.
114 """
114 """
115 # We use getoutput, but we need to strip it because pexpect captures
115 # We use getoutput, but we need to strip it because pexpect captures
116 # the trailing newline differently from commands.getoutput
116 # the trailing newline differently from commands.getoutput
117 print(self.getoutput(cmd).rstrip(), end='', file=sys.stdout)
117 print(self.getoutput(cmd, split=False).rstrip(), end='', file=sys.stdout)
118 sys.stdout.flush()
118 sys.stdout.flush()
119
119
120
120
121 def _showtraceback(self, etype, evalue, stb):
121 def _showtraceback(self, etype, evalue, stb):
122 """Print the traceback purely on stdout for doctest to capture it.
122 """Print the traceback purely on stdout for doctest to capture it.
123 """
123 """
124 print(self.InteractiveTB.stb2text(stb), file=sys.stdout)
124 print(self.InteractiveTB.stb2text(stb), file=sys.stdout)
125
125
126
126
127 def start_ipython():
127 def start_ipython():
128 """Start a global IPython shell, which we need for IPython-specific syntax.
128 """Start a global IPython shell, which we need for IPython-specific syntax.
129 """
129 """
130 global get_ipython
130 global get_ipython
131
131
132 # This function should only ever run once!
132 # This function should only ever run once!
133 if hasattr(start_ipython, 'already_called'):
133 if hasattr(start_ipython, 'already_called'):
134 return
134 return
135 start_ipython.already_called = True
135 start_ipython.already_called = True
136
136
137 # Store certain global objects that IPython modifies
137 # Store certain global objects that IPython modifies
138 _displayhook = sys.displayhook
138 _displayhook = sys.displayhook
139 _excepthook = sys.excepthook
139 _excepthook = sys.excepthook
140 _main = sys.modules.get('__main__')
140 _main = sys.modules.get('__main__')
141
141
142 # Create custom argv and namespaces for our IPython to be test-friendly
142 # Create custom argv and namespaces for our IPython to be test-friendly
143 config = tools.default_config()
143 config = tools.default_config()
144
144
145 # Create and initialize our test-friendly IPython instance.
145 # Create and initialize our test-friendly IPython instance.
146 shell = TerminalInteractiveShell.instance(config=config,
146 shell = TerminalInteractiveShell.instance(config=config,
147 user_ns=ipnsdict(),
147 user_ns=ipnsdict(),
148 user_global_ns={}
148 user_global_ns={}
149 )
149 )
150
150
151 # A few more tweaks needed for playing nicely with doctests...
151 # A few more tweaks needed for playing nicely with doctests...
152
152
153 # These traps are normally only active for interactive use, set them
153 # These traps are normally only active for interactive use, set them
154 # permanently since we'll be mocking interactive sessions.
154 # permanently since we'll be mocking interactive sessions.
155 shell.builtin_trap.activate()
155 shell.builtin_trap.activate()
156
156
157 # Modify the IPython system call with one that uses getoutput, so that we
157 # Modify the IPython system call with one that uses getoutput, so that we
158 # can capture subcommands and print them to Python's stdout, otherwise the
158 # can capture subcommands and print them to Python's stdout, otherwise the
159 # doctest machinery would miss them.
159 # doctest machinery would miss them.
160 shell.system = MethodType(xsys, shell, TerminalInteractiveShell)
160 shell.system = MethodType(xsys, shell, TerminalInteractiveShell)
161
161
162
162
163 shell._showtraceback = MethodType(_showtraceback, shell,
163 shell._showtraceback = MethodType(_showtraceback, shell,
164 TerminalInteractiveShell)
164 TerminalInteractiveShell)
165
165
166 # IPython is ready, now clean up some global state...
166 # IPython is ready, now clean up some global state...
167
167
168 # Deactivate the various python system hooks added by ipython for
168 # Deactivate the various python system hooks added by ipython for
169 # interactive convenience so we don't confuse the doctest system
169 # interactive convenience so we don't confuse the doctest system
170 sys.modules['__main__'] = _main
170 sys.modules['__main__'] = _main
171 sys.displayhook = _displayhook
171 sys.displayhook = _displayhook
172 sys.excepthook = _excepthook
172 sys.excepthook = _excepthook
173
173
174 # So that ipython magics and aliases can be doctested (they work by making
174 # So that ipython magics and aliases can be doctested (they work by making
175 # a call into a global _ip object). Also make the top-level get_ipython
175 # a call into a global _ip object). Also make the top-level get_ipython
176 # now return this without recursively calling here again.
176 # now return this without recursively calling here again.
177 _ip = shell
177 _ip = shell
178 get_ipython = _ip.get_ipython
178 get_ipython = _ip.get_ipython
179 __builtin__._ip = _ip
179 __builtin__._ip = _ip
180 __builtin__.get_ipython = get_ipython
180 __builtin__.get_ipython = get_ipython
181
181
182 return _ip
182 return _ip
General Comments 0
You need to be logged in to leave comments. Login now