##// END OF EJS Templates
Cleaned up embedded shell and added cleanup method to InteractiveShell....
Cleaned up embedded shell and added cleanup method to InteractiveShell. * Added explicit code in InteractiveShell to make sure it cleans itself up. This is now done by the single method .cleanup, that can be called to have InteractiveShell cleanup. We can't use __del__ because of the many cycles in our object graph. * The embedded shell is refactored to no embedding logic is in the base class. Thus, InteractiveShell no longer takes an ``embedded`` argument. Just use InteractiveShellEmbed. * Created a super simple top-level :func:`embed` function that creates an InteractiveShellEmbed and calls it.

File last commit:

r2224:11a6689b merge
r2226:7053ea2c
Show More
component.py
233 lines | 7.7 KiB | text/x-python | PythonLexer
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 #!/usr/bin/env python
# encoding: utf-8
"""
A lightweight component system for IPython.
Authors:
* Brian Granger
* Fernando Perez
"""
#-----------------------------------------------------------------------------
# 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
#-----------------------------------------------------------------------------
Brian Granger
Improvement to how config is handled in Components....
r2184 from copy import deepcopy
Brian Granger
Continuing a massive refactor of everything.
r2205 import datetime
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 from weakref import WeakValueDictionary
Brian Granger
Improvements to component.py....
r2180 from IPython.utils.ipstruct import Struct
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 from IPython.utils.traitlets import (
Brian Granger
Improvements to component.py....
r2180 HasTraitlets, TraitletError, MetaHasTraitlets, Instance, This
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 )
#-----------------------------------------------------------------------------
# Helper classes for Components
#-----------------------------------------------------------------------------
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183 class ComponentError(Exception):
pass
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 class MetaComponentTracker(type):
"""A metaclass that tracks instances of Components and its subclasses."""
def __init__(cls, name, bases, d):
super(MetaComponentTracker, cls).__init__(name, bases, d)
cls.__instance_refs = WeakValueDictionary()
cls.__numcreated = 0
def __call__(cls, *args, **kw):
Brian Granger
Improvements to component.py....
r2180 """Called when *class* is called (instantiated)!!!
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
Brian Granger
Improvements to component.py....
r2180 When a Component or subclass is instantiated, this is called and
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 the instance is saved in a WeakValueDictionary for tracking.
"""
instance = super(MetaComponentTracker, cls).__call__(*args, **kw)
for c in cls.__mro__:
if issubclass(cls, c) and issubclass(c, Component):
c.__numcreated += 1
c.__instance_refs[c.__numcreated] = instance
return instance
Brian Granger
Removed reduntant klass argument from Component.get_instances.
r2221 def get_instances(cls, name=None, root=None):
Brian Granger
Improvements to component.py....
r2180 """Get all instances of cls and its subclasses.
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
Brian Granger
Improvements to component.py....
r2180 Parameters
----------
name : str
Limit to components with this name.
root : Component or subclass
Limit to components having this root.
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 """
Brian Granger
Improvements to component.py....
r2180 instances = cls.__instance_refs.values()
if name is not None:
instances = [i for i in instances if i.name == name]
if root is not None:
instances = [i for i in instances if i.root == root]
return instances
Brian Granger
Removed reduntant klass argument from Component.get_instances.
r2221 def get_instances_by_condition(cls, call, name=None, root=None):
Brian Granger
Improvements to component.py....
r2180 """Get all instances of cls, i such that call(i)==True.
Brian Granger
Removed reduntant klass argument from Component.get_instances.
r2221 This also takes the ``name`` and ``root`` arguments of
Brian Granger
Improvements to component.py....
r2180 :meth:`get_instance`
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 """
Brian Granger
Removed reduntant klass argument from Component.get_instances.
r2221 return [i for i in cls.get_instances(name, root) if call(i)]
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
class ComponentNameGenerator(object):
"""A Singleton to generate unique component names."""
def __init__(self, prefix):
self.prefix = prefix
self.i = 0
def __call__(self):
count = self.i
self.i += 1
return "%s%s" % (self.prefix, count)
ComponentNameGenerator = ComponentNameGenerator('ipython.component')
class MetaComponent(MetaHasTraitlets, MetaComponentTracker):
pass
#-----------------------------------------------------------------------------
# Component implementation
#-----------------------------------------------------------------------------
class Component(HasTraitlets):
__metaclass__ = MetaComponent
Brian Granger
Improvements to component.py....
r2180 # Traitlets are fun!
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183 config = Instance(Struct,(),{})
parent = This()
root = This()
Brian Granger
Continuing a massive refactor of everything.
r2205 created = None
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
def __init__(self, parent, name=None, config=None):
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183 """Create a component given a parent and possibly and name and config.
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
Parameters
----------
parent : Component subclass
The parent in the component graph. The parent is used
to get the root of the component graph.
name : str
The unique name of the component. If empty, then a unique
one will be autogenerated.
Brian Granger
Improvement to how config is handled in Components....
r2184 config : Struct
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183 If this is empty, self.config = parent.config, otherwise
self.config = config and root.config is ignored. This argument
should only be used to *override* the automatic inheritance of
parent.config. If a caller wants to modify parent.config
(not override), the caller should make a copy and change
attributes and then pass the copy to this argument.
Notes
-----
Subclasses of Component must call the :meth:`__init__` method of
:class:`Component` *before* doing anything else and using
:func:`super`::
class MyComponent(Component):
def __init__(self, parent, name=None, config=None):
super(MyComponent, self).__init__(parent, name, config)
# Then any other code you need to finish initialization.
This ensures that the :attr:`parent`, :attr:`name` and :attr:`config`
attributes are handled properly.
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 """
super(Component, self).__init__()
Brian Granger
Improvements to component.py....
r2180 self._children = []
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 if name is None:
Brian Granger
Improvements to component.py....
r2180 self.name = ComponentNameGenerator()
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 else:
Brian Granger
Improvements to component.py....
r2180 self.name = name
self.root = self # This is the default, it is set when parent is set
Brian Granger
Minor work on how ipythondir is handled.
r2223 self.parent = parent
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 if config is not None:
Brian Granger
Improvement to how config is handled in Components....
r2184 self.config = deepcopy(config)
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 else:
if self.parent is not None:
Brian Granger
Improvement to how config is handled in Components....
r2184 self.config = deepcopy(self.parent.config)
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
Brian Granger
Continuing a massive refactor of everything.
r2205 self.created = datetime.datetime.now()
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 #-------------------------------------------------------------------------
Brian Granger
Improvements to component.py....
r2180 # Static traitlet notifiations
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 #-------------------------------------------------------------------------
Brian Granger
Improvements to component.py....
r2180 def _parent_changed(self, name, old, new):
if old is not None:
old._remove_child(self)
if new is not None:
new._add_child(self)
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
Brian Granger
Improvements to component.py....
r2180 if new is None:
self.root = self
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 else:
Brian Granger
Improvements to component.py....
r2180 self.root = new.root
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183 def _root_changed(self, name, old, new):
if self.parent is None:
if not (new is self):
raise ComponentError("Root not self, but parent is None.")
else:
if not self.parent.root is new:
raise ComponentError("Error in setting the root attribute: "
"root != parent.root")
Brian Granger
Improvement to how config is handled in Components....
r2184
def _config_changed(self, name, old, new):
Brian Granger
Minor doc updates.
r2222 """Update all the class traits having a config_key with the config.
For any class traitlet with a ``config_key`` metadata attribute, we
update the traitlet with the value of the corresponding config entry.
In the future, we might want to do a pop here so stale config info
is not passed onto children.
"""
Brian Granger
Improvement to how config is handled in Components....
r2184 # Get all traitlets with a config_key metadata entry
Brian Granger
Semi-final Application and minor work on traitlets.
r2200 traitlets = self.traitlets('config_key')
Brian Granger
Improvement to how config is handled in Components....
r2184 for k, v in traitlets.items():
try:
config_value = new[v.get_metadata('config_key')]
except KeyError:
pass
else:
setattr(self, k, config_value)
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 @property
Brian Granger
Improvements to component.py....
r2180 def children(self):
"""A list of all my child components."""
return self._children
def _remove_child(self, child):
Brian Granger
Fixing minor typo.
r2219 """A private method for removing children components."""
Brian Granger
Improvements to component.py....
r2180 if child in self._children:
index = self._children.index(child)
del self._children[index]
def _add_child(self, child):
Brian Granger
Fixing minor typo.
r2219 """A private method for adding children components."""
Brian Granger
Improvements to component.py....
r2180 if child not in self._children:
self._children.append(child)
def __repr__(self):
Brian Granger
Adding testing for componenets.
r2181 return "<Component('%s')>" % self.name