builtin_trap.py
120 lines
| 4.1 KiB
| text/x-python
|
PythonLexer
Brian Granger
|
r2227 | """ | ||
A context manager for managing things injected into :mod:`__builtin__`. | ||||
Authors: | ||||
* Brian Granger | ||||
Fernando Perez
|
r2957 | * Fernando Perez | ||
Brian Granger
|
r2227 | """ | ||
#----------------------------------------------------------------------------- | ||||
Fernando Perez
|
r2957 | # Copyright (C) 2010 The IPython Development Team. | ||
# | ||||
# Distributed under the terms of the BSD License. | ||||
Brian Granger
|
r2227 | # | ||
Fernando Perez
|
r2957 | # Complete license in the file COPYING.txt, distributed with this software. | ||
Brian Granger
|
r2227 | #----------------------------------------------------------------------------- | ||
#----------------------------------------------------------------------------- | ||||
# Imports | ||||
#----------------------------------------------------------------------------- | ||||
import __builtin__ | ||||
Brian Granger
|
r2731 | from IPython.config.configurable import Configurable | ||
Brian Granger
|
r2227 | from IPython.core.quitter import Quitter | ||
Brian Granger
|
r2731 | from IPython.utils.traitlets import Instance | ||
Brian Granger
|
r2229 | |||
Brian Granger
|
r2227 | #----------------------------------------------------------------------------- | ||
# Classes and functions | ||||
#----------------------------------------------------------------------------- | ||||
Fernando Perez
|
r2404 | class __BuiltinUndefined(object): pass | ||
BuiltinUndefined = __BuiltinUndefined() | ||||
Brian Granger
|
r2227 | |||
Brian Granger
|
r2731 | class BuiltinTrap(Configurable): | ||
Brian Granger
|
r2227 | |||
Brian Granger
|
r2760 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') | ||
Brian Granger
|
r2731 | |||
Brian Granger
|
r2740 | def __init__(self, shell=None): | ||
super(BuiltinTrap, self).__init__(shell=shell, config=None) | ||||
Brian Granger
|
r2244 | self._orig_builtins = {} | ||
Brian Granger
|
r2245 | # We define this to track if a single BuiltinTrap is nested. | ||
# Only turn off the trap when the outermost call to __exit__ is made. | ||||
self._nested_level = 0 | ||||
Brian Granger
|
r2731 | self.shell = shell | ||
Fernando Perez
|
r2957 | # builtins we always add | ||
self.auto_builtins = {'exit': Quitter(self.shell, 'exit'), | ||||
'quit': Quitter(self.shell, 'quit'), | ||||
'get_ipython': self.shell.get_ipython, | ||||
} | ||||
# Recursive reload function | ||||
try: | ||||
from IPython.lib import deepreload | ||||
if self.shell.deep_reload: | ||||
self.auto_builtins['reload'] = deepreload.reload | ||||
else: | ||||
self.auto_builtins['dreload']= deepreload.reload | ||||
except ImportError: | ||||
pass | ||||
Brian Granger
|
r2227 | |||
def __enter__(self): | ||||
Brian Granger
|
r2245 | if self._nested_level == 0: | ||
Fernando Perez
|
r2957 | self.activate() | ||
Brian Granger
|
r2245 | self._nested_level += 1 | ||
Brian Granger
|
r2227 | # I return self, so callers can use add_builtin in a with clause. | ||
return self | ||||
def __exit__(self, type, value, traceback): | ||||
Brian Granger
|
r2245 | if self._nested_level == 1: | ||
Fernando Perez
|
r2957 | self.deactivate() | ||
Brian Granger
|
r2245 | self._nested_level -= 1 | ||
Brian Granger
|
r2281 | # Returning False will cause exceptions to propagate | ||
return False | ||||
Brian Granger
|
r2227 | |||
def add_builtin(self, key, value): | ||||
"""Add a builtin and save the original.""" | ||||
Fernando Perez
|
r2957 | bdict = __builtin__.__dict__ | ||
orig = bdict.get(key, BuiltinUndefined) | ||||
Brian Granger
|
r2227 | self._orig_builtins[key] = orig | ||
Fernando Perez
|
r2957 | bdict[key] = value | ||
Brian Granger
|
r2227 | |||
def remove_builtin(self, key): | ||||
"""Remove an added builtin and re-set the original.""" | ||||
try: | ||||
orig = self._orig_builtins.pop(key) | ||||
except KeyError: | ||||
pass | ||||
else: | ||||
if orig is BuiltinUndefined: | ||||
del __builtin__.__dict__[key] | ||||
else: | ||||
__builtin__.__dict__[key] = orig | ||||
Fernando Perez
|
r2957 | def activate(self): | ||
Brian Granger
|
r2227 | """Store ipython references in the __builtin__ namespace.""" | ||
Fernando Perez
|
r2957 | add_builtin = self.add_builtin | ||
for name, func in self.auto_builtins.iteritems(): | ||||
add_builtin(name, func) | ||||
Brian Granger
|
r2227 | |||
# Keep in the builtins a flag for when IPython is active. We set it | ||||
# with setdefault so that multiple nested IPythons don't clobber one | ||||
Fernando Perez
|
r2957 | # another. | ||
__builtin__.__dict__.setdefault('__IPYTHON__active', 0) | ||||
Brian Granger
|
r2227 | |||
Fernando Perez
|
r2957 | def deactivate(self): | ||
Brian Granger
|
r2227 | """Remove any builtins which might have been added by add_builtins, or | ||
restore overwritten ones to their previous values.""" | ||||
Fernando Perez
|
r2957 | # Note: must iterate over a static keys() list because we'll be | ||
# mutating the dict itself | ||||
remove_builtin = self.remove_builtin | ||||
Brian Granger
|
r2227 | for key in self._orig_builtins.keys(): | ||
Fernando Perez
|
r2957 | remove_builtin(key) | ||
Brian Granger
|
r2227 | self._orig_builtins.clear() | ||
self._builtins_added = False | ||||
try: | ||||
del __builtin__.__dict__['__IPYTHON__active'] | ||||
except KeyError: | ||||
Brian Granger
|
r2245 | pass | ||