##// END OF EJS Templates
Created context manager for the things injected into __builtin__.
Brian Granger -
Show More
@@ -0,0 +1,104 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
3 """
4 A context manager for managing things injected into :mod:`__builtin__`.
5
6 Authors:
7
8 * Brian Granger
9 """
10
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2009 The IPython Development Team
13 #
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
17
18 #-----------------------------------------------------------------------------
19 # Imports
20 #-----------------------------------------------------------------------------
21
22 import __builtin__
23
24 from IPython.core.component import Component
25 from IPython.core.quitter import Quitter
26
27 #-----------------------------------------------------------------------------
28 # Classes and functions
29 #-----------------------------------------------------------------------------
30
31
32 class BuiltinUndefined(object): pass
33 BuiltinUndefined = BuiltinUndefined()
34
35
36 class BuiltinTrap(Component):
37
38 def __init__(self, parent, name=None, config=None):
39 super(BuiltinTrap, self).__init__(parent, name, config)
40 # Don't just grab parent!!!
41 from IPython.core.iplib import InteractiveShell
42 self.shell = InteractiveShell.get_instances(root=self.root)[0]
43 self._orig_builtins = {}
44
45 def __enter__(self):
46 self.set()
47 # I return self, so callers can use add_builtin in a with clause.
48 return self
49
50 def __exit__(self, type, value, traceback):
51 self.unset()
52 return True
53
54 def add_builtin(self, key, value):
55 """Add a builtin and save the original."""
56 orig = __builtin__.__dict__.get(key, BuiltinUndefined)
57 self._orig_builtins[key] = orig
58 __builtin__.__dict__[key] = value
59
60 def remove_builtin(self, key):
61 """Remove an added builtin and re-set the original."""
62 try:
63 orig = self._orig_builtins.pop(key)
64 except KeyError:
65 pass
66 else:
67 if orig is BuiltinUndefined:
68 del __builtin__.__dict__[key]
69 else:
70 __builtin__.__dict__[key] = orig
71
72 def set(self):
73 """Store ipython references in the __builtin__ namespace."""
74 self.add_builtin('exit', Quitter(self.shell, 'exit'))
75 self.add_builtin('quit', Quitter(self.shell, 'quit'))
76
77 # Recursive reload function
78 try:
79 from IPython.lib import deepreload
80 if self.shell.deep_reload:
81 self.add_builtin('reload', deepreload.reload)
82 else:
83 self.add_builtin('dreload', deepreload.reload)
84 del deepreload
85 except ImportError:
86 pass
87
88 # Keep in the builtins a flag for when IPython is active. We set it
89 # with setdefault so that multiple nested IPythons don't clobber one
90 # another. Each will increase its value by one upon being activated,
91 # which also gives us a way to determine the nesting level.
92 __builtin__.__dict__.setdefault('__IPYTHON__active',0)
93
94 def unset(self):
95 """Remove any builtins which might have been added by add_builtins, or
96 restore overwritten ones to their previous values."""
97 for key in self._orig_builtins.keys():
98 self.remove_builtin(key)
99 self._orig_builtins.clear()
100 self._builtins_added = False
101 try:
102 del __builtin__.__dict__['__IPYTHON__active']
103 except KeyError:
104 pass No newline at end of file
@@ -0,0 +1,38 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
3 """
4 A simple class for quitting IPython.
5
6 Authors:
7
8 * Brian Granger
9 """
10
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2009 The IPython Development Team
13 #
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
17
18 #-----------------------------------------------------------------------------
19 # Imports
20 #-----------------------------------------------------------------------------
21
22
23 class Quitter(object):
24 """Simple class to handle exit, similar to Python 2.5's.
25
26 It handles exiting in an ipython-safe manner, which the one in Python 2.5
27 doesn't do (obviously, since it doesn't know about ipython)."""
28
29 def __init__(self, shell, name):
30 self.shell = shell
31 self.name = name
32
33 def __repr__(self):
34 return 'Type %s() to exit.' % self.name
35 __str__ = __repr__
36
37 def __call__(self):
38 self.shell.exit() No newline at end of file
@@ -52,15 +52,19 b' class MetaComponentTracker(type):'
52 52 When a Component or subclass is instantiated, this is called and
53 53 the instance is saved in a WeakValueDictionary for tracking.
54 54 """
55
56 instance = super(MetaComponentTracker, cls).__call__(*args, **kw)
55 instance = cls.__new__(cls, *args, **kw)
56 # Do this before __init__ is called so get_instances works inside
57 # __init__ methods!
57 58 for c in cls.__mro__:
58 59 if issubclass(cls, c) and issubclass(c, Component):
59 60 c.__numcreated += 1
60 61 c.__instance_refs[c.__numcreated] = instance
62 if isinstance(instance, cls):
63 cls.__init__(instance, *args, **kw)
64
61 65 return instance
62 66
63 def get_instances(cls, name=None, root=None):
67 def get_instances(cls, name=None, root=None, classname=None):
64 68 """Get all instances of cls and its subclasses.
65 69
66 70 Parameters
@@ -69,21 +73,26 b' class MetaComponentTracker(type):'
69 73 Limit to components with this name.
70 74 root : Component or subclass
71 75 Limit to components having this root.
76 classname : str
77 The string name of a class to match exactly.
72 78 """
73 79 instances = cls.__instance_refs.values()
74 80 if name is not None:
75 81 instances = [i for i in instances if i.name == name]
82 if classname is not None:
83 instances = [i for i in instances if i.__class__.__name__ == classname]
76 84 if root is not None:
77 85 instances = [i for i in instances if i.root == root]
78 86 return instances
79 87
80 def get_instances_by_condition(cls, call, name=None, root=None):
88 def get_instances_by_condition(cls, call, name=None, root=None,
89 classname=None):
81 90 """Get all instances of cls, i such that call(i)==True.
82 91
83 This also takes the ``name`` and ``root`` arguments of
84 :meth:`get_instance`
92 This also takes the ``name`` and ``root`` and ``classname``
93 arguments of :meth:`get_instance`
85 94 """
86 return [i for i in cls.get_instances(name, root) if call(i)]
95 return [i for i in cls.get_instances(name, root, classname) if call(i)]
87 96
88 97
89 98 class ComponentNameGenerator(object):
@@ -23,6 +23,8 b' Notes'
23 23 # Imports
24 24 #-----------------------------------------------------------------------------
25 25
26 from __future__ import with_statement
27
26 28 import sys
27 29
28 30 from IPython.core import ultratb
@@ -63,7 +65,7 b' class InteractiveShellEmbed(InteractiveShell):'
63 65 def __init__(self, parent=None, config=None, ipythondir=None, usage=None,
64 66 user_ns=None, user_global_ns=None,
65 67 banner1=None, banner2=None,
66 custom_exceptions=((),None), exit_msg=None):
68 custom_exceptions=((),None), exit_msg=''):
67 69
68 70 # First we need to save the state of sys.displayhook and
69 71 # sys.ipcompleter so we can restore it when we are done.
@@ -172,7 +174,7 b' class InteractiveShellEmbed(InteractiveShell):'
172 174
173 175 # Call the embedding code with a stack depth of 1 so it can skip over
174 176 # our call and get the original caller's namespaces.
175 self.embed_mainloop(banner, local_ns, global_ns,
177 self.mainloop(banner, local_ns, global_ns,
176 178 stack_depth=stack_depth)
177 179
178 180 if self.exit_msg is not None:
@@ -182,6 +184,71 b' class InteractiveShellEmbed(InteractiveShell):'
182 184 self.restore_sys_displayhook()
183 185 self.restore_sys_ipcompleter()
184 186
187 def mainloop(self,header='',local_ns=None,global_ns=None,stack_depth=0):
188 """Embeds IPython into a running python program.
189
190 Input:
191
192 - header: An optional header message can be specified.
193
194 - local_ns, global_ns: working namespaces. If given as None, the
195 IPython-initialized one is updated with __main__.__dict__, so that
196 program variables become visible but user-specific configuration
197 remains possible.
198
199 - stack_depth: specifies how many levels in the stack to go to
200 looking for namespaces (when local_ns and global_ns are None). This
201 allows an intermediate caller to make sure that this function gets
202 the namespace from the intended level in the stack. By default (0)
203 it will get its locals and globals from the immediate caller.
204
205 Warning: it's possible to use this in a program which is being run by
206 IPython itself (via %run), but some funny things will happen (a few
207 globals get overwritten). In the future this will be cleaned up, as
208 there is no fundamental reason why it can't work perfectly."""
209
210 # Get locals and globals from caller
211 if local_ns is None or global_ns is None:
212 call_frame = sys._getframe(stack_depth).f_back
213
214 if local_ns is None:
215 local_ns = call_frame.f_locals
216 if global_ns is None:
217 global_ns = call_frame.f_globals
218
219 # Update namespaces and fire up interpreter
220
221 # The global one is easy, we can just throw it in
222 self.user_global_ns = global_ns
223
224 # but the user/local one is tricky: ipython needs it to store internal
225 # data, but we also need the locals. We'll copy locals in the user
226 # one, but will track what got copied so we can delete them at exit.
227 # This is so that a later embedded call doesn't see locals from a
228 # previous call (which most likely existed in a separate scope).
229 local_varnames = local_ns.keys()
230 self.user_ns.update(local_ns)
231 #self.user_ns['local_ns'] = local_ns # dbg
232
233 # Patch for global embedding to make sure that things don't overwrite
234 # user globals accidentally. Thanks to Richard <rxe@renre-europe.com>
235 # FIXME. Test this a bit more carefully (the if.. is new)
236 if local_ns is None and global_ns is None:
237 self.user_global_ns.update(__main__.__dict__)
238
239 # make sure the tab-completer has the correct frame information, so it
240 # actually completes using the frame's locals/globals
241 self.set_completer_frame()
242
243 with self.builtin_trap:
244 self.interact(header)
245
246 # now, purge out the user namespace from anything we might have added
247 # from the caller's local namespace
248 delvar = self.user_ns.pop
249 for var in local_varnames:
250 delvar(var,None)
251
185 252
186 253 _embedded_shell = None
187 254
@@ -16,6 +16,8 b' Main IPython Component'
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 from __future__ import with_statement
20
19 21 import __main__
20 22 import __builtin__
21 23 import StringIO
@@ -38,6 +40,7 b' from IPython.core import shadowns'
38 40 from IPython.core import history as ipcorehist
39 41 from IPython.core import prefilter
40 42 from IPython.core.autocall import IPyAutocall
43 from IPython.core.builtin_trap import BuiltinTrap
41 44 from IPython.core.fakemodule import FakeModule, init_fakemod_dict
42 45 from IPython.core.logger import Logger
43 46 from IPython.core.magic import Magic
@@ -112,28 +115,6 b' class SpaceInInput(exceptions.Exception): pass'
112 115
113 116 class Bunch: pass
114 117
115 class BuiltinUndefined: pass
116 BuiltinUndefined = BuiltinUndefined()
117
118
119 class Quitter(object):
120 """Simple class to handle exit, similar to Python 2.5's.
121
122 It handles exiting in an ipython-safe manner, which the one in Python 2.5
123 doesn't do (obviously, since it doesn't know about ipython)."""
124
125 def __init__(self, shell, name):
126 self.shell = shell
127 self.name = name
128
129 def __repr__(self):
130 return 'Type %s() to exit.' % self.name
131 __str__ = __repr__
132
133 def __call__(self):
134 self.shell.exit()
135
136
137 118 class InputList(list):
138 119 """Class to store user input.
139 120
@@ -340,7 +321,6 b' class InteractiveShell(Component, Magic):'
340 321 self.hooks.late_startup_hook()
341 322
342 323 def cleanup(self):
343 self.remove_builtins()
344 324 self.restore_sys_module_state()
345 325
346 326 #-------------------------------------------------------------------------
@@ -834,10 +814,7 b' class InteractiveShell(Component, Magic):'
834 814 self.magic_alias(alias)
835 815
836 816 def init_builtins(self):
837 # track which builtins we add, so we can clean up later
838 self._orig_builtins = {}
839 self._builtins_added = False
840 self.add_builtins()
817 self.builtin_trap = BuiltinTrap(self)
841 818
842 819 def init_shadow_hist(self):
843 820 try:
@@ -1075,60 +1052,6 b' class InteractiveShell(Component, Magic):'
1075 1052 except ImportError:
1076 1053 warn('help() not available - check site.py')
1077 1054
1078 def add_builtin(self, key, value):
1079 """Add a builtin and save the original."""
1080 orig = __builtin__.__dict__.get(key, BuiltinUndefined)
1081 self._orig_builtins[key] = orig
1082 __builtin__.__dict__[key] = value
1083
1084 def remove_builtin(self, key):
1085 """Remove an added builtin and re-set the original."""
1086 try:
1087 orig = self._orig_builtins.pop(key)
1088 except KeyError:
1089 pass
1090 else:
1091 if orig is BuiltinUndefined:
1092 del __builtin__.__dict__[key]
1093 else:
1094 __builtin__.__dict__[key] = orig
1095
1096 def add_builtins(self):
1097 """Store ipython references into the __builtin__ namespace.
1098
1099 We strive to modify the __builtin__ namespace as little as possible.
1100 """
1101 if not self._builtins_added:
1102 self.add_builtin('exit', Quitter(self,'exit'))
1103 self.add_builtin('quit', Quitter(self,'quit'))
1104
1105 # Recursive reload function
1106 try:
1107 from IPython.lib import deepreload
1108 if self.deep_reload:
1109 self.add_builtin('reload', deepreload.reload)
1110 else:
1111 self.add_builtin('dreload', deepreload.reload)
1112 del deepreload
1113 except ImportError:
1114 pass
1115
1116 # Keep in the builtins a flag for when IPython is active. We set it
1117 # with setdefault so that multiple nested IPythons don't clobber one
1118 # another. Each will increase its value by one upon being activated,
1119 # which also gives us a way to determine the nesting level.
1120 __builtin__.__dict__.setdefault('__IPYTHON__active',0)
1121 self._builtins_added = True
1122
1123 def remove_builtins(self):
1124 """Remove any builtins which might have been added by add_builtins, or
1125 restore overwritten ones to their previous values."""
1126 if self._builtins_added:
1127 for key in self._orig_builtins.keys():
1128 self.remove_builtin(key)
1129 self._orig_builtins.clear()
1130 self._builtins_added = False
1131
1132 1055 def save_sys_module_state(self):
1133 1056 """Save the state of hooks in the sys module.
1134 1057
@@ -1328,7 +1251,9 b' class InteractiveShell(Component, Magic):'
1328 1251 error("Magic function `%s` not found." % magic_name)
1329 1252 else:
1330 1253 magic_args = self.var_expand(magic_args,1)
1331 return fn(magic_args)
1254 with self.builtin_trap:
1255 result = fn(magic_args)
1256 return result
1332 1257
1333 1258 def define_magic(self, magicname, func):
1334 1259 """Expose own function as magic function for ipython
@@ -1423,6 +1348,7 b' class InteractiveShell(Component, Magic):'
1423 1348
1424 1349 def ex(self, cmd):
1425 1350 """Execute a normal python statement in user namespace."""
1351 with self.builtin_trap:
1426 1352 exec cmd in self.user_global_ns, self.user_ns
1427 1353
1428 1354 def ev(self, expr):
@@ -1430,7 +1356,9 b' class InteractiveShell(Component, Magic):'
1430 1356
1431 1357 Returns the result of evaluation
1432 1358 """
1433 return eval(expr, self.user_global_ns, self.user_ns)
1359 with self.builtin_trap:
1360 result = eval(expr, self.user_global_ns, self.user_ns)
1361 return result
1434 1362
1435 1363 def getoutput(self, cmd):
1436 1364 return getoutput(self.var_expand(cmd,depth=2),
@@ -1468,6 +1396,8 b' class InteractiveShell(Component, Magic):'
1468 1396 Out[10]: ['x.ljust', 'x.lower', 'x.lstrip']
1469 1397 """
1470 1398
1399 # Inject names into __builtin__ so we can complete on the added names.
1400 with self.builtin_trap:
1471 1401 complete = self.Completer.complete
1472 1402 state = 0
1473 1403 # use a dict so we get unique keys, since ipyhton's multiple
@@ -1875,6 +1805,8 b' class InteractiveShell(Component, Magic):'
1875 1805 If an optional banner argument is given, it will override the
1876 1806 internally created default banner.
1877 1807 """
1808
1809 with self.builtin_trap:
1878 1810 if self.c: # Emulate Python's -c option
1879 1811 self.exec_init_cmd()
1880 1812
@@ -1909,77 +1841,6 b' class InteractiveShell(Component, Magic):'
1909 1841 if not self.interactive:
1910 1842 self.ask_exit()
1911 1843
1912 def embed_mainloop(self,header='',local_ns=None,global_ns=None,stack_depth=0):
1913 """Embeds IPython into a running python program.
1914
1915 Input:
1916
1917 - header: An optional header message can be specified.
1918
1919 - local_ns, global_ns: working namespaces. If given as None, the
1920 IPython-initialized one is updated with __main__.__dict__, so that
1921 program variables become visible but user-specific configuration
1922 remains possible.
1923
1924 - stack_depth: specifies how many levels in the stack to go to
1925 looking for namespaces (when local_ns and global_ns are None). This
1926 allows an intermediate caller to make sure that this function gets
1927 the namespace from the intended level in the stack. By default (0)
1928 it will get its locals and globals from the immediate caller.
1929
1930 Warning: it's possible to use this in a program which is being run by
1931 IPython itself (via %run), but some funny things will happen (a few
1932 globals get overwritten). In the future this will be cleaned up, as
1933 there is no fundamental reason why it can't work perfectly."""
1934
1935 # Get locals and globals from caller
1936 if local_ns is None or global_ns is None:
1937 call_frame = sys._getframe(stack_depth).f_back
1938
1939 if local_ns is None:
1940 local_ns = call_frame.f_locals
1941 if global_ns is None:
1942 global_ns = call_frame.f_globals
1943
1944 # Update namespaces and fire up interpreter
1945
1946 # The global one is easy, we can just throw it in
1947 self.user_global_ns = global_ns
1948
1949 # but the user/local one is tricky: ipython needs it to store internal
1950 # data, but we also need the locals. We'll copy locals in the user
1951 # one, but will track what got copied so we can delete them at exit.
1952 # This is so that a later embedded call doesn't see locals from a
1953 # previous call (which most likely existed in a separate scope).
1954 local_varnames = local_ns.keys()
1955 self.user_ns.update(local_ns)
1956 #self.user_ns['local_ns'] = local_ns # dbg
1957
1958 # Patch for global embedding to make sure that things don't overwrite
1959 # user globals accidentally. Thanks to Richard <rxe@renre-europe.com>
1960 # FIXME. Test this a bit more carefully (the if.. is new)
1961 if local_ns is None and global_ns is None:
1962 self.user_global_ns.update(__main__.__dict__)
1963
1964 # make sure the tab-completer has the correct frame information, so it
1965 # actually completes using the frame's locals/globals
1966 self.set_completer_frame()
1967
1968 # before activating the interactive mode, we need to make sure that
1969 # all names in the builtin namespace needed by ipython point to
1970 # ourselves, and not to other instances.
1971 self.add_builtins()
1972
1973 self.interact(header)
1974
1975 # now, purge out the user namespace from anything we might have added
1976 # from the caller's local namespace
1977 delvar = self.user_ns.pop
1978 for var in local_varnames:
1979 delvar(var,None)
1980 # and clean builtins we may have overridden
1981 self.remove_builtins()
1982
1983 1844 def interact_prompt(self):
1984 1845 """ Print the prompt (in read-eval-print loop)
1985 1846
@@ -2377,6 +2238,7 b' class InteractiveShell(Component, Magic):'
2377 2238 lines = lines.splitlines()
2378 2239 more = 0
2379 2240
2241 with self.builtin_trap:
2380 2242 for line in lines:
2381 2243 # skip blank lines so we don't mess up the prompt counter, but do
2382 2244 # NOT skip even a blank line if we are in a code block (more is
General Comments 0
You need to be logged in to leave comments. Login now