builtin_trap.py
115 lines
| 3.9 KiB
| text/x-python
|
PythonLexer
Brian Granger
|
r2227 | #!/usr/bin/env python | ||
# encoding: utf-8 | ||||
""" | ||||
A context manager for managing things injected into :mod:`__builtin__`. | ||||
Authors: | ||||
* Brian Granger | ||||
""" | ||||
#----------------------------------------------------------------------------- | ||||
# Copyright (C) 2008-2009 The IPython Development Team | ||||
# | ||||
# Distributed under the terms of the BSD License. The full license is in | ||||
# the file COPYING, distributed as part of this software. | ||||
#----------------------------------------------------------------------------- | ||||
#----------------------------------------------------------------------------- | ||||
# 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 | ||
Brian Granger
|
r2227 | |||
def __enter__(self): | ||||
Brian Granger
|
r2245 | if self._nested_level == 0: | ||
self.set() | ||||
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: | ||
self.unset() | ||||
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.""" | ||||
orig = __builtin__.__dict__.get(key, BuiltinUndefined) | ||||
self._orig_builtins[key] = orig | ||||
__builtin__.__dict__[key] = value | ||||
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 | ||||
def set(self): | ||||
"""Store ipython references in the __builtin__ namespace.""" | ||||
self.add_builtin('exit', Quitter(self.shell, 'exit')) | ||||
self.add_builtin('quit', Quitter(self.shell, 'quit')) | ||||
Brian Granger
|
r2312 | self.add_builtin('get_ipython', self.shell.get_ipython) | ||
Brian Granger
|
r2227 | |||
# Recursive reload function | ||||
try: | ||||
from IPython.lib import deepreload | ||||
if self.shell.deep_reload: | ||||
self.add_builtin('reload', deepreload.reload) | ||||
else: | ||||
self.add_builtin('dreload', deepreload.reload) | ||||
del deepreload | ||||
except ImportError: | ||||
pass | ||||
# 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 | ||||
# another. Each will increase its value by one upon being activated, | ||||
# which also gives us a way to determine the nesting level. | ||||
__builtin__.__dict__.setdefault('__IPYTHON__active',0) | ||||
def unset(self): | ||||
"""Remove any builtins which might have been added by add_builtins, or | ||||
restore overwritten ones to their previous values.""" | ||||
for key in self._orig_builtins.keys(): | ||||
self.remove_builtin(key) | ||||
self._orig_builtins.clear() | ||||
self._builtins_added = False | ||||
try: | ||||
del __builtin__.__dict__['__IPYTHON__active'] | ||||
except KeyError: | ||||
Brian Granger
|
r2245 | pass | ||