1"""
2A context manager for managing things injected into :mod:`builtins`.
3"""
4# Copyright (c) IPython Development Team.
5# Distributed under the terms of the Modified BSD License.
6import builtins as builtin_mod
7
8from traitlets.config.configurable import Configurable
9
10from traitlets import Instance
11
12
13class __BuiltinUndefined:
14 pass
15
16
17BuiltinUndefined = __BuiltinUndefined()
18
19
20class __HideBuiltin:
21 pass
22
23
24HideBuiltin = __HideBuiltin()
25
26
27class BuiltinTrap(Configurable):
28
29 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
30 allow_none=True)
31
32 def __init__(self, shell=None):
33 super(BuiltinTrap, self).__init__(shell=shell, config=None)
34 self._orig_builtins = {}
35 # We define this to track if a single BuiltinTrap is nested.
36 # Only turn off the trap when the outermost call to __exit__ is made.
37 self._nested_level = 0
38 self.shell = shell
39 # builtins we always add - if set to HideBuiltin, they will just
40 # be removed instead of being replaced by something else
41 self.auto_builtins = {'exit': HideBuiltin,
42 'quit': HideBuiltin,
43 'get_ipython': self.shell.get_ipython,
44 }
45
46 def __enter__(self):
47 if self._nested_level == 0:
48 self.activate()
49 self._nested_level += 1
50 # I return self, so callers can use add_builtin in a with clause.
51 return self
52
53 def __exit__(self, type, value, traceback):
54 if self._nested_level == 1:
55 self.deactivate()
56 self._nested_level -= 1
57 # Returning False will cause exceptions to propagate
58 return False
59
60 def add_builtin(self, key, value):
61 """Add a builtin and save the original."""
62 bdict = builtin_mod.__dict__
63 orig = bdict.get(key, BuiltinUndefined)
64 if value is HideBuiltin:
65 if orig is not BuiltinUndefined: #same as 'key in bdict'
66 self._orig_builtins[key] = orig
67 del bdict[key]
68 else:
69 self._orig_builtins[key] = orig
70 bdict[key] = value
71
72 def remove_builtin(self, key, orig):
73 """Remove an added builtin and re-set the original."""
74 if orig is BuiltinUndefined:
75 del builtin_mod.__dict__[key]
76 else:
77 builtin_mod.__dict__[key] = orig
78
79 def activate(self):
80 """Store ipython references in the __builtin__ namespace."""
81
82 add_builtin = self.add_builtin
83 for name, func in self.auto_builtins.items():
84 add_builtin(name, func)
85
86 def deactivate(self):
87 """Remove any builtins which might have been added by add_builtins, or
88 restore overwritten ones to their previous values."""
89 remove_builtin = self.remove_builtin
90 for key, val in self._orig_builtins.items():
91 remove_builtin(key, val)
92 self._orig_builtins.clear()
93 self._builtins_added = False