##// END OF EJS Templates
Move crash handling to the application level and simplify class structure....
Move crash handling to the application level and simplify class structure. Starting to try to take real advantage of the refactoring, to have generic crash handling. This also lets us initialize the app without needing all the self.attempt() wrappers, since now there's a good system-wide crash handler at the app level (not inside the shell instance). I didn't yet remove the attempt() method because we may have occasional uses for it (we still do, but in one place only). I also removed some extra class layers that weren't quite needed. Creating classes solely for the purpose of passing parameters makes the code (IMO) harder to understand, I kept getting lost in parts of the class hierarchy. I think these changes provide the same flexibility but with easier to follow code (less things to remember, basically). What I tried to do was to use argument passing instead of inheritance for all cases I saw where the inheritance wasn't really adding new functionality. In some cases, this actually allowed me to remove methods that were effectively duplicated in the subclasses.

File last commit:

r2379:89f51ace
r2403:08d6ac78
Show More
builtin_trap.py
118 lines | 4.0 KiB | text/x-python | PythonLexer
#!/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__
from IPython.core.component import Component
from IPython.core.quitter import Quitter
from IPython.utils.autoattr import auto_attr
#-----------------------------------------------------------------------------
# Classes and functions
#-----------------------------------------------------------------------------
class BuiltinUndefined(object): pass
BuiltinUndefined = BuiltinUndefined()
class BuiltinTrap(Component):
def __init__(self, parent):
super(BuiltinTrap, self).__init__(parent, None, None)
self._orig_builtins = {}
# 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
@auto_attr
def shell(self):
return Component.get_instances(
root=self.root,
klass='IPython.core.iplib.InteractiveShell')[0]
def __enter__(self):
if self._nested_level == 0:
self.set()
self._nested_level += 1
# I return self, so callers can use add_builtin in a with clause.
return self
def __exit__(self, type, value, traceback):
if self._nested_level == 1:
self.unset()
self._nested_level -= 1
# Returning False will cause exceptions to propagate
return False
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'))
self.add_builtin('get_ipython', self.shell.get_ipython)
# 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:
pass