##// END OF EJS Templates
Add file I forgot! Thanks to J. Hunter for report.
Fernando Perez -
Show More
@@ -0,0 +1,169 b''
1 """Global IPython app to support test running.
2
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
5 into a fit. This code should be considered a gross hack, but it gets the job
6 done.
7 """
8
9 from __future__ import absolute_import
10
11 #-----------------------------------------------------------------------------
12 # Module imports
13 #-----------------------------------------------------------------------------
14
15 # From the standard library
16 import __builtin__
17 import commands
18 import new
19 import os
20 import sys
21
22 from . import tools
23
24 #-----------------------------------------------------------------------------
25 # Functions
26 #-----------------------------------------------------------------------------
27
28 # Hack to modify the %run command so we can sync the user's namespace with the
29 # test globals. Once we move over to a clean magic system, this will be done
30 # with much less ugliness.
31
32 class py_file_finder(object):
33 def __init__(self,test_filename):
34 self.test_filename = test_filename
35
36 def __call__(self,name):
37 from IPython.utils.genutils import get_py_filename
38 try:
39 return get_py_filename(name)
40 except IOError:
41 test_dir = os.path.dirname(self.test_filename)
42 new_path = os.path.join(test_dir,name)
43 return get_py_filename(new_path)
44
45
46 def _run_ns_sync(self,arg_s,runner=None):
47 """Modified version of %run that syncs testing namespaces.
48
49 This is strictly needed for running doctests that call %run.
50 """
51 #print >> sys.stderr, 'in run_ns_sync', arg_s # dbg
52
53 _ip = get_ipython()
54 finder = py_file_finder(arg_s)
55 out = _ip.magic_run_ori(arg_s,runner,finder)
56 return out
57
58
59 class ipnsdict(dict):
60 """A special subclass of dict for use as an IPython namespace in doctests.
61
62 This subclass adds a simple checkpointing capability so that when testing
63 machinery clears it (we use it as the test execution context), it doesn't
64 get completely destroyed.
65 """
66
67 def __init__(self,*a):
68 dict.__init__(self,*a)
69 self._savedict = {}
70
71 def clear(self):
72 dict.clear(self)
73 self.update(self._savedict)
74
75 def _checkpoint(self):
76 self._savedict.clear()
77 self._savedict.update(self)
78
79 def update(self,other):
80 self._checkpoint()
81 dict.update(self,other)
82
83 # If '_' is in the namespace, python won't set it when executing code,
84 # and we have examples that test it. So we ensure that the namespace
85 # is always 'clean' of it before it's used for test code execution.
86 self.pop('_',None)
87
88 # The builtins namespace must *always* be the real __builtin__ module,
89 # else weird stuff happens. The main ipython code does have provisions
90 # to ensure this after %run, but since in this class we do some
91 # aggressive low-level cleaning of the execution namespace, we need to
92 # correct for that ourselves, to ensure consitency with the 'real'
93 # ipython.
94 self['__builtins__'] = __builtin__
95
96
97 def get_ipython():
98 # This will get replaced by the real thing once we start IPython below
99 return None
100
101 def start_ipython():
102 """Start a global IPython shell, which we need for IPython-specific syntax.
103 """
104 global get_ipython
105
106 # This function should only ever run once!
107 if hasattr(start_ipython,'already_called'):
108 return
109 start_ipython.already_called = True
110
111 # Ok, first time we're called, go ahead
112 from IPython.core import ipapp, iplib
113
114 def xsys(cmd):
115 """Execute a command and print its output.
116
117 This is just a convenience function to replace the IPython system call
118 with one that is more doctest-friendly.
119 """
120 cmd = _ip.var_expand(cmd,depth=1)
121 sys.stdout.write(commands.getoutput(cmd))
122 sys.stdout.flush()
123
124 # Store certain global objects that IPython modifies
125 _displayhook = sys.displayhook
126 _excepthook = sys.excepthook
127 _main = sys.modules.get('__main__')
128
129 argv = tools.default_argv()
130
131 # Start IPython instance. We customize it to start with minimal frills.
132 user_ns,global_ns = iplib.make_user_namespaces(ipnsdict(),{})
133 ip = ipapp.IPythonApp(argv, user_ns=user_ns, user_global_ns=global_ns)
134 ip.initialize()
135 ip.shell.builtin_trap.set()
136 # Butcher the logger
137 ip.shell.log = lambda *a,**k: None
138
139 # Deactivate the various python system hooks added by ipython for
140 # interactive convenience so we don't confuse the doctest system
141 sys.modules['__main__'] = _main
142 sys.displayhook = _displayhook
143 sys.excepthook = _excepthook
144
145 # So that ipython magics and aliases can be doctested (they work by making
146 # a call into a global _ip object)
147
148 _ip = ip.shell
149 get_ipython = _ip.get_ipython
150 __builtin__._ip = _ip
151 __builtin__.get_ipython = get_ipython
152
153 # Modify the IPython system call with one that uses getoutput, so that we
154 # can capture subcommands and print them to Python's stdout, otherwise the
155 # doctest machinery would miss them.
156 ip.shell.system = xsys
157
158 # Also patch our %run function in.
159 ## im = new.instancemethod(_run_ns_sync,_ip, _ip.__class__)
160 ## ip.shell.magic_run_ori = _ip.magic_run
161 ## ip.shell.magic_run = im
162
163 # XXX - For some very bizarre reason, the loading of %history by default is
164 # failing. This needs to be fixed later, but for now at least this ensures
165 # that tests that use %hist run to completion.
166 from IPython.core import history
167 history.init_ipython(ip.shell)
168 if not hasattr(ip.shell,'magic_history'):
169 raise RuntimeError("Can't load magics, aborting")
General Comments 0
You need to be logged in to leave comments. Login now