##// END OF EJS Templates
Small fixes so the docs build....
Fernando Perez -
Show More
@@ -1,336 +1,336 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """A simple configuration system.
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 8 """
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Copyright (C) 2008-2009 The IPython Development Team
12 12 #
13 13 # Distributed under the terms of the BSD License. The full license is in
14 14 # the file COPYING, distributed as part of this software.
15 15 #-----------------------------------------------------------------------------
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Imports
19 19 #-----------------------------------------------------------------------------
20 20
21 21 import __builtin__
22 22 import os
23 23 import sys
24 24
25 25 from IPython.external import argparse
26 26 from IPython.utils.genutils import filefind
27 27
28 28 #-----------------------------------------------------------------------------
29 29 # Exceptions
30 30 #-----------------------------------------------------------------------------
31 31
32 32
33 33 class ConfigError(Exception):
34 34 pass
35 35
36 36
37 37 class ConfigLoaderError(ConfigError):
38 38 pass
39 39
40 40
41 41 #-----------------------------------------------------------------------------
42 42 # Config class for holding config information
43 43 #-----------------------------------------------------------------------------
44 44
45 45
46 46 class Config(dict):
47 47 """An attribute based dict that can do smart merges."""
48 48
49 49 def __init__(self, *args, **kwds):
50 50 dict.__init__(self, *args, **kwds)
51 51 # This sets self.__dict__ = self, but it has to be done this way
52 52 # because we are also overriding __setattr__.
53 53 dict.__setattr__(self, '__dict__', self)
54 54
55 55 def _merge(self, other):
56 56 to_update = {}
57 57 for k, v in other.items():
58 58 if not self.has_key(k):
59 59 to_update[k] = v
60 60 else: # I have this key
61 61 if isinstance(v, Config):
62 62 # Recursively merge common sub Configs
63 63 self[k]._merge(v)
64 64 else:
65 65 # Plain updates for non-Configs
66 66 to_update[k] = v
67 67
68 68 self.update(to_update)
69 69
70 70 def _is_section_key(self, key):
71 71 if key[0].upper()==key[0] and not key.startswith('_'):
72 72 return True
73 73 else:
74 74 return False
75 75
76 76 def has_key(self, key):
77 77 if self._is_section_key(key):
78 78 return True
79 79 else:
80 80 return dict.has_key(self, key)
81 81
82 82 def _has_section(self, key):
83 83 if self._is_section_key(key):
84 84 if dict.has_key(self, key):
85 85 return True
86 86 return False
87 87
88 88 def copy(self):
89 89 return type(self)(dict.copy(self))
90 90
91 91 def __copy__(self):
92 92 return self.copy()
93 93
94 94 def __deepcopy__(self, memo):
95 95 import copy
96 96 return type(self)(copy.deepcopy(self.items()))
97 97
98 98 def __getitem__(self, key):
99 99 # Because we use this for an exec namespace, we need to delegate
100 100 # the lookup of names in __builtin__ to itself. This means
101 101 # that you can't have section or attribute names that are
102 102 # builtins.
103 103 try:
104 104 return getattr(__builtin__, key)
105 105 except AttributeError:
106 106 pass
107 107 if self._is_section_key(key):
108 108 try:
109 109 return dict.__getitem__(self, key)
110 110 except KeyError:
111 111 c = Config()
112 112 dict.__setitem__(self, key, c)
113 113 return c
114 114 else:
115 115 return dict.__getitem__(self, key)
116 116
117 117 def __setitem__(self, key, value):
118 118 # Don't allow names in __builtin__ to be modified.
119 119 if hasattr(__builtin__, key):
120 120 raise ConfigError('Config variable names cannot have the same name '
121 121 'as a Python builtin: %s' % key)
122 122 if self._is_section_key(key):
123 123 if not isinstance(value, Config):
124 124 raise ValueError('values whose keys begin with an uppercase '
125 125 'char must be Config instances: %r, %r' % (key, value))
126 126 else:
127 127 dict.__setitem__(self, key, value)
128 128
129 129 def __getattr__(self, key):
130 130 try:
131 131 return self.__getitem__(key)
132 132 except KeyError, e:
133 133 raise AttributeError(e)
134 134
135 135 def __setattr__(self, key, value):
136 136 try:
137 137 self.__setitem__(key, value)
138 138 except KeyError, e:
139 139 raise AttributeError(e)
140 140
141 141 def __delattr__(self, key):
142 142 try:
143 143 dict.__delitem__(self, key)
144 144 except KeyError, e:
145 145 raise AttributeError(e)
146 146
147 147
148 148 #-----------------------------------------------------------------------------
149 149 # Config loading classes
150 150 #-----------------------------------------------------------------------------
151 151
152 152
153 153 class ConfigLoader(object):
154 154 """A object for loading configurations from just about anywhere.
155 155
156 156 The resulting configuration is packaged as a :class:`Struct`.
157 157
158 158 Notes
159 159 -----
160 160 A :class:`ConfigLoader` does one thing: load a config from a source
161 161 (file, command line arguments) and returns the data as a :class:`Struct`.
162 162 There are lots of things that :class:`ConfigLoader` does not do. It does
163 163 not implement complex logic for finding config files. It does not handle
164 164 default values or merge multiple configs. These things need to be
165 165 handled elsewhere.
166 166 """
167 167
168 168 def __init__(self):
169 169 """A base class for config loaders.
170 170
171 171 Examples
172 172 --------
173 173
174 174 >>> cl = ConfigLoader()
175 175 >>> config = cl.load_config()
176 176 >>> config
177 177 {}
178 178 """
179 179 self.clear()
180 180
181 181 def clear(self):
182 182 self.config = Config()
183 183
184 184 def load_config(self):
185 185 """Load a config from somewhere, return a Struct.
186 186
187 187 Usually, this will cause self.config to be set and then returned.
188 188 """
189 189 return self.config
190 190
191 191
192 192 class FileConfigLoader(ConfigLoader):
193 193 """A base class for file based configurations.
194 194
195 195 As we add more file based config loaders, the common logic should go
196 196 here.
197 197 """
198 198 pass
199 199
200 200
201 201 class PyFileConfigLoader(FileConfigLoader):
202 202 """A config loader for pure python files.
203 203
204 204 This calls execfile on a plain python file and looks for attributes
205 205 that are all caps. These attribute are added to the config Struct.
206 206 """
207 207
208 208 def __init__(self, filename, path=None):
209 209 """Build a config loader for a filename and path.
210 210
211 211 Parameters
212 212 ----------
213 213 filename : str
214 214 The file name of the config file.
215 215 path : str, list, tuple
216 216 The path to search for the config file on, or a sequence of
217 217 paths to try in order.
218 218 """
219 219 super(PyFileConfigLoader, self).__init__()
220 220 self.filename = filename
221 221 self.path = path
222 222 self.full_filename = ''
223 223 self.data = None
224 224
225 225 def load_config(self):
226 226 """Load the config from a file and return it as a Struct."""
227 227 self._find_file()
228 228 self._read_file_as_dict()
229 229 self._convert_to_config()
230 230 return self.config
231 231
232 232 def _find_file(self):
233 233 """Try to find the file by searching the paths."""
234 234 self.full_filename = filefind(self.filename, self.path)
235 235
236 236 def _read_file_as_dict(self):
237 237 """Load the config file into self.config, with recursive loading."""
238 238 # This closure is made available in the namespace that is used
239 239 # to exec the config file. This allows users to call
240 240 # load_subconfig('myconfig.py') to load config files recursively.
241 241 # It needs to be a closure because it has references to self.path
242 242 # and self.config. The sub-config is loaded with the same path
243 243 # as the parent, but it uses an empty config which is then merged
244 244 # with the parents.
245 245 def load_subconfig(fname):
246 246 loader = PyFileConfigLoader(fname, self.path)
247 247 try:
248 248 sub_config = loader.load_config()
249 249 except IOError:
250 250 # Pass silently if the sub config is not there. This happens
251 251 # when a user us using a profile, but not the default config.
252 252 pass
253 253 else:
254 254 self.config._merge(sub_config)
255 255
256 256 # Again, this needs to be a closure and should be used in config
257 257 # files to get the config being loaded.
258 258 def get_config():
259 259 return self.config
260 260
261 261 namespace = dict(load_subconfig=load_subconfig, get_config=get_config)
262 262 execfile(self.full_filename, namespace)
263 263
264 264 def _convert_to_config(self):
265 265 if self.data is None:
266 266 ConfigLoaderError('self.data does not exist')
267 267
268 268
269 269 class CommandLineConfigLoader(ConfigLoader):
270 270 """A config loader for command line arguments.
271 271
272 272 As we add more command line based loaders, the common logic should go
273 273 here.
274 274 """
275 275
276 276
277 class NoConfigDefault(object): pass
278 NoConfigDefault = NoConfigDefault()
277 class __NoConfigDefault(object): pass
278 NoConfigDefault = __NoConfigDefault()
279 279
280 280
281 281 class ArgParseConfigLoader(CommandLineConfigLoader):
282 282
283 283 # arguments = [(('-f','--file'),dict(type=str,dest='file'))]
284 284 arguments = ()
285 285
286 286 def __init__(self, *args, **kw):
287 287 """Create a config loader for use with argparse.
288 288
289 289 The args and kwargs arguments here are passed onto the constructor
290 290 of :class:`argparse.ArgumentParser`.
291 291 """
292 292 super(CommandLineConfigLoader, self).__init__()
293 293 self.args = args
294 294 self.kw = kw
295 295
296 296 def load_config(self, args=None):
297 297 """Parse command line arguments and return as a Struct."""
298 298 self._create_parser()
299 299 self._parse_args(args)
300 300 self._convert_to_config()
301 301 return self.config
302 302
303 303 def get_extra_args(self):
304 304 if hasattr(self, 'extra_args'):
305 305 return self.extra_args
306 306 else:
307 307 return []
308 308
309 309 def _create_parser(self):
310 310 self.parser = argparse.ArgumentParser(*self.args, **self.kw)
311 311 self._add_arguments()
312 312 self._add_other_arguments()
313 313
314 314 def _add_other_arguments(self):
315 315 pass
316 316
317 317 def _add_arguments(self):
318 318 for argument in self.arguments:
319 319 if not argument[1].has_key('default'):
320 320 argument[1]['default'] = NoConfigDefault
321 321 self.parser.add_argument(*argument[0],**argument[1])
322 322
323 323 def _parse_args(self, args=None):
324 324 """self.parser->self.parsed_data"""
325 325 if args is None:
326 326 self.parsed_data, self.extra_args = self.parser.parse_known_args()
327 327 else:
328 328 self.parsed_data, self.extra_args = self.parser.parse_known_args(args)
329 329
330 330 def _convert_to_config(self):
331 331 """self.parsed_data->self.config"""
332 332 for k, v in vars(self.parsed_data).items():
333 333 if v is not NoConfigDefault:
334 334 exec_str = 'self.config.' + k + '= v'
335 335 exec exec_str in locals(), globals()
336 336
@@ -1,118 +1,118 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 A context manager for managing things injected into :mod:`__builtin__`.
5 5
6 6 Authors:
7 7
8 8 * Brian Granger
9 9 """
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Copyright (C) 2008-2009 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 import __builtin__
23 23
24 24 from IPython.core.component import Component
25 25 from IPython.core.quitter import Quitter
26 26
27 27 from IPython.utils.autoattr import auto_attr
28 28
29 29 #-----------------------------------------------------------------------------
30 30 # Classes and functions
31 31 #-----------------------------------------------------------------------------
32 32
33 33
34 class BuiltinUndefined(object): pass
35 BuiltinUndefined = BuiltinUndefined()
34 class __BuiltinUndefined(object): pass
35 BuiltinUndefined = __BuiltinUndefined()
36 36
37 37
38 38 class BuiltinTrap(Component):
39 39
40 40 def __init__(self, parent):
41 41 super(BuiltinTrap, self).__init__(parent, None, None)
42 42 self._orig_builtins = {}
43 43 # We define this to track if a single BuiltinTrap is nested.
44 44 # Only turn off the trap when the outermost call to __exit__ is made.
45 45 self._nested_level = 0
46 46
47 47 @auto_attr
48 48 def shell(self):
49 49 return Component.get_instances(
50 50 root=self.root,
51 51 klass='IPython.core.iplib.InteractiveShell')[0]
52 52
53 53 def __enter__(self):
54 54 if self._nested_level == 0:
55 55 self.set()
56 56 self._nested_level += 1
57 57 # I return self, so callers can use add_builtin in a with clause.
58 58 return self
59 59
60 60 def __exit__(self, type, value, traceback):
61 61 if self._nested_level == 1:
62 62 self.unset()
63 63 self._nested_level -= 1
64 64 # Returning False will cause exceptions to propagate
65 65 return False
66 66
67 67 def add_builtin(self, key, value):
68 68 """Add a builtin and save the original."""
69 69 orig = __builtin__.__dict__.get(key, BuiltinUndefined)
70 70 self._orig_builtins[key] = orig
71 71 __builtin__.__dict__[key] = value
72 72
73 73 def remove_builtin(self, key):
74 74 """Remove an added builtin and re-set the original."""
75 75 try:
76 76 orig = self._orig_builtins.pop(key)
77 77 except KeyError:
78 78 pass
79 79 else:
80 80 if orig is BuiltinUndefined:
81 81 del __builtin__.__dict__[key]
82 82 else:
83 83 __builtin__.__dict__[key] = orig
84 84
85 85 def set(self):
86 86 """Store ipython references in the __builtin__ namespace."""
87 87 self.add_builtin('exit', Quitter(self.shell, 'exit'))
88 88 self.add_builtin('quit', Quitter(self.shell, 'quit'))
89 89 self.add_builtin('get_ipython', self.shell.get_ipython)
90 90
91 91 # Recursive reload function
92 92 try:
93 93 from IPython.lib import deepreload
94 94 if self.shell.deep_reload:
95 95 self.add_builtin('reload', deepreload.reload)
96 96 else:
97 97 self.add_builtin('dreload', deepreload.reload)
98 98 del deepreload
99 99 except ImportError:
100 100 pass
101 101
102 102 # Keep in the builtins a flag for when IPython is active. We set it
103 103 # with setdefault so that multiple nested IPythons don't clobber one
104 104 # another. Each will increase its value by one upon being activated,
105 105 # which also gives us a way to determine the nesting level.
106 106 __builtin__.__dict__.setdefault('__IPYTHON__active',0)
107 107
108 108 def unset(self):
109 109 """Remove any builtins which might have been added by add_builtins, or
110 110 restore overwritten ones to their previous values."""
111 111 for key in self._orig_builtins.keys():
112 112 self.remove_builtin(key)
113 113 self._orig_builtins.clear()
114 114 self._builtins_added = False
115 115 try:
116 116 del __builtin__.__dict__['__IPYTHON__active']
117 117 except KeyError:
118 118 pass
@@ -1,346 +1,346 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 import datetime
25 25 from weakref import WeakValueDictionary
26 26
27 27 from IPython.utils.importstring import import_item
28 28 from IPython.config.loader import Config
29 29 from IPython.utils.traitlets import (
30 30 HasTraitlets, TraitletError, MetaHasTraitlets, Instance, This
31 31 )
32 32
33 33
34 34 #-----------------------------------------------------------------------------
35 35 # Helper classes for Components
36 36 #-----------------------------------------------------------------------------
37 37
38 38
39 39 class ComponentError(Exception):
40 40 pass
41 41
42 42 class MetaComponentTracker(type):
43 43 """A metaclass that tracks instances of Components and its subclasses."""
44 44
45 45 def __init__(cls, name, bases, d):
46 46 super(MetaComponentTracker, cls).__init__(name, bases, d)
47 47 cls.__instance_refs = WeakValueDictionary()
48 48 cls.__numcreated = 0
49 49
50 50 def __call__(cls, *args, **kw):
51 51 """Called when a class is called (instantiated)!!!
52 52
53 53 When a Component or subclass is instantiated, this is called and
54 54 the instance is saved in a WeakValueDictionary for tracking.
55 55 """
56 56 instance = cls.__new__(cls, *args, **kw)
57 57
58 58 # Register the instance before __init__ is called so get_instances
59 59 # works inside __init__ methods!
60 60 indices = cls.register_instance(instance)
61 61
62 62 # This is in a try/except because of the __init__ method fails, the
63 63 # instance is discarded and shouldn't be tracked.
64 64 try:
65 65 if isinstance(instance, cls):
66 66 cls.__init__(instance, *args, **kw)
67 67 except:
68 68 # Unregister the instance because __init__ failed!
69 69 cls.unregister_instances(indices)
70 70 raise
71 71 else:
72 72 return instance
73 73
74 74 def register_instance(cls, instance):
75 75 """Register instance with cls and its subclasses."""
76 76 # indices is a list of the keys used to register the instance
77 77 # with. This list is needed if the instance needs to be unregistered.
78 78 indices = []
79 79 for c in cls.__mro__:
80 80 if issubclass(cls, c) and issubclass(c, Component):
81 81 c.__numcreated += 1
82 82 indices.append(c.__numcreated)
83 83 c.__instance_refs[c.__numcreated] = instance
84 84 else:
85 85 break
86 86 return indices
87 87
88 88 def unregister_instances(cls, indices):
89 89 """Unregister instance with cls and its subclasses."""
90 90 for c, index in zip(cls.__mro__, indices):
91 91 try:
92 92 del c.__instance_refs[index]
93 93 except KeyError:
94 94 pass
95 95
96 96 def clear_instances(cls):
97 97 """Clear all instances tracked by cls."""
98 98 cls.__instance_refs.clear()
99 99 cls.__numcreated = 0
100 100
101 101 def get_instances(cls, name=None, root=None, klass=None):
102 102 """Get all instances of cls and its subclasses.
103 103
104 104 Parameters
105 105 ----------
106 106 name : str
107 107 Limit to components with this name.
108 108 root : Component or subclass
109 109 Limit to components having this root.
110 110 klass : class or str
111 111 Limits to instances of the class or its subclasses. If a str
112 112 is given ut must be in the form 'foo.bar.MyClass'. The str
113 113 form of this argument is useful for forward declarations.
114 114 """
115 115 if klass is not None:
116 116 if isinstance(klass, basestring):
117 117 klass = import_item(klass)
118 118 # Limit search to instances of klass for performance
119 119 if issubclass(klass, Component):
120 120 return klass.get_instances(name=name, root=root)
121 121 instances = cls.__instance_refs.values()
122 122 if name is not None:
123 123 instances = [i for i in instances if i.name == name]
124 124 if klass is not None:
125 125 instances = [i for i in instances if isinstance(i, klass)]
126 126 if root is not None:
127 127 instances = [i for i in instances if i.root == root]
128 128 return instances
129 129
130 130 def get_instances_by_condition(cls, call, name=None, root=None,
131 131 klass=None):
132 132 """Get all instances of cls, i such that call(i)==True.
133 133
134 134 This also takes the ``name`` and ``root`` and ``classname``
135 135 arguments of :meth:`get_instance`
136 136 """
137 137 return [i for i in cls.get_instances(name, root, klass) if call(i)]
138 138
139 139
140 140 def masquerade_as(instance, cls):
141 141 """Let instance masquerade as an instance of cls.
142 142
143 143 Sometimes, such as in testing code, it is useful to let a class
144 144 masquerade as another. Python, being duck typed, allows this by
145 145 default. But, instances of components are tracked by their class type.
146 146
147 147 After calling this, ``cls.get_instances()`` will return ``instance``. This
148 148 does not, however, cause ``isinstance(instance, cls)`` to return ``True``.
149 149
150 150 Parameters
151 151 ----------
152 152 instance : an instance of a Component or Component subclass
153 153 The instance that will pretend to be a cls.
154 154 cls : subclass of Component
155 155 The Component subclass that instance will pretend to be.
156 156 """
157 157 cls.register_instance(instance)
158 158
159 159
160 class ComponentNameGenerator(object):
160 class __ComponentNameGenerator(object):
161 161 """A Singleton to generate unique component names."""
162 162
163 163 def __init__(self, prefix):
164 164 self.prefix = prefix
165 165 self.i = 0
166 166
167 167 def __call__(self):
168 168 count = self.i
169 169 self.i += 1
170 170 return "%s%s" % (self.prefix, count)
171 171
172 172
173 ComponentNameGenerator = ComponentNameGenerator('ipython.component')
173 ComponentNameGenerator = __ComponentNameGenerator('ipython.component')
174 174
175 175
176 176 class MetaComponent(MetaHasTraitlets, MetaComponentTracker):
177 177 pass
178 178
179 179
180 180 #-----------------------------------------------------------------------------
181 181 # Component implementation
182 182 #-----------------------------------------------------------------------------
183 183
184 184
185 185 class Component(HasTraitlets):
186 186
187 187 __metaclass__ = MetaComponent
188 188
189 189 # Traitlets are fun!
190 190 config = Instance(Config,(),{})
191 191 parent = This()
192 192 root = This()
193 193 created = None
194 194
195 195 def __init__(self, parent, name=None, config=None):
196 196 """Create a component given a parent and possibly and name and config.
197 197
198 198 Parameters
199 199 ----------
200 200 parent : Component subclass
201 201 The parent in the component graph. The parent is used
202 202 to get the root of the component graph.
203 203 name : str
204 204 The unique name of the component. If empty, then a unique
205 205 one will be autogenerated.
206 206 config : Config
207 207 If this is empty, self.config = parent.config, otherwise
208 208 self.config = config and root.config is ignored. This argument
209 209 should only be used to *override* the automatic inheritance of
210 210 parent.config. If a caller wants to modify parent.config
211 211 (not override), the caller should make a copy and change
212 212 attributes and then pass the copy to this argument.
213 213
214 214 Notes
215 215 -----
216 216 Subclasses of Component must call the :meth:`__init__` method of
217 217 :class:`Component` *before* doing anything else and using
218 218 :func:`super`::
219 219
220 220 class MyComponent(Component):
221 221 def __init__(self, parent, name=None, config=None):
222 222 super(MyComponent, self).__init__(parent, name, config)
223 223 # Then any other code you need to finish initialization.
224 224
225 225 This ensures that the :attr:`parent`, :attr:`name` and :attr:`config`
226 226 attributes are handled properly.
227 227 """
228 228 super(Component, self).__init__()
229 229 self._children = []
230 230 if name is None:
231 231 self.name = ComponentNameGenerator()
232 232 else:
233 233 self.name = name
234 234 self.root = self # This is the default, it is set when parent is set
235 235 self.parent = parent
236 236 if config is not None:
237 237 self.config = config
238 238 # We used to deepcopy, but for now we are trying to just save
239 239 # by reference. This *could* have side effects as all components
240 240 # will share config. In fact, I did find such a side effect in
241 241 # _config_changed below. If a config attribute value was a mutable type
242 242 # all instances of a component were getting the same copy, effectively
243 243 # making that a class attribute.
244 244 # self.config = deepcopy(config)
245 245 else:
246 246 if self.parent is not None:
247 247 self.config = self.parent.config
248 248 # We used to deepcopy, but for now we are trying to just save
249 249 # by reference. This *could* have side effects as all components
250 250 # will share config. In fact, I did find such a side effect in
251 251 # _config_changed below. If a config attribute value was a mutable type
252 252 # all instances of a component were getting the same copy, effectively
253 253 # making that a class attribute.
254 254 # self.config = deepcopy(self.parent.config)
255 255
256 256 self.created = datetime.datetime.now()
257 257
258 258 #-------------------------------------------------------------------------
259 259 # Static traitlet notifiations
260 260 #-------------------------------------------------------------------------
261 261
262 262 def _parent_changed(self, name, old, new):
263 263 if old is not None:
264 264 old._remove_child(self)
265 265 if new is not None:
266 266 new._add_child(self)
267 267
268 268 if new is None:
269 269 self.root = self
270 270 else:
271 271 self.root = new.root
272 272
273 273 def _root_changed(self, name, old, new):
274 274 if self.parent is None:
275 275 if not (new is self):
276 276 raise ComponentError("Root not self, but parent is None.")
277 277 else:
278 278 if not self.parent.root is new:
279 279 raise ComponentError("Error in setting the root attribute: "
280 280 "root != parent.root")
281 281
282 282 def _config_changed(self, name, old, new):
283 283 """Update all the class traits having ``config=True`` as metadata.
284 284
285 285 For any class traitlet with a ``config`` metadata attribute that is
286 286 ``True``, we update the traitlet with the value of the corresponding
287 287 config entry.
288 288 """
289 289 # Get all traitlets with a config metadata entry that is True
290 290 traitlets = self.traitlets(config=True)
291 291
292 292 # We auto-load config section for this class as well as any parent
293 293 # classes that are Component subclasses. This starts with Component
294 294 # and works down the mro loading the config for each section.
295 295 section_names = [cls.__name__ for cls in \
296 296 reversed(self.__class__.__mro__) if
297 297 issubclass(cls, Component) and issubclass(self.__class__, cls)]
298 298
299 299 for sname in section_names:
300 300 # Don't do a blind getattr as that would cause the config to
301 301 # dynamically create the section with name self.__class__.__name__.
302 302 if new._has_section(sname):
303 303 my_config = new[sname]
304 304 for k, v in traitlets.items():
305 305 # Don't allow traitlets with config=True to start with
306 306 # uppercase. Otherwise, they are confused with Config
307 307 # subsections. But, developers shouldn't have uppercase
308 308 # attributes anyways! (PEP 6)
309 309 if k[0].upper()==k[0] and not k.startswith('_'):
310 310 raise ComponentError('Component traitlets with '
311 311 'config=True must start with a lowercase so they are '
312 312 'not confused with Config subsections: %s.%s' % \
313 313 (self.__class__.__name__, k))
314 314 try:
315 315 # Here we grab the value from the config
316 316 # If k has the naming convention of a config
317 317 # section, it will be auto created.
318 318 config_value = my_config[k]
319 319 except KeyError:
320 320 pass
321 321 else:
322 322 # print "Setting %s.%s from %s.%s=%r" % \
323 323 # (self.__class__.__name__,k,sname,k,config_value)
324 324 # We have to do a deepcopy here if we don't deepcopy the entire
325 325 # config object. If we don't, a mutable config_value will be
326 326 # shared by all instances, effectively making it a class attribute.
327 327 setattr(self, k, deepcopy(config_value))
328 328
329 329 @property
330 330 def children(self):
331 331 """A list of all my child components."""
332 332 return self._children
333 333
334 334 def _remove_child(self, child):
335 335 """A private method for removing children components."""
336 336 if child in self._children:
337 337 index = self._children.index(child)
338 338 del self._children[index]
339 339
340 340 def _add_child(self, child):
341 341 """A private method for adding children components."""
342 342 if child not in self._children:
343 343 self._children.append(child)
344 344
345 345 def __repr__(self):
346 346 return "<%s('%s')>" % (self.__class__.__name__, self.name)
@@ -1,43 +1,65 b''
1 1 #!/usr/bin/env python
2 2 """Script to auto-generate our API docs.
3 3 """
4 4 # stdlib imports
5 5 import os
6 6 import sys
7 7
8 8 # local imports
9 9 sys.path.append(os.path.abspath('sphinxext'))
10 10 from apigen import ApiDocWriter
11 11
12 12 #*****************************************************************************
13 13 if __name__ == '__main__':
14 14 pjoin = os.path.join
15 15 package = 'IPython'
16 16 outdir = pjoin('source','api','generated')
17 17 docwriter = ApiDocWriter(package,rst_extension='.txt')
18 18 # You have to escape the . here because . is a special char for regexps.
19 19 # You must do make clean if you change this!
20 20 docwriter.package_skip_patterns += [r'\.fixes$',
21 21 r'\.external$',
22 22 r'\.extensions',
23 23 r'\.kernel\.config',
24 24 r'\.attic',
25 25 r'\.quarantine',
26 26 r'\.deathrow',
27 27 r'\.config\.default',
28 28 r'\.config\.profile',
29 29 r'\.frontend',
30 30 r'\.gui'
31 31 ]
32
32 33 docwriter.module_skip_patterns += [ r'\.core\.fakemodule',
34
35 # XXX These need fixing, disabling for
36 # now but we need to figure out why
37 # they are breaking. Error from sphinx
38 # for each group copied below
39
40 # AttributeError: __abstractmethods__
41 r'\.core\.component',
42 r'\.utils\.traitlets',
43
44 # AttributeError: __provides__
45 r'\.kernel\.clusterdir',
46 r'\.kernel\.configobjfactory',
47 r'\.kernel\.fcutil',
48 r'\.kernel\.ipcontrollerapp',
49 r'\.kernel\.launcher',
50 r'\.kernel\.task',
51 r'\.kernel\.winhpcjob',
52 r'\.testing\.util',
53
54 # Keeping these disabled is OK
33 55 r'\.cocoa',
34 56 r'\.ipdoctest',
35 57 r'\.Gnuplot',
36 58 r'\.frontend\.process\.winprocess',
37 59 r'\.Shell',
38 60 ]
39 61 docwriter.write_api_docs(outdir)
40 62 docwriter.write_index(outdir, 'gen',
41 63 relative_to = pjoin('source','api')
42 64 )
43 65 print '%d files written' % len(docwriter.written_modules)
General Comments 0
You need to be logged in to leave comments. Login now