##// END OF EJS Templates
Fixing minor typo.
Brian Granger -
Show More
@@ -1,225 +1,225 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 A lightweight component system for IPython.
5 5
6 6 Authors:
7 7
8 8 * Brian Granger
9 9 * Fernando Perez
10 10 """
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Copyright (C) 2008-2009 The IPython Development Team
14 14 #
15 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 from copy import deepcopy
24 24 from weakref import WeakValueDictionary
25 25
26 26 from IPython.utils.ipstruct import Struct
27 27 from IPython.utils.traitlets import (
28 28 HasTraitlets, TraitletError, MetaHasTraitlets, Instance, This
29 29 )
30 30
31 31
32 32 #-----------------------------------------------------------------------------
33 33 # Helper classes for Components
34 34 #-----------------------------------------------------------------------------
35 35
36 36
37 37 class ComponentError(Exception):
38 38 pass
39 39
40 40 class MetaComponentTracker(type):
41 41 """A metaclass that tracks instances of Components and its subclasses."""
42 42
43 43 def __init__(cls, name, bases, d):
44 44 super(MetaComponentTracker, cls).__init__(name, bases, d)
45 45 cls.__instance_refs = WeakValueDictionary()
46 46 cls.__numcreated = 0
47 47
48 48 def __call__(cls, *args, **kw):
49 49 """Called when *class* is called (instantiated)!!!
50 50
51 51 When a Component or subclass is instantiated, this is called and
52 52 the instance is saved in a WeakValueDictionary for tracking.
53 53 """
54 54
55 55 instance = super(MetaComponentTracker, cls).__call__(*args, **kw)
56 56 for c in cls.__mro__:
57 57 if issubclass(cls, c) and issubclass(c, Component):
58 58 c.__numcreated += 1
59 59 c.__instance_refs[c.__numcreated] = instance
60 60 return instance
61 61
62 62 def get_instances(cls, name=None, klass=None, root=None):
63 63 """Get all instances of cls and its subclasses.
64 64
65 65 Parameters
66 66 ----------
67 67 name : str
68 68 Limit to components with this name.
69 69 klass : class
70 70 Limit to components having isinstance(component, klass)
71 71 root : Component or subclass
72 72 Limit to components having this root.
73 73 """
74 74 instances = cls.__instance_refs.values()
75 75 if name is not None:
76 76 instances = [i for i in instances if i.name == name]
77 77 if klass is not None:
78 78 instances = [i for i in instances if isinstance(i, klass)]
79 79 if root is not None:
80 80 instances = [i for i in instances if i.root == root]
81 81 return instances
82 82
83 83 def get_instances_by_condition(cls, call, name=None, klass=None, root=None):
84 84 """Get all instances of cls, i such that call(i)==True.
85 85
86 86 This also takes the ``name``, ``klass`` and ``root`` arguments of
87 87 :meth:`get_instance`
88 88 """
89 89 return [i for i in cls.get_instances(name,klass,root) if call(i)]
90 90
91 91
92 92 class ComponentNameGenerator(object):
93 93 """A Singleton to generate unique component names."""
94 94
95 95 def __init__(self, prefix):
96 96 self.prefix = prefix
97 97 self.i = 0
98 98
99 99 def __call__(self):
100 100 count = self.i
101 101 self.i += 1
102 102 return "%s%s" % (self.prefix, count)
103 103
104 104
105 105 ComponentNameGenerator = ComponentNameGenerator('ipython.component')
106 106
107 107
108 108 class MetaComponent(MetaHasTraitlets, MetaComponentTracker):
109 109 pass
110 110
111 111
112 112 #-----------------------------------------------------------------------------
113 113 # Component implementation
114 114 #-----------------------------------------------------------------------------
115 115
116 116
117 117 class Component(HasTraitlets):
118 118
119 119 __metaclass__ = MetaComponent
120 120
121 121 # Traitlets are fun!
122 122 config = Instance(Struct,(),{})
123 123 parent = This()
124 124 root = This()
125 125
126 126 def __init__(self, parent, name=None, config=None):
127 127 """Create a component given a parent and possibly and name and config.
128 128
129 129 Parameters
130 130 ----------
131 131 parent : Component subclass
132 132 The parent in the component graph. The parent is used
133 133 to get the root of the component graph.
134 134 name : str
135 135 The unique name of the component. If empty, then a unique
136 136 one will be autogenerated.
137 137 config : Struct
138 138 If this is empty, self.config = parent.config, otherwise
139 139 self.config = config and root.config is ignored. This argument
140 140 should only be used to *override* the automatic inheritance of
141 141 parent.config. If a caller wants to modify parent.config
142 142 (not override), the caller should make a copy and change
143 143 attributes and then pass the copy to this argument.
144 144
145 145 Notes
146 146 -----
147 147 Subclasses of Component must call the :meth:`__init__` method of
148 148 :class:`Component` *before* doing anything else and using
149 149 :func:`super`::
150 150
151 151 class MyComponent(Component):
152 152 def __init__(self, parent, name=None, config=None):
153 153 super(MyComponent, self).__init__(parent, name, config)
154 154 # Then any other code you need to finish initialization.
155 155
156 156 This ensures that the :attr:`parent`, :attr:`name` and :attr:`config`
157 157 attributes are handled properly.
158 158 """
159 159 super(Component, self).__init__()
160 160 self._children = []
161 161 if name is None:
162 162 self.name = ComponentNameGenerator()
163 163 else:
164 164 self.name = name
165 165 self.root = self # This is the default, it is set when parent is set
166 166 self.parent = parent
167 167 if config is not None:
168 168 self.config = deepcopy(config)
169 169 else:
170 170 if self.parent is not None:
171 171 self.config = deepcopy(self.parent.config)
172 172
173 173 #-------------------------------------------------------------------------
174 174 # Static traitlet notifiations
175 175 #-------------------------------------------------------------------------
176 176
177 177 def _parent_changed(self, name, old, new):
178 178 if old is not None:
179 179 old._remove_child(self)
180 180 if new is not None:
181 181 new._add_child(self)
182 182
183 183 if new is None:
184 184 self.root = self
185 185 else:
186 186 self.root = new.root
187 187
188 188 def _root_changed(self, name, old, new):
189 189 if self.parent is None:
190 190 if not (new is self):
191 191 raise ComponentError("Root not self, but parent is None.")
192 192 else:
193 193 if not self.parent.root is new:
194 194 raise ComponentError("Error in setting the root attribute: "
195 195 "root != parent.root")
196 196
197 197 def _config_changed(self, name, old, new):
198 198 # Get all traitlets with a config_key metadata entry
199 199 traitlets = self.traitlets('config_key')
200 200 for k, v in traitlets.items():
201 201 try:
202 202 config_value = new[v.get_metadata('config_key')]
203 203 except KeyError:
204 204 pass
205 205 else:
206 206 setattr(self, k, config_value)
207 207
208 208 @property
209 209 def children(self):
210 210 """A list of all my child components."""
211 211 return self._children
212 212
213 213 def _remove_child(self, child):
214 """A private method for removing children componenets."""
214 """A private method for removing children components."""
215 215 if child in self._children:
216 216 index = self._children.index(child)
217 217 del self._children[index]
218 218
219 219 def _add_child(self, child):
220 """A private method for adding children componenets."""
220 """A private method for adding children components."""
221 221 if child not in self._children:
222 222 self._children.append(child)
223 223
224 224 def __repr__(self):
225 225 return "<Component('%s')>" % self.name
General Comments 0
You need to be logged in to leave comments. Login now