~ipython-contrib/ipython/traitlets-rename

« back to all changes in this revision

Viewing changes to IPython/testing/globalipapp.py

  • Committer: Dav Clark
  • Date: 2010-01-14 04:02:25 UTC
  • mfrom: (1102.1.220 trunk-dev)
  • Revision ID: davclark@berkeley.edu-20100114040225-dl8eyu6eao2oszra
mergedĀ fromĀ ~fdo.perez/ipython/trunk-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
from IPython.utils.genutils import Term
 
24
 
 
25
#-----------------------------------------------------------------------------
 
26
# Functions
 
27
#-----------------------------------------------------------------------------
 
28
 
 
29
# Hack to modify the %run command so we can sync the user's namespace with the
 
30
# test globals.  Once we move over to a clean magic system, this will be done
 
31
# with much less ugliness.
 
32
 
 
33
class py_file_finder(object):
 
34
    def __init__(self,test_filename):
 
35
        self.test_filename = test_filename
 
36
        
 
37
    def __call__(self,name):
 
38
        from IPython.utils.genutils import get_py_filename
 
39
        try:
 
40
            return get_py_filename(name)
 
41
        except IOError:
 
42
            test_dir = os.path.dirname(self.test_filename)
 
43
            new_path = os.path.join(test_dir,name)
 
44
            return get_py_filename(new_path)
 
45
    
 
46
 
 
47
def _run_ns_sync(self,arg_s,runner=None):
 
48
    """Modified version of %run that syncs testing namespaces.
 
49
 
 
50
    This is strictly needed for running doctests that call %run.
 
51
    """
 
52
    #print >> sys.stderr,  'in run_ns_sync', arg_s  # dbg
 
53
    
 
54
    _ip = get_ipython()
 
55
    finder = py_file_finder(arg_s)
 
56
    out = _ip.magic_run_ori(arg_s,runner,finder)
 
57
    return out
 
58
 
 
59
 
 
60
class ipnsdict(dict):
 
61
    """A special subclass of dict for use as an IPython namespace in doctests.
 
62
 
 
63
    This subclass adds a simple checkpointing capability so that when testing
 
64
    machinery clears it (we use it as the test execution context), it doesn't
 
65
    get completely destroyed.
 
66
    """
 
67
    
 
68
    def __init__(self,*a):
 
69
        dict.__init__(self,*a)
 
70
        self._savedict = {}
 
71
        
 
72
    def clear(self):
 
73
        dict.clear(self)
 
74
        self.update(self._savedict)
 
75
        
 
76
    def _checkpoint(self):
 
77
        self._savedict.clear()
 
78
        self._savedict.update(self)
 
79
 
 
80
    def update(self,other):
 
81
        self._checkpoint()
 
82
        dict.update(self,other)
 
83
 
 
84
        # If '_' is in the namespace, python won't set it when executing code,
 
85
        # and we have examples that test it.  So we ensure that the namespace
 
86
        # is always 'clean' of it before it's used for test code execution.
 
87
        self.pop('_',None)
 
88
 
 
89
        # The builtins namespace must *always* be the real __builtin__ module,
 
90
        # else weird stuff happens.  The main ipython code does have provisions
 
91
        # to ensure this after %run, but since in this class we do some
 
92
        # aggressive low-level cleaning of the execution namespace, we need to
 
93
        # correct for that ourselves, to ensure consitency with the 'real'
 
94
        # ipython.
 
95
        self['__builtins__'] = __builtin__
 
96
        
 
97
 
 
98
def get_ipython():
 
99
    # This will get replaced by the real thing once we start IPython below
 
100
    return start_ipython()
 
101
 
 
102
def start_ipython():
 
103
    """Start a global IPython shell, which we need for IPython-specific syntax.
 
104
    """
 
105
    global get_ipython
 
106
 
 
107
    # This function should only ever run once!
 
108
    if hasattr(start_ipython,'already_called'):
 
109
        return
 
110
    start_ipython.already_called = True
 
111
 
 
112
    # Ok,  first time we're called, go ahead
 
113
    from IPython.core import ipapp, iplib
 
114
    
 
115
    def xsys(cmd):
 
116
        """Execute a command and print its output.
 
117
 
 
118
        This is just a convenience function to replace the IPython system call
 
119
        with one that is more doctest-friendly.
 
120
        """
 
121
        cmd = _ip.var_expand(cmd,depth=1)
 
122
        sys.stdout.write(commands.getoutput(cmd))
 
123
        sys.stdout.flush()
 
124
 
 
125
    # Store certain global objects that IPython modifies
 
126
    _displayhook = sys.displayhook
 
127
    _excepthook = sys.excepthook
 
128
    _main = sys.modules.get('__main__')
 
129
 
 
130
    # Create custom argv and namespaces for our IPython to be test-friendly
 
131
    argv = tools.default_argv()
 
132
    user_ns, global_ns = iplib.make_user_namespaces(ipnsdict(), {})
 
133
    
 
134
    # Create and initialize our test-friendly IPython instance.
 
135
    ip = ipapp.IPythonApp(argv, user_ns=user_ns, user_global_ns=global_ns)
 
136
    ip.initialize()
 
137
 
 
138
    # A few more tweaks needed for playing nicely with doctests...
 
139
    
 
140
    # These traps are normally only active for interactive use, set them
 
141
    # permanently since we'll be mocking interactive sessions.
 
142
    ip.shell.builtin_trap.set()
 
143
 
 
144
    # Set error printing to stdout so nose can doctest exceptions
 
145
    ip.shell.InteractiveTB.out_stream = 'stdout'
 
146
    
 
147
    # Modify the IPython system call with one that uses getoutput, so that we
 
148
    # can capture subcommands and print them to Python's stdout, otherwise the
 
149
    # doctest machinery would miss them.
 
150
    ip.shell.system = xsys
 
151
 
 
152
    # IPython is ready, now clean up some global state...
 
153
    
 
154
    # Deactivate the various python system hooks added by ipython for
 
155
    # interactive convenience so we don't confuse the doctest system
 
156
    sys.modules['__main__'] = _main
 
157
    sys.displayhook = _displayhook
 
158
    sys.excepthook = _excepthook
 
159
 
 
160
    # So that ipython magics and aliases can be doctested (they work by making
 
161
    # a call into a global _ip object).  Also make the top-level get_ipython
 
162
    # now return this without recursively calling here again.
 
163
    _ip = ip.shell
 
164
    get_ipython = _ip.get_ipython
 
165
    __builtin__._ip = _ip
 
166
    __builtin__.get_ipython = get_ipython
 
167
 
 
168
    return _ip