##// END OF EJS Templates
Only include inheritance diagram where it's useful.
Thomas Kluyver -
Show More
@@ -1,351 +1,356 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A base class for objects that are configurable.
3 A base class for objects that are configurable.
4
4
5 Inheritance diagram:
6
7 .. inheritance-diagram:: IPython.config.configurable
8 :parts: 3
9
5 Authors:
10 Authors:
6
11
7 * Brian Granger
12 * Brian Granger
8 * Fernando Perez
13 * Fernando Perez
9 * Min RK
14 * Min RK
10 """
15 """
11
16
12 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2011 The IPython Development Team
18 # Copyright (C) 2008-2011 The IPython Development Team
14 #
19 #
15 # Distributed under the terms of the BSD License. The full license is in
20 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
21 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
18
23
19 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
20 # Imports
25 # Imports
21 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
22
27
23 import datetime
28 import datetime
24 from copy import deepcopy
29 from copy import deepcopy
25
30
26 from loader import Config
31 from loader import Config
27 from IPython.utils.traitlets import HasTraits, Instance
32 from IPython.utils.traitlets import HasTraits, Instance
28 from IPython.utils.text import indent, wrap_paragraphs
33 from IPython.utils.text import indent, wrap_paragraphs
29
34
30
35
31 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
32 # Helper classes for Configurables
37 # Helper classes for Configurables
33 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
34
39
35
40
36 class ConfigurableError(Exception):
41 class ConfigurableError(Exception):
37 pass
42 pass
38
43
39
44
40 class MultipleInstanceError(ConfigurableError):
45 class MultipleInstanceError(ConfigurableError):
41 pass
46 pass
42
47
43 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
44 # Configurable implementation
49 # Configurable implementation
45 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
46
51
47 class Configurable(HasTraits):
52 class Configurable(HasTraits):
48
53
49 config = Instance(Config,(),{})
54 config = Instance(Config,(),{})
50 created = None
55 created = None
51
56
52 def __init__(self, **kwargs):
57 def __init__(self, **kwargs):
53 """Create a configurable given a config config.
58 """Create a configurable given a config config.
54
59
55 Parameters
60 Parameters
56 ----------
61 ----------
57 config : Config
62 config : Config
58 If this is empty, default values are used. If config is a
63 If this is empty, default values are used. If config is a
59 :class:`Config` instance, it will be used to configure the
64 :class:`Config` instance, it will be used to configure the
60 instance.
65 instance.
61
66
62 Notes
67 Notes
63 -----
68 -----
64 Subclasses of Configurable must call the :meth:`__init__` method of
69 Subclasses of Configurable must call the :meth:`__init__` method of
65 :class:`Configurable` *before* doing anything else and using
70 :class:`Configurable` *before* doing anything else and using
66 :func:`super`::
71 :func:`super`::
67
72
68 class MyConfigurable(Configurable):
73 class MyConfigurable(Configurable):
69 def __init__(self, config=None):
74 def __init__(self, config=None):
70 super(MyConfigurable, self).__init__(config)
75 super(MyConfigurable, self).__init__(config)
71 # Then any other code you need to finish initialization.
76 # Then any other code you need to finish initialization.
72
77
73 This ensures that instances will be configured properly.
78 This ensures that instances will be configured properly.
74 """
79 """
75 config = kwargs.pop('config', None)
80 config = kwargs.pop('config', None)
76 if config is not None:
81 if config is not None:
77 # We used to deepcopy, but for now we are trying to just save
82 # We used to deepcopy, but for now we are trying to just save
78 # by reference. This *could* have side effects as all components
83 # by reference. This *could* have side effects as all components
79 # will share config. In fact, I did find such a side effect in
84 # will share config. In fact, I did find such a side effect in
80 # _config_changed below. If a config attribute value was a mutable type
85 # _config_changed below. If a config attribute value was a mutable type
81 # all instances of a component were getting the same copy, effectively
86 # all instances of a component were getting the same copy, effectively
82 # making that a class attribute.
87 # making that a class attribute.
83 # self.config = deepcopy(config)
88 # self.config = deepcopy(config)
84 self.config = config
89 self.config = config
85 # This should go second so individual keyword arguments override
90 # This should go second so individual keyword arguments override
86 # the values in config.
91 # the values in config.
87 super(Configurable, self).__init__(**kwargs)
92 super(Configurable, self).__init__(**kwargs)
88 self.created = datetime.datetime.now()
93 self.created = datetime.datetime.now()
89
94
90 #-------------------------------------------------------------------------
95 #-------------------------------------------------------------------------
91 # Static trait notifiations
96 # Static trait notifiations
92 #-------------------------------------------------------------------------
97 #-------------------------------------------------------------------------
93
98
94 def _config_changed(self, name, old, new):
99 def _config_changed(self, name, old, new):
95 """Update all the class traits having ``config=True`` as metadata.
100 """Update all the class traits having ``config=True`` as metadata.
96
101
97 For any class trait with a ``config`` metadata attribute that is
102 For any class trait with a ``config`` metadata attribute that is
98 ``True``, we update the trait with the value of the corresponding
103 ``True``, we update the trait with the value of the corresponding
99 config entry.
104 config entry.
100 """
105 """
101 # Get all traits with a config metadata entry that is True
106 # Get all traits with a config metadata entry that is True
102 traits = self.traits(config=True)
107 traits = self.traits(config=True)
103
108
104 # We auto-load config section for this class as well as any parent
109 # We auto-load config section for this class as well as any parent
105 # classes that are Configurable subclasses. This starts with Configurable
110 # classes that are Configurable subclasses. This starts with Configurable
106 # and works down the mro loading the config for each section.
111 # and works down the mro loading the config for each section.
107 section_names = [cls.__name__ for cls in \
112 section_names = [cls.__name__ for cls in \
108 reversed(self.__class__.__mro__) if
113 reversed(self.__class__.__mro__) if
109 issubclass(cls, Configurable) and issubclass(self.__class__, cls)]
114 issubclass(cls, Configurable) and issubclass(self.__class__, cls)]
110
115
111 for sname in section_names:
116 for sname in section_names:
112 # Don't do a blind getattr as that would cause the config to
117 # Don't do a blind getattr as that would cause the config to
113 # dynamically create the section with name self.__class__.__name__.
118 # dynamically create the section with name self.__class__.__name__.
114 if new._has_section(sname):
119 if new._has_section(sname):
115 my_config = new[sname]
120 my_config = new[sname]
116 for k, v in traits.iteritems():
121 for k, v in traits.iteritems():
117 # Don't allow traitlets with config=True to start with
122 # Don't allow traitlets with config=True to start with
118 # uppercase. Otherwise, they are confused with Config
123 # uppercase. Otherwise, they are confused with Config
119 # subsections. But, developers shouldn't have uppercase
124 # subsections. But, developers shouldn't have uppercase
120 # attributes anyways! (PEP 6)
125 # attributes anyways! (PEP 6)
121 if k[0].upper()==k[0] and not k.startswith('_'):
126 if k[0].upper()==k[0] and not k.startswith('_'):
122 raise ConfigurableError('Configurable traitlets with '
127 raise ConfigurableError('Configurable traitlets with '
123 'config=True must start with a lowercase so they are '
128 'config=True must start with a lowercase so they are '
124 'not confused with Config subsections: %s.%s' % \
129 'not confused with Config subsections: %s.%s' % \
125 (self.__class__.__name__, k))
130 (self.__class__.__name__, k))
126 try:
131 try:
127 # Here we grab the value from the config
132 # Here we grab the value from the config
128 # If k has the naming convention of a config
133 # If k has the naming convention of a config
129 # section, it will be auto created.
134 # section, it will be auto created.
130 config_value = my_config[k]
135 config_value = my_config[k]
131 except KeyError:
136 except KeyError:
132 pass
137 pass
133 else:
138 else:
134 # print "Setting %s.%s from %s.%s=%r" % \
139 # print "Setting %s.%s from %s.%s=%r" % \
135 # (self.__class__.__name__,k,sname,k,config_value)
140 # (self.__class__.__name__,k,sname,k,config_value)
136 # We have to do a deepcopy here if we don't deepcopy the entire
141 # We have to do a deepcopy here if we don't deepcopy the entire
137 # config object. If we don't, a mutable config_value will be
142 # config object. If we don't, a mutable config_value will be
138 # shared by all instances, effectively making it a class attribute.
143 # shared by all instances, effectively making it a class attribute.
139 setattr(self, k, deepcopy(config_value))
144 setattr(self, k, deepcopy(config_value))
140
145
141 def update_config(self, config):
146 def update_config(self, config):
142 """Fire the traits events when the config is updated."""
147 """Fire the traits events when the config is updated."""
143 # Save a copy of the current config.
148 # Save a copy of the current config.
144 newconfig = deepcopy(self.config)
149 newconfig = deepcopy(self.config)
145 # Merge the new config into the current one.
150 # Merge the new config into the current one.
146 newconfig._merge(config)
151 newconfig._merge(config)
147 # Save the combined config as self.config, which triggers the traits
152 # Save the combined config as self.config, which triggers the traits
148 # events.
153 # events.
149 self.config = newconfig
154 self.config = newconfig
150
155
151 @classmethod
156 @classmethod
152 def class_get_help(cls, inst=None):
157 def class_get_help(cls, inst=None):
153 """Get the help string for this class in ReST format.
158 """Get the help string for this class in ReST format.
154
159
155 If `inst` is given, it's current trait values will be used in place of
160 If `inst` is given, it's current trait values will be used in place of
156 class defaults.
161 class defaults.
157 """
162 """
158 assert inst is None or isinstance(inst, cls)
163 assert inst is None or isinstance(inst, cls)
159 cls_traits = cls.class_traits(config=True)
164 cls_traits = cls.class_traits(config=True)
160 final_help = []
165 final_help = []
161 final_help.append(u'%s options' % cls.__name__)
166 final_help.append(u'%s options' % cls.__name__)
162 final_help.append(len(final_help[0])*u'-')
167 final_help.append(len(final_help[0])*u'-')
163 for k,v in sorted(cls.class_traits(config=True).iteritems()):
168 for k,v in sorted(cls.class_traits(config=True).iteritems()):
164 help = cls.class_get_trait_help(v, inst)
169 help = cls.class_get_trait_help(v, inst)
165 final_help.append(help)
170 final_help.append(help)
166 return '\n'.join(final_help)
171 return '\n'.join(final_help)
167
172
168 @classmethod
173 @classmethod
169 def class_get_trait_help(cls, trait, inst=None):
174 def class_get_trait_help(cls, trait, inst=None):
170 """Get the help string for a single trait.
175 """Get the help string for a single trait.
171
176
172 If `inst` is given, it's current trait values will be used in place of
177 If `inst` is given, it's current trait values will be used in place of
173 the class default.
178 the class default.
174 """
179 """
175 assert inst is None or isinstance(inst, cls)
180 assert inst is None or isinstance(inst, cls)
176 lines = []
181 lines = []
177 header = "--%s.%s=<%s>" % (cls.__name__, trait.name, trait.__class__.__name__)
182 header = "--%s.%s=<%s>" % (cls.__name__, trait.name, trait.__class__.__name__)
178 lines.append(header)
183 lines.append(header)
179 if inst is not None:
184 if inst is not None:
180 lines.append(indent('Current: %r' % getattr(inst, trait.name), 4))
185 lines.append(indent('Current: %r' % getattr(inst, trait.name), 4))
181 else:
186 else:
182 try:
187 try:
183 dvr = repr(trait.get_default_value())
188 dvr = repr(trait.get_default_value())
184 except Exception:
189 except Exception:
185 dvr = None # ignore defaults we can't construct
190 dvr = None # ignore defaults we can't construct
186 if dvr is not None:
191 if dvr is not None:
187 if len(dvr) > 64:
192 if len(dvr) > 64:
188 dvr = dvr[:61]+'...'
193 dvr = dvr[:61]+'...'
189 lines.append(indent('Default: %s' % dvr, 4))
194 lines.append(indent('Default: %s' % dvr, 4))
190 if 'Enum' in trait.__class__.__name__:
195 if 'Enum' in trait.__class__.__name__:
191 # include Enum choices
196 # include Enum choices
192 lines.append(indent('Choices: %r' % (trait.values,)))
197 lines.append(indent('Choices: %r' % (trait.values,)))
193
198
194 help = trait.get_metadata('help')
199 help = trait.get_metadata('help')
195 if help is not None:
200 if help is not None:
196 help = '\n'.join(wrap_paragraphs(help, 76))
201 help = '\n'.join(wrap_paragraphs(help, 76))
197 lines.append(indent(help, 4))
202 lines.append(indent(help, 4))
198 return '\n'.join(lines)
203 return '\n'.join(lines)
199
204
200 @classmethod
205 @classmethod
201 def class_print_help(cls, inst=None):
206 def class_print_help(cls, inst=None):
202 """Get the help string for a single trait and print it."""
207 """Get the help string for a single trait and print it."""
203 print cls.class_get_help(inst)
208 print cls.class_get_help(inst)
204
209
205 @classmethod
210 @classmethod
206 def class_config_section(cls):
211 def class_config_section(cls):
207 """Get the config class config section"""
212 """Get the config class config section"""
208 def c(s):
213 def c(s):
209 """return a commented, wrapped block."""
214 """return a commented, wrapped block."""
210 s = '\n\n'.join(wrap_paragraphs(s, 78))
215 s = '\n\n'.join(wrap_paragraphs(s, 78))
211
216
212 return '# ' + s.replace('\n', '\n# ')
217 return '# ' + s.replace('\n', '\n# ')
213
218
214 # section header
219 # section header
215 breaker = '#' + '-'*78
220 breaker = '#' + '-'*78
216 s = "# %s configuration"%cls.__name__
221 s = "# %s configuration"%cls.__name__
217 lines = [breaker, s, breaker, '']
222 lines = [breaker, s, breaker, '']
218 # get the description trait
223 # get the description trait
219 desc = cls.class_traits().get('description')
224 desc = cls.class_traits().get('description')
220 if desc:
225 if desc:
221 desc = desc.default_value
226 desc = desc.default_value
222 else:
227 else:
223 # no description trait, use __doc__
228 # no description trait, use __doc__
224 desc = getattr(cls, '__doc__', '')
229 desc = getattr(cls, '__doc__', '')
225 if desc:
230 if desc:
226 lines.append(c(desc))
231 lines.append(c(desc))
227 lines.append('')
232 lines.append('')
228
233
229 parents = []
234 parents = []
230 for parent in cls.mro():
235 for parent in cls.mro():
231 # only include parents that are not base classes
236 # only include parents that are not base classes
232 # and are not the class itself
237 # and are not the class itself
233 # and have some configurable traits to inherit
238 # and have some configurable traits to inherit
234 if parent is not cls and issubclass(parent, Configurable) and \
239 if parent is not cls and issubclass(parent, Configurable) and \
235 parent.class_traits(config=True):
240 parent.class_traits(config=True):
236 parents.append(parent)
241 parents.append(parent)
237
242
238 if parents:
243 if parents:
239 pstr = ', '.join([ p.__name__ for p in parents ])
244 pstr = ', '.join([ p.__name__ for p in parents ])
240 lines.append(c('%s will inherit config from: %s'%(cls.__name__, pstr)))
245 lines.append(c('%s will inherit config from: %s'%(cls.__name__, pstr)))
241 lines.append('')
246 lines.append('')
242
247
243 for name,trait in cls.class_traits(config=True).iteritems():
248 for name,trait in cls.class_traits(config=True).iteritems():
244 help = trait.get_metadata('help') or ''
249 help = trait.get_metadata('help') or ''
245 lines.append(c(help))
250 lines.append(c(help))
246 lines.append('# c.%s.%s = %r'%(cls.__name__, name, trait.get_default_value()))
251 lines.append('# c.%s.%s = %r'%(cls.__name__, name, trait.get_default_value()))
247 lines.append('')
252 lines.append('')
248 return '\n'.join(lines)
253 return '\n'.join(lines)
249
254
250
255
251
256
252 class SingletonConfigurable(Configurable):
257 class SingletonConfigurable(Configurable):
253 """A configurable that only allows one instance.
258 """A configurable that only allows one instance.
254
259
255 This class is for classes that should only have one instance of itself
260 This class is for classes that should only have one instance of itself
256 or *any* subclass. To create and retrieve such a class use the
261 or *any* subclass. To create and retrieve such a class use the
257 :meth:`SingletonConfigurable.instance` method.
262 :meth:`SingletonConfigurable.instance` method.
258 """
263 """
259
264
260 _instance = None
265 _instance = None
261
266
262 @classmethod
267 @classmethod
263 def _walk_mro(cls):
268 def _walk_mro(cls):
264 """Walk the cls.mro() for parent classes that are also singletons
269 """Walk the cls.mro() for parent classes that are also singletons
265
270
266 For use in instance()
271 For use in instance()
267 """
272 """
268
273
269 for subclass in cls.mro():
274 for subclass in cls.mro():
270 if issubclass(cls, subclass) and \
275 if issubclass(cls, subclass) and \
271 issubclass(subclass, SingletonConfigurable) and \
276 issubclass(subclass, SingletonConfigurable) and \
272 subclass != SingletonConfigurable:
277 subclass != SingletonConfigurable:
273 yield subclass
278 yield subclass
274
279
275 @classmethod
280 @classmethod
276 def clear_instance(cls):
281 def clear_instance(cls):
277 """unset _instance for this class and singleton parents.
282 """unset _instance for this class and singleton parents.
278 """
283 """
279 if not cls.initialized():
284 if not cls.initialized():
280 return
285 return
281 for subclass in cls._walk_mro():
286 for subclass in cls._walk_mro():
282 if isinstance(subclass._instance, cls):
287 if isinstance(subclass._instance, cls):
283 # only clear instances that are instances
288 # only clear instances that are instances
284 # of the calling class
289 # of the calling class
285 subclass._instance = None
290 subclass._instance = None
286
291
287 @classmethod
292 @classmethod
288 def instance(cls, *args, **kwargs):
293 def instance(cls, *args, **kwargs):
289 """Returns a global instance of this class.
294 """Returns a global instance of this class.
290
295
291 This method create a new instance if none have previously been created
296 This method create a new instance if none have previously been created
292 and returns a previously created instance is one already exists.
297 and returns a previously created instance is one already exists.
293
298
294 The arguments and keyword arguments passed to this method are passed
299 The arguments and keyword arguments passed to this method are passed
295 on to the :meth:`__init__` method of the class upon instantiation.
300 on to the :meth:`__init__` method of the class upon instantiation.
296
301
297 Examples
302 Examples
298 --------
303 --------
299
304
300 Create a singleton class using instance, and retrieve it::
305 Create a singleton class using instance, and retrieve it::
301
306
302 >>> from IPython.config.configurable import SingletonConfigurable
307 >>> from IPython.config.configurable import SingletonConfigurable
303 >>> class Foo(SingletonConfigurable): pass
308 >>> class Foo(SingletonConfigurable): pass
304 >>> foo = Foo.instance()
309 >>> foo = Foo.instance()
305 >>> foo == Foo.instance()
310 >>> foo == Foo.instance()
306 True
311 True
307
312
308 Create a subclass that is retrived using the base class instance::
313 Create a subclass that is retrived using the base class instance::
309
314
310 >>> class Bar(SingletonConfigurable): pass
315 >>> class Bar(SingletonConfigurable): pass
311 >>> class Bam(Bar): pass
316 >>> class Bam(Bar): pass
312 >>> bam = Bam.instance()
317 >>> bam = Bam.instance()
313 >>> bam == Bar.instance()
318 >>> bam == Bar.instance()
314 True
319 True
315 """
320 """
316 # Create and save the instance
321 # Create and save the instance
317 if cls._instance is None:
322 if cls._instance is None:
318 inst = cls(*args, **kwargs)
323 inst = cls(*args, **kwargs)
319 # Now make sure that the instance will also be returned by
324 # Now make sure that the instance will also be returned by
320 # parent classes' _instance attribute.
325 # parent classes' _instance attribute.
321 for subclass in cls._walk_mro():
326 for subclass in cls._walk_mro():
322 subclass._instance = inst
327 subclass._instance = inst
323
328
324 if isinstance(cls._instance, cls):
329 if isinstance(cls._instance, cls):
325 return cls._instance
330 return cls._instance
326 else:
331 else:
327 raise MultipleInstanceError(
332 raise MultipleInstanceError(
328 'Multiple incompatible subclass instances of '
333 'Multiple incompatible subclass instances of '
329 '%s are being created.' % cls.__name__
334 '%s are being created.' % cls.__name__
330 )
335 )
331
336
332 @classmethod
337 @classmethod
333 def initialized(cls):
338 def initialized(cls):
334 """Has an instance been created?"""
339 """Has an instance been created?"""
335 return hasattr(cls, "_instance") and cls._instance is not None
340 return hasattr(cls, "_instance") and cls._instance is not None
336
341
337
342
338 class LoggingConfigurable(Configurable):
343 class LoggingConfigurable(Configurable):
339 """A parent class for Configurables that log.
344 """A parent class for Configurables that log.
340
345
341 Subclasses have a log trait, and the default behavior
346 Subclasses have a log trait, and the default behavior
342 is to get the logger from the currently running Application
347 is to get the logger from the currently running Application
343 via Application.instance().log.
348 via Application.instance().log.
344 """
349 """
345
350
346 log = Instance('logging.Logger')
351 log = Instance('logging.Logger')
347 def _log_default(self):
352 def _log_default(self):
348 from IPython.config.application import Application
353 from IPython.config.application import Application
349 return Application.instance().log
354 return Application.instance().log
350
355
351
356
@@ -1,696 +1,701 b''
1 """A simple configuration system.
1 """A simple configuration system.
2
2
3 Inheritance diagram:
4
5 .. inheritance-diagram:: IPython.config.loader
6 :parts: 3
7
3 Authors
8 Authors
4 -------
9 -------
5 * Brian Granger
10 * Brian Granger
6 * Fernando Perez
11 * Fernando Perez
7 * Min RK
12 * Min RK
8 """
13 """
9
14
10 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2011 The IPython Development Team
16 # Copyright (C) 2008-2011 The IPython Development Team
12 #
17 #
13 # Distributed under the terms of the BSD License. The full license is in
18 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
19 # the file COPYING, distributed as part of this software.
15 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
16
21
17 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
18 # Imports
23 # Imports
19 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
20
25
21 import __builtin__ as builtin_mod
26 import __builtin__ as builtin_mod
22 import os
27 import os
23 import re
28 import re
24 import sys
29 import sys
25
30
26 from IPython.external import argparse
31 from IPython.external import argparse
27 from IPython.utils.path import filefind, get_ipython_dir
32 from IPython.utils.path import filefind, get_ipython_dir
28 from IPython.utils import py3compat, text, warn
33 from IPython.utils import py3compat, text, warn
29 from IPython.utils.encoding import DEFAULT_ENCODING
34 from IPython.utils.encoding import DEFAULT_ENCODING
30
35
31 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
32 # Exceptions
37 # Exceptions
33 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
34
39
35
40
36 class ConfigError(Exception):
41 class ConfigError(Exception):
37 pass
42 pass
38
43
39 class ConfigLoaderError(ConfigError):
44 class ConfigLoaderError(ConfigError):
40 pass
45 pass
41
46
42 class ConfigFileNotFound(ConfigError):
47 class ConfigFileNotFound(ConfigError):
43 pass
48 pass
44
49
45 class ArgumentError(ConfigLoaderError):
50 class ArgumentError(ConfigLoaderError):
46 pass
51 pass
47
52
48 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
49 # Argparse fix
54 # Argparse fix
50 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
51
56
52 # Unfortunately argparse by default prints help messages to stderr instead of
57 # Unfortunately argparse by default prints help messages to stderr instead of
53 # stdout. This makes it annoying to capture long help screens at the command
58 # stdout. This makes it annoying to capture long help screens at the command
54 # line, since one must know how to pipe stderr, which many users don't know how
59 # line, since one must know how to pipe stderr, which many users don't know how
55 # to do. So we override the print_help method with one that defaults to
60 # to do. So we override the print_help method with one that defaults to
56 # stdout and use our class instead.
61 # stdout and use our class instead.
57
62
58 class ArgumentParser(argparse.ArgumentParser):
63 class ArgumentParser(argparse.ArgumentParser):
59 """Simple argparse subclass that prints help to stdout by default."""
64 """Simple argparse subclass that prints help to stdout by default."""
60
65
61 def print_help(self, file=None):
66 def print_help(self, file=None):
62 if file is None:
67 if file is None:
63 file = sys.stdout
68 file = sys.stdout
64 return super(ArgumentParser, self).print_help(file)
69 return super(ArgumentParser, self).print_help(file)
65
70
66 print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__
71 print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__
67
72
68 #-----------------------------------------------------------------------------
73 #-----------------------------------------------------------------------------
69 # Config class for holding config information
74 # Config class for holding config information
70 #-----------------------------------------------------------------------------
75 #-----------------------------------------------------------------------------
71
76
72
77
73 class Config(dict):
78 class Config(dict):
74 """An attribute based dict that can do smart merges."""
79 """An attribute based dict that can do smart merges."""
75
80
76 def __init__(self, *args, **kwds):
81 def __init__(self, *args, **kwds):
77 dict.__init__(self, *args, **kwds)
82 dict.__init__(self, *args, **kwds)
78 # This sets self.__dict__ = self, but it has to be done this way
83 # This sets self.__dict__ = self, but it has to be done this way
79 # because we are also overriding __setattr__.
84 # because we are also overriding __setattr__.
80 dict.__setattr__(self, '__dict__', self)
85 dict.__setattr__(self, '__dict__', self)
81
86
82 def _merge(self, other):
87 def _merge(self, other):
83 to_update = {}
88 to_update = {}
84 for k, v in other.iteritems():
89 for k, v in other.iteritems():
85 if k not in self:
90 if k not in self:
86 to_update[k] = v
91 to_update[k] = v
87 else: # I have this key
92 else: # I have this key
88 if isinstance(v, Config):
93 if isinstance(v, Config):
89 # Recursively merge common sub Configs
94 # Recursively merge common sub Configs
90 self[k]._merge(v)
95 self[k]._merge(v)
91 else:
96 else:
92 # Plain updates for non-Configs
97 # Plain updates for non-Configs
93 to_update[k] = v
98 to_update[k] = v
94
99
95 self.update(to_update)
100 self.update(to_update)
96
101
97 def _is_section_key(self, key):
102 def _is_section_key(self, key):
98 if key[0].upper()==key[0] and not key.startswith('_'):
103 if key[0].upper()==key[0] and not key.startswith('_'):
99 return True
104 return True
100 else:
105 else:
101 return False
106 return False
102
107
103 def __contains__(self, key):
108 def __contains__(self, key):
104 if self._is_section_key(key):
109 if self._is_section_key(key):
105 return True
110 return True
106 else:
111 else:
107 return super(Config, self).__contains__(key)
112 return super(Config, self).__contains__(key)
108 # .has_key is deprecated for dictionaries.
113 # .has_key is deprecated for dictionaries.
109 has_key = __contains__
114 has_key = __contains__
110
115
111 def _has_section(self, key):
116 def _has_section(self, key):
112 if self._is_section_key(key):
117 if self._is_section_key(key):
113 if super(Config, self).__contains__(key):
118 if super(Config, self).__contains__(key):
114 return True
119 return True
115 return False
120 return False
116
121
117 def copy(self):
122 def copy(self):
118 return type(self)(dict.copy(self))
123 return type(self)(dict.copy(self))
119
124
120 def __copy__(self):
125 def __copy__(self):
121 return self.copy()
126 return self.copy()
122
127
123 def __deepcopy__(self, memo):
128 def __deepcopy__(self, memo):
124 import copy
129 import copy
125 return type(self)(copy.deepcopy(self.items()))
130 return type(self)(copy.deepcopy(self.items()))
126
131
127 def __getitem__(self, key):
132 def __getitem__(self, key):
128 # We cannot use directly self._is_section_key, because it triggers
133 # We cannot use directly self._is_section_key, because it triggers
129 # infinite recursion on top of PyPy. Instead, we manually fish the
134 # infinite recursion on top of PyPy. Instead, we manually fish the
130 # bound method.
135 # bound method.
131 is_section_key = self.__class__._is_section_key.__get__(self)
136 is_section_key = self.__class__._is_section_key.__get__(self)
132
137
133 # Because we use this for an exec namespace, we need to delegate
138 # Because we use this for an exec namespace, we need to delegate
134 # the lookup of names in __builtin__ to itself. This means
139 # the lookup of names in __builtin__ to itself. This means
135 # that you can't have section or attribute names that are
140 # that you can't have section or attribute names that are
136 # builtins.
141 # builtins.
137 try:
142 try:
138 return getattr(builtin_mod, key)
143 return getattr(builtin_mod, key)
139 except AttributeError:
144 except AttributeError:
140 pass
145 pass
141 if is_section_key(key):
146 if is_section_key(key):
142 try:
147 try:
143 return dict.__getitem__(self, key)
148 return dict.__getitem__(self, key)
144 except KeyError:
149 except KeyError:
145 c = Config()
150 c = Config()
146 dict.__setitem__(self, key, c)
151 dict.__setitem__(self, key, c)
147 return c
152 return c
148 else:
153 else:
149 return dict.__getitem__(self, key)
154 return dict.__getitem__(self, key)
150
155
151 def __setitem__(self, key, value):
156 def __setitem__(self, key, value):
152 # Don't allow names in __builtin__ to be modified.
157 # Don't allow names in __builtin__ to be modified.
153 if hasattr(builtin_mod, key):
158 if hasattr(builtin_mod, key):
154 raise ConfigError('Config variable names cannot have the same name '
159 raise ConfigError('Config variable names cannot have the same name '
155 'as a Python builtin: %s' % key)
160 'as a Python builtin: %s' % key)
156 if self._is_section_key(key):
161 if self._is_section_key(key):
157 if not isinstance(value, Config):
162 if not isinstance(value, Config):
158 raise ValueError('values whose keys begin with an uppercase '
163 raise ValueError('values whose keys begin with an uppercase '
159 'char must be Config instances: %r, %r' % (key, value))
164 'char must be Config instances: %r, %r' % (key, value))
160 else:
165 else:
161 dict.__setitem__(self, key, value)
166 dict.__setitem__(self, key, value)
162
167
163 def __getattr__(self, key):
168 def __getattr__(self, key):
164 try:
169 try:
165 return self.__getitem__(key)
170 return self.__getitem__(key)
166 except KeyError as e:
171 except KeyError as e:
167 raise AttributeError(e)
172 raise AttributeError(e)
168
173
169 def __setattr__(self, key, value):
174 def __setattr__(self, key, value):
170 try:
175 try:
171 self.__setitem__(key, value)
176 self.__setitem__(key, value)
172 except KeyError as e:
177 except KeyError as e:
173 raise AttributeError(e)
178 raise AttributeError(e)
174
179
175 def __delattr__(self, key):
180 def __delattr__(self, key):
176 try:
181 try:
177 dict.__delitem__(self, key)
182 dict.__delitem__(self, key)
178 except KeyError as e:
183 except KeyError as e:
179 raise AttributeError(e)
184 raise AttributeError(e)
180
185
181
186
182 #-----------------------------------------------------------------------------
187 #-----------------------------------------------------------------------------
183 # Config loading classes
188 # Config loading classes
184 #-----------------------------------------------------------------------------
189 #-----------------------------------------------------------------------------
185
190
186
191
187 class ConfigLoader(object):
192 class ConfigLoader(object):
188 """A object for loading configurations from just about anywhere.
193 """A object for loading configurations from just about anywhere.
189
194
190 The resulting configuration is packaged as a :class:`Struct`.
195 The resulting configuration is packaged as a :class:`Struct`.
191
196
192 Notes
197 Notes
193 -----
198 -----
194 A :class:`ConfigLoader` does one thing: load a config from a source
199 A :class:`ConfigLoader` does one thing: load a config from a source
195 (file, command line arguments) and returns the data as a :class:`Struct`.
200 (file, command line arguments) and returns the data as a :class:`Struct`.
196 There are lots of things that :class:`ConfigLoader` does not do. It does
201 There are lots of things that :class:`ConfigLoader` does not do. It does
197 not implement complex logic for finding config files. It does not handle
202 not implement complex logic for finding config files. It does not handle
198 default values or merge multiple configs. These things need to be
203 default values or merge multiple configs. These things need to be
199 handled elsewhere.
204 handled elsewhere.
200 """
205 """
201
206
202 def __init__(self):
207 def __init__(self):
203 """A base class for config loaders.
208 """A base class for config loaders.
204
209
205 Examples
210 Examples
206 --------
211 --------
207
212
208 >>> cl = ConfigLoader()
213 >>> cl = ConfigLoader()
209 >>> config = cl.load_config()
214 >>> config = cl.load_config()
210 >>> config
215 >>> config
211 {}
216 {}
212 """
217 """
213 self.clear()
218 self.clear()
214
219
215 def clear(self):
220 def clear(self):
216 self.config = Config()
221 self.config = Config()
217
222
218 def load_config(self):
223 def load_config(self):
219 """Load a config from somewhere, return a :class:`Config` instance.
224 """Load a config from somewhere, return a :class:`Config` instance.
220
225
221 Usually, this will cause self.config to be set and then returned.
226 Usually, this will cause self.config to be set and then returned.
222 However, in most cases, :meth:`ConfigLoader.clear` should be called
227 However, in most cases, :meth:`ConfigLoader.clear` should be called
223 to erase any previous state.
228 to erase any previous state.
224 """
229 """
225 self.clear()
230 self.clear()
226 return self.config
231 return self.config
227
232
228
233
229 class FileConfigLoader(ConfigLoader):
234 class FileConfigLoader(ConfigLoader):
230 """A base class for file based configurations.
235 """A base class for file based configurations.
231
236
232 As we add more file based config loaders, the common logic should go
237 As we add more file based config loaders, the common logic should go
233 here.
238 here.
234 """
239 """
235 pass
240 pass
236
241
237
242
238 class PyFileConfigLoader(FileConfigLoader):
243 class PyFileConfigLoader(FileConfigLoader):
239 """A config loader for pure python files.
244 """A config loader for pure python files.
240
245
241 This calls execfile on a plain python file and looks for attributes
246 This calls execfile on a plain python file and looks for attributes
242 that are all caps. These attribute are added to the config Struct.
247 that are all caps. These attribute are added to the config Struct.
243 """
248 """
244
249
245 def __init__(self, filename, path=None):
250 def __init__(self, filename, path=None):
246 """Build a config loader for a filename and path.
251 """Build a config loader for a filename and path.
247
252
248 Parameters
253 Parameters
249 ----------
254 ----------
250 filename : str
255 filename : str
251 The file name of the config file.
256 The file name of the config file.
252 path : str, list, tuple
257 path : str, list, tuple
253 The path to search for the config file on, or a sequence of
258 The path to search for the config file on, or a sequence of
254 paths to try in order.
259 paths to try in order.
255 """
260 """
256 super(PyFileConfigLoader, self).__init__()
261 super(PyFileConfigLoader, self).__init__()
257 self.filename = filename
262 self.filename = filename
258 self.path = path
263 self.path = path
259 self.full_filename = ''
264 self.full_filename = ''
260 self.data = None
265 self.data = None
261
266
262 def load_config(self):
267 def load_config(self):
263 """Load the config from a file and return it as a Struct."""
268 """Load the config from a file and return it as a Struct."""
264 self.clear()
269 self.clear()
265 try:
270 try:
266 self._find_file()
271 self._find_file()
267 except IOError as e:
272 except IOError as e:
268 raise ConfigFileNotFound(str(e))
273 raise ConfigFileNotFound(str(e))
269 self._read_file_as_dict()
274 self._read_file_as_dict()
270 self._convert_to_config()
275 self._convert_to_config()
271 return self.config
276 return self.config
272
277
273 def _find_file(self):
278 def _find_file(self):
274 """Try to find the file by searching the paths."""
279 """Try to find the file by searching the paths."""
275 self.full_filename = filefind(self.filename, self.path)
280 self.full_filename = filefind(self.filename, self.path)
276
281
277 def _read_file_as_dict(self):
282 def _read_file_as_dict(self):
278 """Load the config file into self.config, with recursive loading."""
283 """Load the config file into self.config, with recursive loading."""
279 # This closure is made available in the namespace that is used
284 # This closure is made available in the namespace that is used
280 # to exec the config file. It allows users to call
285 # to exec the config file. It allows users to call
281 # load_subconfig('myconfig.py') to load config files recursively.
286 # load_subconfig('myconfig.py') to load config files recursively.
282 # It needs to be a closure because it has references to self.path
287 # It needs to be a closure because it has references to self.path
283 # and self.config. The sub-config is loaded with the same path
288 # and self.config. The sub-config is loaded with the same path
284 # as the parent, but it uses an empty config which is then merged
289 # as the parent, but it uses an empty config which is then merged
285 # with the parents.
290 # with the parents.
286
291
287 # If a profile is specified, the config file will be loaded
292 # If a profile is specified, the config file will be loaded
288 # from that profile
293 # from that profile
289
294
290 def load_subconfig(fname, profile=None):
295 def load_subconfig(fname, profile=None):
291 # import here to prevent circular imports
296 # import here to prevent circular imports
292 from IPython.core.profiledir import ProfileDir, ProfileDirError
297 from IPython.core.profiledir import ProfileDir, ProfileDirError
293 if profile is not None:
298 if profile is not None:
294 try:
299 try:
295 profile_dir = ProfileDir.find_profile_dir_by_name(
300 profile_dir = ProfileDir.find_profile_dir_by_name(
296 get_ipython_dir(),
301 get_ipython_dir(),
297 profile,
302 profile,
298 )
303 )
299 except ProfileDirError:
304 except ProfileDirError:
300 return
305 return
301 path = profile_dir.location
306 path = profile_dir.location
302 else:
307 else:
303 path = self.path
308 path = self.path
304 loader = PyFileConfigLoader(fname, path)
309 loader = PyFileConfigLoader(fname, path)
305 try:
310 try:
306 sub_config = loader.load_config()
311 sub_config = loader.load_config()
307 except ConfigFileNotFound:
312 except ConfigFileNotFound:
308 # Pass silently if the sub config is not there. This happens
313 # Pass silently if the sub config is not there. This happens
309 # when a user s using a profile, but not the default config.
314 # when a user s using a profile, but not the default config.
310 pass
315 pass
311 else:
316 else:
312 self.config._merge(sub_config)
317 self.config._merge(sub_config)
313
318
314 # Again, this needs to be a closure and should be used in config
319 # Again, this needs to be a closure and should be used in config
315 # files to get the config being loaded.
320 # files to get the config being loaded.
316 def get_config():
321 def get_config():
317 return self.config
322 return self.config
318
323
319 namespace = dict(load_subconfig=load_subconfig, get_config=get_config)
324 namespace = dict(load_subconfig=load_subconfig, get_config=get_config)
320 fs_encoding = sys.getfilesystemencoding() or 'ascii'
325 fs_encoding = sys.getfilesystemencoding() or 'ascii'
321 conf_filename = self.full_filename.encode(fs_encoding)
326 conf_filename = self.full_filename.encode(fs_encoding)
322 py3compat.execfile(conf_filename, namespace)
327 py3compat.execfile(conf_filename, namespace)
323
328
324 def _convert_to_config(self):
329 def _convert_to_config(self):
325 if self.data is None:
330 if self.data is None:
326 ConfigLoaderError('self.data does not exist')
331 ConfigLoaderError('self.data does not exist')
327
332
328
333
329 class CommandLineConfigLoader(ConfigLoader):
334 class CommandLineConfigLoader(ConfigLoader):
330 """A config loader for command line arguments.
335 """A config loader for command line arguments.
331
336
332 As we add more command line based loaders, the common logic should go
337 As we add more command line based loaders, the common logic should go
333 here.
338 here.
334 """
339 """
335
340
336 def _exec_config_str(self, lhs, rhs):
341 def _exec_config_str(self, lhs, rhs):
337 """execute self.config.<lhs> = <rhs>
342 """execute self.config.<lhs> = <rhs>
338
343
339 * expands ~ with expanduser
344 * expands ~ with expanduser
340 * tries to assign with raw eval, otherwise assigns with just the string,
345 * tries to assign with raw eval, otherwise assigns with just the string,
341 allowing `--C.a=foobar` and `--C.a="foobar"` to be equivalent. *Not*
346 allowing `--C.a=foobar` and `--C.a="foobar"` to be equivalent. *Not*
342 equivalent are `--C.a=4` and `--C.a='4'`.
347 equivalent are `--C.a=4` and `--C.a='4'`.
343 """
348 """
344 rhs = os.path.expanduser(rhs)
349 rhs = os.path.expanduser(rhs)
345 try:
350 try:
346 # Try to see if regular Python syntax will work. This
351 # Try to see if regular Python syntax will work. This
347 # won't handle strings as the quote marks are removed
352 # won't handle strings as the quote marks are removed
348 # by the system shell.
353 # by the system shell.
349 value = eval(rhs)
354 value = eval(rhs)
350 except (NameError, SyntaxError):
355 except (NameError, SyntaxError):
351 # This case happens if the rhs is a string.
356 # This case happens if the rhs is a string.
352 value = rhs
357 value = rhs
353
358
354 exec u'self.config.%s = value' % lhs
359 exec u'self.config.%s = value' % lhs
355
360
356 def _load_flag(self, cfg):
361 def _load_flag(self, cfg):
357 """update self.config from a flag, which can be a dict or Config"""
362 """update self.config from a flag, which can be a dict or Config"""
358 if isinstance(cfg, (dict, Config)):
363 if isinstance(cfg, (dict, Config)):
359 # don't clobber whole config sections, update
364 # don't clobber whole config sections, update
360 # each section from config:
365 # each section from config:
361 for sec,c in cfg.iteritems():
366 for sec,c in cfg.iteritems():
362 self.config[sec].update(c)
367 self.config[sec].update(c)
363 else:
368 else:
364 raise TypeError("Invalid flag: %r" % cfg)
369 raise TypeError("Invalid flag: %r" % cfg)
365
370
366 # raw --identifier=value pattern
371 # raw --identifier=value pattern
367 # but *also* accept '-' as wordsep, for aliases
372 # but *also* accept '-' as wordsep, for aliases
368 # accepts: --foo=a
373 # accepts: --foo=a
369 # --Class.trait=value
374 # --Class.trait=value
370 # --alias-name=value
375 # --alias-name=value
371 # rejects: -foo=value
376 # rejects: -foo=value
372 # --foo
377 # --foo
373 # --Class.trait
378 # --Class.trait
374 kv_pattern = re.compile(r'\-\-[A-Za-z][\w\-]*(\.[\w\-]+)*\=.*')
379 kv_pattern = re.compile(r'\-\-[A-Za-z][\w\-]*(\.[\w\-]+)*\=.*')
375
380
376 # just flags, no assignments, with two *or one* leading '-'
381 # just flags, no assignments, with two *or one* leading '-'
377 # accepts: --foo
382 # accepts: --foo
378 # -foo-bar-again
383 # -foo-bar-again
379 # rejects: --anything=anything
384 # rejects: --anything=anything
380 # --two.word
385 # --two.word
381
386
382 flag_pattern = re.compile(r'\-\-?\w+[\-\w]*$')
387 flag_pattern = re.compile(r'\-\-?\w+[\-\w]*$')
383
388
384 class KeyValueConfigLoader(CommandLineConfigLoader):
389 class KeyValueConfigLoader(CommandLineConfigLoader):
385 """A config loader that loads key value pairs from the command line.
390 """A config loader that loads key value pairs from the command line.
386
391
387 This allows command line options to be gives in the following form::
392 This allows command line options to be gives in the following form::
388
393
389 ipython --profile="foo" --InteractiveShell.autocall=False
394 ipython --profile="foo" --InteractiveShell.autocall=False
390 """
395 """
391
396
392 def __init__(self, argv=None, aliases=None, flags=None):
397 def __init__(self, argv=None, aliases=None, flags=None):
393 """Create a key value pair config loader.
398 """Create a key value pair config loader.
394
399
395 Parameters
400 Parameters
396 ----------
401 ----------
397 argv : list
402 argv : list
398 A list that has the form of sys.argv[1:] which has unicode
403 A list that has the form of sys.argv[1:] which has unicode
399 elements of the form u"key=value". If this is None (default),
404 elements of the form u"key=value". If this is None (default),
400 then sys.argv[1:] will be used.
405 then sys.argv[1:] will be used.
401 aliases : dict
406 aliases : dict
402 A dict of aliases for configurable traits.
407 A dict of aliases for configurable traits.
403 Keys are the short aliases, Values are the resolved trait.
408 Keys are the short aliases, Values are the resolved trait.
404 Of the form: `{'alias' : 'Configurable.trait'}`
409 Of the form: `{'alias' : 'Configurable.trait'}`
405 flags : dict
410 flags : dict
406 A dict of flags, keyed by str name. Vaues can be Config objects,
411 A dict of flags, keyed by str name. Vaues can be Config objects,
407 dicts, or "key=value" strings. If Config or dict, when the flag
412 dicts, or "key=value" strings. If Config or dict, when the flag
408 is triggered, The flag is loaded as `self.config.update(m)`.
413 is triggered, The flag is loaded as `self.config.update(m)`.
409
414
410 Returns
415 Returns
411 -------
416 -------
412 config : Config
417 config : Config
413 The resulting Config object.
418 The resulting Config object.
414
419
415 Examples
420 Examples
416 --------
421 --------
417
422
418 >>> from IPython.config.loader import KeyValueConfigLoader
423 >>> from IPython.config.loader import KeyValueConfigLoader
419 >>> cl = KeyValueConfigLoader()
424 >>> cl = KeyValueConfigLoader()
420 >>> d = cl.load_config(["--A.name='brian'","--B.number=0"])
425 >>> d = cl.load_config(["--A.name='brian'","--B.number=0"])
421 >>> sorted(d.items())
426 >>> sorted(d.items())
422 [('A', {'name': 'brian'}), ('B', {'number': 0})]
427 [('A', {'name': 'brian'}), ('B', {'number': 0})]
423 """
428 """
424 self.clear()
429 self.clear()
425 if argv is None:
430 if argv is None:
426 argv = sys.argv[1:]
431 argv = sys.argv[1:]
427 self.argv = argv
432 self.argv = argv
428 self.aliases = aliases or {}
433 self.aliases = aliases or {}
429 self.flags = flags or {}
434 self.flags = flags or {}
430
435
431
436
432 def clear(self):
437 def clear(self):
433 super(KeyValueConfigLoader, self).clear()
438 super(KeyValueConfigLoader, self).clear()
434 self.extra_args = []
439 self.extra_args = []
435
440
436
441
437 def _decode_argv(self, argv, enc=None):
442 def _decode_argv(self, argv, enc=None):
438 """decode argv if bytes, using stin.encoding, falling back on default enc"""
443 """decode argv if bytes, using stin.encoding, falling back on default enc"""
439 uargv = []
444 uargv = []
440 if enc is None:
445 if enc is None:
441 enc = DEFAULT_ENCODING
446 enc = DEFAULT_ENCODING
442 for arg in argv:
447 for arg in argv:
443 if not isinstance(arg, unicode):
448 if not isinstance(arg, unicode):
444 # only decode if not already decoded
449 # only decode if not already decoded
445 arg = arg.decode(enc)
450 arg = arg.decode(enc)
446 uargv.append(arg)
451 uargv.append(arg)
447 return uargv
452 return uargv
448
453
449
454
450 def load_config(self, argv=None, aliases=None, flags=None):
455 def load_config(self, argv=None, aliases=None, flags=None):
451 """Parse the configuration and generate the Config object.
456 """Parse the configuration and generate the Config object.
452
457
453 After loading, any arguments that are not key-value or
458 After loading, any arguments that are not key-value or
454 flags will be stored in self.extra_args - a list of
459 flags will be stored in self.extra_args - a list of
455 unparsed command-line arguments. This is used for
460 unparsed command-line arguments. This is used for
456 arguments such as input files or subcommands.
461 arguments such as input files or subcommands.
457
462
458 Parameters
463 Parameters
459 ----------
464 ----------
460 argv : list, optional
465 argv : list, optional
461 A list that has the form of sys.argv[1:] which has unicode
466 A list that has the form of sys.argv[1:] which has unicode
462 elements of the form u"key=value". If this is None (default),
467 elements of the form u"key=value". If this is None (default),
463 then self.argv will be used.
468 then self.argv will be used.
464 aliases : dict
469 aliases : dict
465 A dict of aliases for configurable traits.
470 A dict of aliases for configurable traits.
466 Keys are the short aliases, Values are the resolved trait.
471 Keys are the short aliases, Values are the resolved trait.
467 Of the form: `{'alias' : 'Configurable.trait'}`
472 Of the form: `{'alias' : 'Configurable.trait'}`
468 flags : dict
473 flags : dict
469 A dict of flags, keyed by str name. Values can be Config objects
474 A dict of flags, keyed by str name. Values can be Config objects
470 or dicts. When the flag is triggered, The config is loaded as
475 or dicts. When the flag is triggered, The config is loaded as
471 `self.config.update(cfg)`.
476 `self.config.update(cfg)`.
472 """
477 """
473 from IPython.config.configurable import Configurable
478 from IPython.config.configurable import Configurable
474
479
475 self.clear()
480 self.clear()
476 if argv is None:
481 if argv is None:
477 argv = self.argv
482 argv = self.argv
478 if aliases is None:
483 if aliases is None:
479 aliases = self.aliases
484 aliases = self.aliases
480 if flags is None:
485 if flags is None:
481 flags = self.flags
486 flags = self.flags
482
487
483 # ensure argv is a list of unicode strings:
488 # ensure argv is a list of unicode strings:
484 uargv = self._decode_argv(argv)
489 uargv = self._decode_argv(argv)
485 for idx,raw in enumerate(uargv):
490 for idx,raw in enumerate(uargv):
486 # strip leading '-'
491 # strip leading '-'
487 item = raw.lstrip('-')
492 item = raw.lstrip('-')
488
493
489 if raw == '--':
494 if raw == '--':
490 # don't parse arguments after '--'
495 # don't parse arguments after '--'
491 # this is useful for relaying arguments to scripts, e.g.
496 # this is useful for relaying arguments to scripts, e.g.
492 # ipython -i foo.py --pylab=qt -- args after '--' go-to-foo.py
497 # ipython -i foo.py --pylab=qt -- args after '--' go-to-foo.py
493 self.extra_args.extend(uargv[idx+1:])
498 self.extra_args.extend(uargv[idx+1:])
494 break
499 break
495
500
496 if kv_pattern.match(raw):
501 if kv_pattern.match(raw):
497 lhs,rhs = item.split('=',1)
502 lhs,rhs = item.split('=',1)
498 # Substitute longnames for aliases.
503 # Substitute longnames for aliases.
499 if lhs in aliases:
504 if lhs in aliases:
500 lhs = aliases[lhs]
505 lhs = aliases[lhs]
501 if '.' not in lhs:
506 if '.' not in lhs:
502 # probably a mistyped alias, but not technically illegal
507 # probably a mistyped alias, but not technically illegal
503 warn.warn("Unrecognized alias: '%s', it will probably have no effect."%lhs)
508 warn.warn("Unrecognized alias: '%s', it will probably have no effect."%lhs)
504 try:
509 try:
505 self._exec_config_str(lhs, rhs)
510 self._exec_config_str(lhs, rhs)
506 except Exception:
511 except Exception:
507 raise ArgumentError("Invalid argument: '%s'" % raw)
512 raise ArgumentError("Invalid argument: '%s'" % raw)
508
513
509 elif flag_pattern.match(raw):
514 elif flag_pattern.match(raw):
510 if item in flags:
515 if item in flags:
511 cfg,help = flags[item]
516 cfg,help = flags[item]
512 self._load_flag(cfg)
517 self._load_flag(cfg)
513 else:
518 else:
514 raise ArgumentError("Unrecognized flag: '%s'"%raw)
519 raise ArgumentError("Unrecognized flag: '%s'"%raw)
515 elif raw.startswith('-'):
520 elif raw.startswith('-'):
516 kv = '--'+item
521 kv = '--'+item
517 if kv_pattern.match(kv):
522 if kv_pattern.match(kv):
518 raise ArgumentError("Invalid argument: '%s', did you mean '%s'?"%(raw, kv))
523 raise ArgumentError("Invalid argument: '%s', did you mean '%s'?"%(raw, kv))
519 else:
524 else:
520 raise ArgumentError("Invalid argument: '%s'"%raw)
525 raise ArgumentError("Invalid argument: '%s'"%raw)
521 else:
526 else:
522 # keep all args that aren't valid in a list,
527 # keep all args that aren't valid in a list,
523 # in case our parent knows what to do with them.
528 # in case our parent knows what to do with them.
524 self.extra_args.append(item)
529 self.extra_args.append(item)
525 return self.config
530 return self.config
526
531
527 class ArgParseConfigLoader(CommandLineConfigLoader):
532 class ArgParseConfigLoader(CommandLineConfigLoader):
528 """A loader that uses the argparse module to load from the command line."""
533 """A loader that uses the argparse module to load from the command line."""
529
534
530 def __init__(self, argv=None, aliases=None, flags=None, *parser_args, **parser_kw):
535 def __init__(self, argv=None, aliases=None, flags=None, *parser_args, **parser_kw):
531 """Create a config loader for use with argparse.
536 """Create a config loader for use with argparse.
532
537
533 Parameters
538 Parameters
534 ----------
539 ----------
535
540
536 argv : optional, list
541 argv : optional, list
537 If given, used to read command-line arguments from, otherwise
542 If given, used to read command-line arguments from, otherwise
538 sys.argv[1:] is used.
543 sys.argv[1:] is used.
539
544
540 parser_args : tuple
545 parser_args : tuple
541 A tuple of positional arguments that will be passed to the
546 A tuple of positional arguments that will be passed to the
542 constructor of :class:`argparse.ArgumentParser`.
547 constructor of :class:`argparse.ArgumentParser`.
543
548
544 parser_kw : dict
549 parser_kw : dict
545 A tuple of keyword arguments that will be passed to the
550 A tuple of keyword arguments that will be passed to the
546 constructor of :class:`argparse.ArgumentParser`.
551 constructor of :class:`argparse.ArgumentParser`.
547
552
548 Returns
553 Returns
549 -------
554 -------
550 config : Config
555 config : Config
551 The resulting Config object.
556 The resulting Config object.
552 """
557 """
553 super(CommandLineConfigLoader, self).__init__()
558 super(CommandLineConfigLoader, self).__init__()
554 self.clear()
559 self.clear()
555 if argv is None:
560 if argv is None:
556 argv = sys.argv[1:]
561 argv = sys.argv[1:]
557 self.argv = argv
562 self.argv = argv
558 self.aliases = aliases or {}
563 self.aliases = aliases or {}
559 self.flags = flags or {}
564 self.flags = flags or {}
560
565
561 self.parser_args = parser_args
566 self.parser_args = parser_args
562 self.version = parser_kw.pop("version", None)
567 self.version = parser_kw.pop("version", None)
563 kwargs = dict(argument_default=argparse.SUPPRESS)
568 kwargs = dict(argument_default=argparse.SUPPRESS)
564 kwargs.update(parser_kw)
569 kwargs.update(parser_kw)
565 self.parser_kw = kwargs
570 self.parser_kw = kwargs
566
571
567 def load_config(self, argv=None, aliases=None, flags=None):
572 def load_config(self, argv=None, aliases=None, flags=None):
568 """Parse command line arguments and return as a Config object.
573 """Parse command line arguments and return as a Config object.
569
574
570 Parameters
575 Parameters
571 ----------
576 ----------
572
577
573 args : optional, list
578 args : optional, list
574 If given, a list with the structure of sys.argv[1:] to parse
579 If given, a list with the structure of sys.argv[1:] to parse
575 arguments from. If not given, the instance's self.argv attribute
580 arguments from. If not given, the instance's self.argv attribute
576 (given at construction time) is used."""
581 (given at construction time) is used."""
577 self.clear()
582 self.clear()
578 if argv is None:
583 if argv is None:
579 argv = self.argv
584 argv = self.argv
580 if aliases is None:
585 if aliases is None:
581 aliases = self.aliases
586 aliases = self.aliases
582 if flags is None:
587 if flags is None:
583 flags = self.flags
588 flags = self.flags
584 self._create_parser(aliases, flags)
589 self._create_parser(aliases, flags)
585 self._parse_args(argv)
590 self._parse_args(argv)
586 self._convert_to_config()
591 self._convert_to_config()
587 return self.config
592 return self.config
588
593
589 def get_extra_args(self):
594 def get_extra_args(self):
590 if hasattr(self, 'extra_args'):
595 if hasattr(self, 'extra_args'):
591 return self.extra_args
596 return self.extra_args
592 else:
597 else:
593 return []
598 return []
594
599
595 def _create_parser(self, aliases=None, flags=None):
600 def _create_parser(self, aliases=None, flags=None):
596 self.parser = ArgumentParser(*self.parser_args, **self.parser_kw)
601 self.parser = ArgumentParser(*self.parser_args, **self.parser_kw)
597 self._add_arguments(aliases, flags)
602 self._add_arguments(aliases, flags)
598
603
599 def _add_arguments(self, aliases=None, flags=None):
604 def _add_arguments(self, aliases=None, flags=None):
600 raise NotImplementedError("subclasses must implement _add_arguments")
605 raise NotImplementedError("subclasses must implement _add_arguments")
601
606
602 def _parse_args(self, args):
607 def _parse_args(self, args):
603 """self.parser->self.parsed_data"""
608 """self.parser->self.parsed_data"""
604 # decode sys.argv to support unicode command-line options
609 # decode sys.argv to support unicode command-line options
605 enc = DEFAULT_ENCODING
610 enc = DEFAULT_ENCODING
606 uargs = [py3compat.cast_unicode(a, enc) for a in args]
611 uargs = [py3compat.cast_unicode(a, enc) for a in args]
607 self.parsed_data, self.extra_args = self.parser.parse_known_args(uargs)
612 self.parsed_data, self.extra_args = self.parser.parse_known_args(uargs)
608
613
609 def _convert_to_config(self):
614 def _convert_to_config(self):
610 """self.parsed_data->self.config"""
615 """self.parsed_data->self.config"""
611 for k, v in vars(self.parsed_data).iteritems():
616 for k, v in vars(self.parsed_data).iteritems():
612 exec "self.config.%s = v"%k in locals(), globals()
617 exec "self.config.%s = v"%k in locals(), globals()
613
618
614 class KVArgParseConfigLoader(ArgParseConfigLoader):
619 class KVArgParseConfigLoader(ArgParseConfigLoader):
615 """A config loader that loads aliases and flags with argparse,
620 """A config loader that loads aliases and flags with argparse,
616 but will use KVLoader for the rest. This allows better parsing
621 but will use KVLoader for the rest. This allows better parsing
617 of common args, such as `ipython -c 'print 5'`, but still gets
622 of common args, such as `ipython -c 'print 5'`, but still gets
618 arbitrary config with `ipython --InteractiveShell.use_readline=False`"""
623 arbitrary config with `ipython --InteractiveShell.use_readline=False`"""
619
624
620 def _add_arguments(self, aliases=None, flags=None):
625 def _add_arguments(self, aliases=None, flags=None):
621 self.alias_flags = {}
626 self.alias_flags = {}
622 # print aliases, flags
627 # print aliases, flags
623 if aliases is None:
628 if aliases is None:
624 aliases = self.aliases
629 aliases = self.aliases
625 if flags is None:
630 if flags is None:
626 flags = self.flags
631 flags = self.flags
627 paa = self.parser.add_argument
632 paa = self.parser.add_argument
628 for key,value in aliases.iteritems():
633 for key,value in aliases.iteritems():
629 if key in flags:
634 if key in flags:
630 # flags
635 # flags
631 nargs = '?'
636 nargs = '?'
632 else:
637 else:
633 nargs = None
638 nargs = None
634 if len(key) is 1:
639 if len(key) is 1:
635 paa('-'+key, '--'+key, type=unicode, dest=value, nargs=nargs)
640 paa('-'+key, '--'+key, type=unicode, dest=value, nargs=nargs)
636 else:
641 else:
637 paa('--'+key, type=unicode, dest=value, nargs=nargs)
642 paa('--'+key, type=unicode, dest=value, nargs=nargs)
638 for key, (value, help) in flags.iteritems():
643 for key, (value, help) in flags.iteritems():
639 if key in self.aliases:
644 if key in self.aliases:
640 #
645 #
641 self.alias_flags[self.aliases[key]] = value
646 self.alias_flags[self.aliases[key]] = value
642 continue
647 continue
643 if len(key) is 1:
648 if len(key) is 1:
644 paa('-'+key, '--'+key, action='append_const', dest='_flags', const=value)
649 paa('-'+key, '--'+key, action='append_const', dest='_flags', const=value)
645 else:
650 else:
646 paa('--'+key, action='append_const', dest='_flags', const=value)
651 paa('--'+key, action='append_const', dest='_flags', const=value)
647
652
648 def _convert_to_config(self):
653 def _convert_to_config(self):
649 """self.parsed_data->self.config, parse unrecognized extra args via KVLoader."""
654 """self.parsed_data->self.config, parse unrecognized extra args via KVLoader."""
650 # remove subconfigs list from namespace before transforming the Namespace
655 # remove subconfigs list from namespace before transforming the Namespace
651 if '_flags' in self.parsed_data:
656 if '_flags' in self.parsed_data:
652 subcs = self.parsed_data._flags
657 subcs = self.parsed_data._flags
653 del self.parsed_data._flags
658 del self.parsed_data._flags
654 else:
659 else:
655 subcs = []
660 subcs = []
656
661
657 for k, v in vars(self.parsed_data).iteritems():
662 for k, v in vars(self.parsed_data).iteritems():
658 if v is None:
663 if v is None:
659 # it was a flag that shares the name of an alias
664 # it was a flag that shares the name of an alias
660 subcs.append(self.alias_flags[k])
665 subcs.append(self.alias_flags[k])
661 else:
666 else:
662 # eval the KV assignment
667 # eval the KV assignment
663 self._exec_config_str(k, v)
668 self._exec_config_str(k, v)
664
669
665 for subc in subcs:
670 for subc in subcs:
666 self._load_flag(subc)
671 self._load_flag(subc)
667
672
668 if self.extra_args:
673 if self.extra_args:
669 sub_parser = KeyValueConfigLoader()
674 sub_parser = KeyValueConfigLoader()
670 sub_parser.load_config(self.extra_args)
675 sub_parser.load_config(self.extra_args)
671 self.config._merge(sub_parser.config)
676 self.config._merge(sub_parser.config)
672 self.extra_args = sub_parser.extra_args
677 self.extra_args = sub_parser.extra_args
673
678
674
679
675 def load_pyconfig_files(config_files, path):
680 def load_pyconfig_files(config_files, path):
676 """Load multiple Python config files, merging each of them in turn.
681 """Load multiple Python config files, merging each of them in turn.
677
682
678 Parameters
683 Parameters
679 ==========
684 ==========
680 config_files : list of str
685 config_files : list of str
681 List of config files names to load and merge into the config.
686 List of config files names to load and merge into the config.
682 path : unicode
687 path : unicode
683 The full path to the location of the config files.
688 The full path to the location of the config files.
684 """
689 """
685 config = Config()
690 config = Config()
686 for cf in config_files:
691 for cf in config_files:
687 loader = PyFileConfigLoader(cf, path=path)
692 loader = PyFileConfigLoader(cf, path=path)
688 try:
693 try:
689 next_config = loader.load_config()
694 next_config = loader.load_config()
690 except ConfigFileNotFound:
695 except ConfigFileNotFound:
691 pass
696 pass
692 except:
697 except:
693 raise
698 raise
694 else:
699 else:
695 config._merge(next_config)
700 config._merge(next_config)
696 return config
701 return config
@@ -1,621 +1,625 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Display formatters.
2 """Display formatters.
3
3
4 Inheritance diagram:
5
6 .. inheritance-diagram:: IPython.core.formatters
7 :parts: 3
4
8
5 Authors:
9 Authors:
6
10
7 * Robert Kern
11 * Robert Kern
8 * Brian Granger
12 * Brian Granger
9 """
13 """
10 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
11 # Copyright (C) 2010-2011, IPython Development Team.
15 # Copyright (C) 2010-2011, IPython Development Team.
12 #
16 #
13 # Distributed under the terms of the Modified BSD License.
17 # Distributed under the terms of the Modified BSD License.
14 #
18 #
15 # The full license is in the file COPYING.txt, distributed with this software.
19 # The full license is in the file COPYING.txt, distributed with this software.
16 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
17
21
18 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
19 # Imports
23 # Imports
20 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
21
25
22 # Stdlib imports
26 # Stdlib imports
23 import abc
27 import abc
24 import sys
28 import sys
25 # We must use StringIO, as cStringIO doesn't handle unicode properly.
29 # We must use StringIO, as cStringIO doesn't handle unicode properly.
26 from StringIO import StringIO
30 from StringIO import StringIO
27
31
28 # Our own imports
32 # Our own imports
29 from IPython.config.configurable import Configurable
33 from IPython.config.configurable import Configurable
30 from IPython.lib import pretty
34 from IPython.lib import pretty
31 from IPython.utils.traitlets import Bool, Dict, Integer, Unicode, CUnicode, ObjectName
35 from IPython.utils.traitlets import Bool, Dict, Integer, Unicode, CUnicode, ObjectName
32 from IPython.utils.py3compat import unicode_to_str
36 from IPython.utils.py3compat import unicode_to_str
33
37
34
38
35 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
36 # The main DisplayFormatter class
40 # The main DisplayFormatter class
37 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
38
42
39
43
40 class DisplayFormatter(Configurable):
44 class DisplayFormatter(Configurable):
41
45
42 # When set to true only the default plain text formatter will be used.
46 # When set to true only the default plain text formatter will be used.
43 plain_text_only = Bool(False, config=True)
47 plain_text_only = Bool(False, config=True)
44
48
45 # A dict of formatter whose keys are format types (MIME types) and whose
49 # A dict of formatter whose keys are format types (MIME types) and whose
46 # values are subclasses of BaseFormatter.
50 # values are subclasses of BaseFormatter.
47 formatters = Dict()
51 formatters = Dict()
48 def _formatters_default(self):
52 def _formatters_default(self):
49 """Activate the default formatters."""
53 """Activate the default formatters."""
50 formatter_classes = [
54 formatter_classes = [
51 PlainTextFormatter,
55 PlainTextFormatter,
52 HTMLFormatter,
56 HTMLFormatter,
53 SVGFormatter,
57 SVGFormatter,
54 PNGFormatter,
58 PNGFormatter,
55 JPEGFormatter,
59 JPEGFormatter,
56 LatexFormatter,
60 LatexFormatter,
57 JSONFormatter,
61 JSONFormatter,
58 JavascriptFormatter
62 JavascriptFormatter
59 ]
63 ]
60 d = {}
64 d = {}
61 for cls in formatter_classes:
65 for cls in formatter_classes:
62 f = cls(config=self.config)
66 f = cls(config=self.config)
63 d[f.format_type] = f
67 d[f.format_type] = f
64 return d
68 return d
65
69
66 def format(self, obj, include=None, exclude=None):
70 def format(self, obj, include=None, exclude=None):
67 """Return a format data dict for an object.
71 """Return a format data dict for an object.
68
72
69 By default all format types will be computed.
73 By default all format types will be computed.
70
74
71 The following MIME types are currently implemented:
75 The following MIME types are currently implemented:
72
76
73 * text/plain
77 * text/plain
74 * text/html
78 * text/html
75 * text/latex
79 * text/latex
76 * application/json
80 * application/json
77 * application/javascript
81 * application/javascript
78 * image/png
82 * image/png
79 * image/jpeg
83 * image/jpeg
80 * image/svg+xml
84 * image/svg+xml
81
85
82 Parameters
86 Parameters
83 ----------
87 ----------
84 obj : object
88 obj : object
85 The Python object whose format data will be computed.
89 The Python object whose format data will be computed.
86 include : list or tuple, optional
90 include : list or tuple, optional
87 A list of format type strings (MIME types) to include in the
91 A list of format type strings (MIME types) to include in the
88 format data dict. If this is set *only* the format types included
92 format data dict. If this is set *only* the format types included
89 in this list will be computed.
93 in this list will be computed.
90 exclude : list or tuple, optional
94 exclude : list or tuple, optional
91 A list of format type string (MIME types) to exclue in the format
95 A list of format type string (MIME types) to exclue in the format
92 data dict. If this is set all format types will be computed,
96 data dict. If this is set all format types will be computed,
93 except for those included in this argument.
97 except for those included in this argument.
94
98
95 Returns
99 Returns
96 -------
100 -------
97 format_dict : dict
101 format_dict : dict
98 A dictionary of key/value pairs, one or each format that was
102 A dictionary of key/value pairs, one or each format that was
99 generated for the object. The keys are the format types, which
103 generated for the object. The keys are the format types, which
100 will usually be MIME type strings and the values and JSON'able
104 will usually be MIME type strings and the values and JSON'able
101 data structure containing the raw data for the representation in
105 data structure containing the raw data for the representation in
102 that format.
106 that format.
103 """
107 """
104 format_dict = {}
108 format_dict = {}
105
109
106 # If plain text only is active
110 # If plain text only is active
107 if self.plain_text_only:
111 if self.plain_text_only:
108 formatter = self.formatters['text/plain']
112 formatter = self.formatters['text/plain']
109 try:
113 try:
110 data = formatter(obj)
114 data = formatter(obj)
111 except:
115 except:
112 # FIXME: log the exception
116 # FIXME: log the exception
113 raise
117 raise
114 if data is not None:
118 if data is not None:
115 format_dict['text/plain'] = data
119 format_dict['text/plain'] = data
116 return format_dict
120 return format_dict
117
121
118 for format_type, formatter in self.formatters.items():
122 for format_type, formatter in self.formatters.items():
119 if include is not None:
123 if include is not None:
120 if format_type not in include:
124 if format_type not in include:
121 continue
125 continue
122 if exclude is not None:
126 if exclude is not None:
123 if format_type in exclude:
127 if format_type in exclude:
124 continue
128 continue
125 try:
129 try:
126 data = formatter(obj)
130 data = formatter(obj)
127 except:
131 except:
128 # FIXME: log the exception
132 # FIXME: log the exception
129 raise
133 raise
130 if data is not None:
134 if data is not None:
131 format_dict[format_type] = data
135 format_dict[format_type] = data
132 return format_dict
136 return format_dict
133
137
134 @property
138 @property
135 def format_types(self):
139 def format_types(self):
136 """Return the format types (MIME types) of the active formatters."""
140 """Return the format types (MIME types) of the active formatters."""
137 return self.formatters.keys()
141 return self.formatters.keys()
138
142
139
143
140 #-----------------------------------------------------------------------------
144 #-----------------------------------------------------------------------------
141 # Formatters for specific format types (text, html, svg, etc.)
145 # Formatters for specific format types (text, html, svg, etc.)
142 #-----------------------------------------------------------------------------
146 #-----------------------------------------------------------------------------
143
147
144
148
145 class FormatterABC(object):
149 class FormatterABC(object):
146 """ Abstract base class for Formatters.
150 """ Abstract base class for Formatters.
147
151
148 A formatter is a callable class that is responsible for computing the
152 A formatter is a callable class that is responsible for computing the
149 raw format data for a particular format type (MIME type). For example,
153 raw format data for a particular format type (MIME type). For example,
150 an HTML formatter would have a format type of `text/html` and would return
154 an HTML formatter would have a format type of `text/html` and would return
151 the HTML representation of the object when called.
155 the HTML representation of the object when called.
152 """
156 """
153 __metaclass__ = abc.ABCMeta
157 __metaclass__ = abc.ABCMeta
154
158
155 # The format type of the data returned, usually a MIME type.
159 # The format type of the data returned, usually a MIME type.
156 format_type = 'text/plain'
160 format_type = 'text/plain'
157
161
158 # Is the formatter enabled...
162 # Is the formatter enabled...
159 enabled = True
163 enabled = True
160
164
161 @abc.abstractmethod
165 @abc.abstractmethod
162 def __call__(self, obj):
166 def __call__(self, obj):
163 """Return a JSON'able representation of the object.
167 """Return a JSON'able representation of the object.
164
168
165 If the object cannot be formatted by this formatter, then return None
169 If the object cannot be formatted by this formatter, then return None
166 """
170 """
167 try:
171 try:
168 return repr(obj)
172 return repr(obj)
169 except TypeError:
173 except TypeError:
170 return None
174 return None
171
175
172
176
173 class BaseFormatter(Configurable):
177 class BaseFormatter(Configurable):
174 """A base formatter class that is configurable.
178 """A base formatter class that is configurable.
175
179
176 This formatter should usually be used as the base class of all formatters.
180 This formatter should usually be used as the base class of all formatters.
177 It is a traited :class:`Configurable` class and includes an extensible
181 It is a traited :class:`Configurable` class and includes an extensible
178 API for users to determine how their objects are formatted. The following
182 API for users to determine how their objects are formatted. The following
179 logic is used to find a function to format an given object.
183 logic is used to find a function to format an given object.
180
184
181 1. The object is introspected to see if it has a method with the name
185 1. The object is introspected to see if it has a method with the name
182 :attr:`print_method`. If is does, that object is passed to that method
186 :attr:`print_method`. If is does, that object is passed to that method
183 for formatting.
187 for formatting.
184 2. If no print method is found, three internal dictionaries are consulted
188 2. If no print method is found, three internal dictionaries are consulted
185 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
189 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
186 and :attr:`deferred_printers`.
190 and :attr:`deferred_printers`.
187
191
188 Users should use these dictionaries to register functions that will be
192 Users should use these dictionaries to register functions that will be
189 used to compute the format data for their objects (if those objects don't
193 used to compute the format data for their objects (if those objects don't
190 have the special print methods). The easiest way of using these
194 have the special print methods). The easiest way of using these
191 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
195 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
192 methods.
196 methods.
193
197
194 If no function/callable is found to compute the format data, ``None`` is
198 If no function/callable is found to compute the format data, ``None`` is
195 returned and this format type is not used.
199 returned and this format type is not used.
196 """
200 """
197
201
198 format_type = Unicode('text/plain')
202 format_type = Unicode('text/plain')
199
203
200 enabled = Bool(True, config=True)
204 enabled = Bool(True, config=True)
201
205
202 print_method = ObjectName('__repr__')
206 print_method = ObjectName('__repr__')
203
207
204 # The singleton printers.
208 # The singleton printers.
205 # Maps the IDs of the builtin singleton objects to the format functions.
209 # Maps the IDs of the builtin singleton objects to the format functions.
206 singleton_printers = Dict(config=True)
210 singleton_printers = Dict(config=True)
207 def _singleton_printers_default(self):
211 def _singleton_printers_default(self):
208 return {}
212 return {}
209
213
210 # The type-specific printers.
214 # The type-specific printers.
211 # Map type objects to the format functions.
215 # Map type objects to the format functions.
212 type_printers = Dict(config=True)
216 type_printers = Dict(config=True)
213 def _type_printers_default(self):
217 def _type_printers_default(self):
214 return {}
218 return {}
215
219
216 # The deferred-import type-specific printers.
220 # The deferred-import type-specific printers.
217 # Map (modulename, classname) pairs to the format functions.
221 # Map (modulename, classname) pairs to the format functions.
218 deferred_printers = Dict(config=True)
222 deferred_printers = Dict(config=True)
219 def _deferred_printers_default(self):
223 def _deferred_printers_default(self):
220 return {}
224 return {}
221
225
222 def __call__(self, obj):
226 def __call__(self, obj):
223 """Compute the format for an object."""
227 """Compute the format for an object."""
224 if self.enabled:
228 if self.enabled:
225 obj_id = id(obj)
229 obj_id = id(obj)
226 try:
230 try:
227 obj_class = getattr(obj, '__class__', None) or type(obj)
231 obj_class = getattr(obj, '__class__', None) or type(obj)
228 # First try to find registered singleton printers for the type.
232 # First try to find registered singleton printers for the type.
229 try:
233 try:
230 printer = self.singleton_printers[obj_id]
234 printer = self.singleton_printers[obj_id]
231 except (TypeError, KeyError):
235 except (TypeError, KeyError):
232 pass
236 pass
233 else:
237 else:
234 return printer(obj)
238 return printer(obj)
235 # Next look for type_printers.
239 # Next look for type_printers.
236 for cls in pretty._get_mro(obj_class):
240 for cls in pretty._get_mro(obj_class):
237 if cls in self.type_printers:
241 if cls in self.type_printers:
238 return self.type_printers[cls](obj)
242 return self.type_printers[cls](obj)
239 else:
243 else:
240 printer = self._in_deferred_types(cls)
244 printer = self._in_deferred_types(cls)
241 if printer is not None:
245 if printer is not None:
242 return printer(obj)
246 return printer(obj)
243 # Finally look for special method names.
247 # Finally look for special method names.
244 if hasattr(obj_class, self.print_method):
248 if hasattr(obj_class, self.print_method):
245 printer = getattr(obj_class, self.print_method)
249 printer = getattr(obj_class, self.print_method)
246 return printer(obj)
250 return printer(obj)
247 return None
251 return None
248 except Exception:
252 except Exception:
249 pass
253 pass
250 else:
254 else:
251 return None
255 return None
252
256
253 def for_type(self, typ, func):
257 def for_type(self, typ, func):
254 """Add a format function for a given type.
258 """Add a format function for a given type.
255
259
256 Parameters
260 Parameters
257 -----------
261 -----------
258 typ : class
262 typ : class
259 The class of the object that will be formatted using `func`.
263 The class of the object that will be formatted using `func`.
260 func : callable
264 func : callable
261 The callable that will be called to compute the format data. The
265 The callable that will be called to compute the format data. The
262 call signature of this function is simple, it must take the
266 call signature of this function is simple, it must take the
263 object to be formatted and return the raw data for the given
267 object to be formatted and return the raw data for the given
264 format. Subclasses may use a different call signature for the
268 format. Subclasses may use a different call signature for the
265 `func` argument.
269 `func` argument.
266 """
270 """
267 oldfunc = self.type_printers.get(typ, None)
271 oldfunc = self.type_printers.get(typ, None)
268 if func is not None:
272 if func is not None:
269 # To support easy restoration of old printers, we need to ignore
273 # To support easy restoration of old printers, we need to ignore
270 # Nones.
274 # Nones.
271 self.type_printers[typ] = func
275 self.type_printers[typ] = func
272 return oldfunc
276 return oldfunc
273
277
274 def for_type_by_name(self, type_module, type_name, func):
278 def for_type_by_name(self, type_module, type_name, func):
275 """Add a format function for a type specified by the full dotted
279 """Add a format function for a type specified by the full dotted
276 module and name of the type, rather than the type of the object.
280 module and name of the type, rather than the type of the object.
277
281
278 Parameters
282 Parameters
279 ----------
283 ----------
280 type_module : str
284 type_module : str
281 The full dotted name of the module the type is defined in, like
285 The full dotted name of the module the type is defined in, like
282 ``numpy``.
286 ``numpy``.
283 type_name : str
287 type_name : str
284 The name of the type (the class name), like ``dtype``
288 The name of the type (the class name), like ``dtype``
285 func : callable
289 func : callable
286 The callable that will be called to compute the format data. The
290 The callable that will be called to compute the format data. The
287 call signature of this function is simple, it must take the
291 call signature of this function is simple, it must take the
288 object to be formatted and return the raw data for the given
292 object to be formatted and return the raw data for the given
289 format. Subclasses may use a different call signature for the
293 format. Subclasses may use a different call signature for the
290 `func` argument.
294 `func` argument.
291 """
295 """
292 key = (type_module, type_name)
296 key = (type_module, type_name)
293 oldfunc = self.deferred_printers.get(key, None)
297 oldfunc = self.deferred_printers.get(key, None)
294 if func is not None:
298 if func is not None:
295 # To support easy restoration of old printers, we need to ignore
299 # To support easy restoration of old printers, we need to ignore
296 # Nones.
300 # Nones.
297 self.deferred_printers[key] = func
301 self.deferred_printers[key] = func
298 return oldfunc
302 return oldfunc
299
303
300 def _in_deferred_types(self, cls):
304 def _in_deferred_types(self, cls):
301 """
305 """
302 Check if the given class is specified in the deferred type registry.
306 Check if the given class is specified in the deferred type registry.
303
307
304 Returns the printer from the registry if it exists, and None if the
308 Returns the printer from the registry if it exists, and None if the
305 class is not in the registry. Successful matches will be moved to the
309 class is not in the registry. Successful matches will be moved to the
306 regular type registry for future use.
310 regular type registry for future use.
307 """
311 """
308 mod = getattr(cls, '__module__', None)
312 mod = getattr(cls, '__module__', None)
309 name = getattr(cls, '__name__', None)
313 name = getattr(cls, '__name__', None)
310 key = (mod, name)
314 key = (mod, name)
311 printer = None
315 printer = None
312 if key in self.deferred_printers:
316 if key in self.deferred_printers:
313 # Move the printer over to the regular registry.
317 # Move the printer over to the regular registry.
314 printer = self.deferred_printers.pop(key)
318 printer = self.deferred_printers.pop(key)
315 self.type_printers[cls] = printer
319 self.type_printers[cls] = printer
316 return printer
320 return printer
317
321
318
322
319 class PlainTextFormatter(BaseFormatter):
323 class PlainTextFormatter(BaseFormatter):
320 """The default pretty-printer.
324 """The default pretty-printer.
321
325
322 This uses :mod:`IPython.lib.pretty` to compute the format data of
326 This uses :mod:`IPython.lib.pretty` to compute the format data of
323 the object. If the object cannot be pretty printed, :func:`repr` is used.
327 the object. If the object cannot be pretty printed, :func:`repr` is used.
324 See the documentation of :mod:`IPython.lib.pretty` for details on
328 See the documentation of :mod:`IPython.lib.pretty` for details on
325 how to write pretty printers. Here is a simple example::
329 how to write pretty printers. Here is a simple example::
326
330
327 def dtype_pprinter(obj, p, cycle):
331 def dtype_pprinter(obj, p, cycle):
328 if cycle:
332 if cycle:
329 return p.text('dtype(...)')
333 return p.text('dtype(...)')
330 if hasattr(obj, 'fields'):
334 if hasattr(obj, 'fields'):
331 if obj.fields is None:
335 if obj.fields is None:
332 p.text(repr(obj))
336 p.text(repr(obj))
333 else:
337 else:
334 p.begin_group(7, 'dtype([')
338 p.begin_group(7, 'dtype([')
335 for i, field in enumerate(obj.descr):
339 for i, field in enumerate(obj.descr):
336 if i > 0:
340 if i > 0:
337 p.text(',')
341 p.text(',')
338 p.breakable()
342 p.breakable()
339 p.pretty(field)
343 p.pretty(field)
340 p.end_group(7, '])')
344 p.end_group(7, '])')
341 """
345 """
342
346
343 # The format type of data returned.
347 # The format type of data returned.
344 format_type = Unicode('text/plain')
348 format_type = Unicode('text/plain')
345
349
346 # This subclass ignores this attribute as it always need to return
350 # This subclass ignores this attribute as it always need to return
347 # something.
351 # something.
348 enabled = Bool(True, config=False)
352 enabled = Bool(True, config=False)
349
353
350 # Look for a _repr_pretty_ methods to use for pretty printing.
354 # Look for a _repr_pretty_ methods to use for pretty printing.
351 print_method = ObjectName('_repr_pretty_')
355 print_method = ObjectName('_repr_pretty_')
352
356
353 # Whether to pretty-print or not.
357 # Whether to pretty-print or not.
354 pprint = Bool(True, config=True)
358 pprint = Bool(True, config=True)
355
359
356 # Whether to be verbose or not.
360 # Whether to be verbose or not.
357 verbose = Bool(False, config=True)
361 verbose = Bool(False, config=True)
358
362
359 # The maximum width.
363 # The maximum width.
360 max_width = Integer(79, config=True)
364 max_width = Integer(79, config=True)
361
365
362 # The newline character.
366 # The newline character.
363 newline = Unicode('\n', config=True)
367 newline = Unicode('\n', config=True)
364
368
365 # format-string for pprinting floats
369 # format-string for pprinting floats
366 float_format = Unicode('%r')
370 float_format = Unicode('%r')
367 # setter for float precision, either int or direct format-string
371 # setter for float precision, either int or direct format-string
368 float_precision = CUnicode('', config=True)
372 float_precision = CUnicode('', config=True)
369
373
370 def _float_precision_changed(self, name, old, new):
374 def _float_precision_changed(self, name, old, new):
371 """float_precision changed, set float_format accordingly.
375 """float_precision changed, set float_format accordingly.
372
376
373 float_precision can be set by int or str.
377 float_precision can be set by int or str.
374 This will set float_format, after interpreting input.
378 This will set float_format, after interpreting input.
375 If numpy has been imported, numpy print precision will also be set.
379 If numpy has been imported, numpy print precision will also be set.
376
380
377 integer `n` sets format to '%.nf', otherwise, format set directly.
381 integer `n` sets format to '%.nf', otherwise, format set directly.
378
382
379 An empty string returns to defaults (repr for float, 8 for numpy).
383 An empty string returns to defaults (repr for float, 8 for numpy).
380
384
381 This parameter can be set via the '%precision' magic.
385 This parameter can be set via the '%precision' magic.
382 """
386 """
383
387
384 if '%' in new:
388 if '%' in new:
385 # got explicit format string
389 # got explicit format string
386 fmt = new
390 fmt = new
387 try:
391 try:
388 fmt%3.14159
392 fmt%3.14159
389 except Exception:
393 except Exception:
390 raise ValueError("Precision must be int or format string, not %r"%new)
394 raise ValueError("Precision must be int or format string, not %r"%new)
391 elif new:
395 elif new:
392 # otherwise, should be an int
396 # otherwise, should be an int
393 try:
397 try:
394 i = int(new)
398 i = int(new)
395 assert i >= 0
399 assert i >= 0
396 except ValueError:
400 except ValueError:
397 raise ValueError("Precision must be int or format string, not %r"%new)
401 raise ValueError("Precision must be int or format string, not %r"%new)
398 except AssertionError:
402 except AssertionError:
399 raise ValueError("int precision must be non-negative, not %r"%i)
403 raise ValueError("int precision must be non-negative, not %r"%i)
400
404
401 fmt = '%%.%if'%i
405 fmt = '%%.%if'%i
402 if 'numpy' in sys.modules:
406 if 'numpy' in sys.modules:
403 # set numpy precision if it has been imported
407 # set numpy precision if it has been imported
404 import numpy
408 import numpy
405 numpy.set_printoptions(precision=i)
409 numpy.set_printoptions(precision=i)
406 else:
410 else:
407 # default back to repr
411 # default back to repr
408 fmt = '%r'
412 fmt = '%r'
409 if 'numpy' in sys.modules:
413 if 'numpy' in sys.modules:
410 import numpy
414 import numpy
411 # numpy default is 8
415 # numpy default is 8
412 numpy.set_printoptions(precision=8)
416 numpy.set_printoptions(precision=8)
413 self.float_format = fmt
417 self.float_format = fmt
414
418
415 # Use the default pretty printers from IPython.lib.pretty.
419 # Use the default pretty printers from IPython.lib.pretty.
416 def _singleton_printers_default(self):
420 def _singleton_printers_default(self):
417 return pretty._singleton_pprinters.copy()
421 return pretty._singleton_pprinters.copy()
418
422
419 def _type_printers_default(self):
423 def _type_printers_default(self):
420 d = pretty._type_pprinters.copy()
424 d = pretty._type_pprinters.copy()
421 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
425 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
422 return d
426 return d
423
427
424 def _deferred_printers_default(self):
428 def _deferred_printers_default(self):
425 return pretty._deferred_type_pprinters.copy()
429 return pretty._deferred_type_pprinters.copy()
426
430
427 #### FormatterABC interface ####
431 #### FormatterABC interface ####
428
432
429 def __call__(self, obj):
433 def __call__(self, obj):
430 """Compute the pretty representation of the object."""
434 """Compute the pretty representation of the object."""
431 if not self.pprint:
435 if not self.pprint:
432 try:
436 try:
433 return repr(obj)
437 return repr(obj)
434 except TypeError:
438 except TypeError:
435 return ''
439 return ''
436 else:
440 else:
437 # This uses use StringIO, as cStringIO doesn't handle unicode.
441 # This uses use StringIO, as cStringIO doesn't handle unicode.
438 stream = StringIO()
442 stream = StringIO()
439 # self.newline.encode() is a quick fix for issue gh-597. We need to
443 # self.newline.encode() is a quick fix for issue gh-597. We need to
440 # ensure that stream does not get a mix of unicode and bytestrings,
444 # ensure that stream does not get a mix of unicode and bytestrings,
441 # or it will cause trouble.
445 # or it will cause trouble.
442 printer = pretty.RepresentationPrinter(stream, self.verbose,
446 printer = pretty.RepresentationPrinter(stream, self.verbose,
443 self.max_width, unicode_to_str(self.newline),
447 self.max_width, unicode_to_str(self.newline),
444 singleton_pprinters=self.singleton_printers,
448 singleton_pprinters=self.singleton_printers,
445 type_pprinters=self.type_printers,
449 type_pprinters=self.type_printers,
446 deferred_pprinters=self.deferred_printers)
450 deferred_pprinters=self.deferred_printers)
447 printer.pretty(obj)
451 printer.pretty(obj)
448 printer.flush()
452 printer.flush()
449 return stream.getvalue()
453 return stream.getvalue()
450
454
451
455
452 class HTMLFormatter(BaseFormatter):
456 class HTMLFormatter(BaseFormatter):
453 """An HTML formatter.
457 """An HTML formatter.
454
458
455 To define the callables that compute the HTML representation of your
459 To define the callables that compute the HTML representation of your
456 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
460 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
457 or :meth:`for_type_by_name` methods to register functions that handle
461 or :meth:`for_type_by_name` methods to register functions that handle
458 this.
462 this.
459
463
460 The return value of this formatter should be a valid HTML snippet that
464 The return value of this formatter should be a valid HTML snippet that
461 could be injected into an existing DOM. It should *not* include the
465 could be injected into an existing DOM. It should *not* include the
462 ```<html>`` or ```<body>`` tags.
466 ```<html>`` or ```<body>`` tags.
463 """
467 """
464 format_type = Unicode('text/html')
468 format_type = Unicode('text/html')
465
469
466 print_method = ObjectName('_repr_html_')
470 print_method = ObjectName('_repr_html_')
467
471
468
472
469 class SVGFormatter(BaseFormatter):
473 class SVGFormatter(BaseFormatter):
470 """An SVG formatter.
474 """An SVG formatter.
471
475
472 To define the callables that compute the SVG representation of your
476 To define the callables that compute the SVG representation of your
473 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
477 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
474 or :meth:`for_type_by_name` methods to register functions that handle
478 or :meth:`for_type_by_name` methods to register functions that handle
475 this.
479 this.
476
480
477 The return value of this formatter should be valid SVG enclosed in
481 The return value of this formatter should be valid SVG enclosed in
478 ```<svg>``` tags, that could be injected into an existing DOM. It should
482 ```<svg>``` tags, that could be injected into an existing DOM. It should
479 *not* include the ```<html>`` or ```<body>`` tags.
483 *not* include the ```<html>`` or ```<body>`` tags.
480 """
484 """
481 format_type = Unicode('image/svg+xml')
485 format_type = Unicode('image/svg+xml')
482
486
483 print_method = ObjectName('_repr_svg_')
487 print_method = ObjectName('_repr_svg_')
484
488
485
489
486 class PNGFormatter(BaseFormatter):
490 class PNGFormatter(BaseFormatter):
487 """A PNG formatter.
491 """A PNG formatter.
488
492
489 To define the callables that compute the PNG representation of your
493 To define the callables that compute the PNG representation of your
490 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
494 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
491 or :meth:`for_type_by_name` methods to register functions that handle
495 or :meth:`for_type_by_name` methods to register functions that handle
492 this.
496 this.
493
497
494 The return value of this formatter should be raw PNG data, *not*
498 The return value of this formatter should be raw PNG data, *not*
495 base64 encoded.
499 base64 encoded.
496 """
500 """
497 format_type = Unicode('image/png')
501 format_type = Unicode('image/png')
498
502
499 print_method = ObjectName('_repr_png_')
503 print_method = ObjectName('_repr_png_')
500
504
501
505
502 class JPEGFormatter(BaseFormatter):
506 class JPEGFormatter(BaseFormatter):
503 """A JPEG formatter.
507 """A JPEG formatter.
504
508
505 To define the callables that compute the JPEG representation of your
509 To define the callables that compute the JPEG representation of your
506 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
510 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
507 or :meth:`for_type_by_name` methods to register functions that handle
511 or :meth:`for_type_by_name` methods to register functions that handle
508 this.
512 this.
509
513
510 The return value of this formatter should be raw JPEG data, *not*
514 The return value of this formatter should be raw JPEG data, *not*
511 base64 encoded.
515 base64 encoded.
512 """
516 """
513 format_type = Unicode('image/jpeg')
517 format_type = Unicode('image/jpeg')
514
518
515 print_method = ObjectName('_repr_jpeg_')
519 print_method = ObjectName('_repr_jpeg_')
516
520
517
521
518 class LatexFormatter(BaseFormatter):
522 class LatexFormatter(BaseFormatter):
519 """A LaTeX formatter.
523 """A LaTeX formatter.
520
524
521 To define the callables that compute the LaTeX representation of your
525 To define the callables that compute the LaTeX representation of your
522 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
526 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
523 or :meth:`for_type_by_name` methods to register functions that handle
527 or :meth:`for_type_by_name` methods to register functions that handle
524 this.
528 this.
525
529
526 The return value of this formatter should be a valid LaTeX equation,
530 The return value of this formatter should be a valid LaTeX equation,
527 enclosed in either ```$```, ```$$``` or another LaTeX equation
531 enclosed in either ```$```, ```$$``` or another LaTeX equation
528 environment.
532 environment.
529 """
533 """
530 format_type = Unicode('text/latex')
534 format_type = Unicode('text/latex')
531
535
532 print_method = ObjectName('_repr_latex_')
536 print_method = ObjectName('_repr_latex_')
533
537
534
538
535 class JSONFormatter(BaseFormatter):
539 class JSONFormatter(BaseFormatter):
536 """A JSON string formatter.
540 """A JSON string formatter.
537
541
538 To define the callables that compute the JSON string representation of
542 To define the callables that compute the JSON string representation of
539 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
543 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
540 or :meth:`for_type_by_name` methods to register functions that handle
544 or :meth:`for_type_by_name` methods to register functions that handle
541 this.
545 this.
542
546
543 The return value of this formatter should be a valid JSON string.
547 The return value of this formatter should be a valid JSON string.
544 """
548 """
545 format_type = Unicode('application/json')
549 format_type = Unicode('application/json')
546
550
547 print_method = ObjectName('_repr_json_')
551 print_method = ObjectName('_repr_json_')
548
552
549
553
550 class JavascriptFormatter(BaseFormatter):
554 class JavascriptFormatter(BaseFormatter):
551 """A Javascript formatter.
555 """A Javascript formatter.
552
556
553 To define the callables that compute the Javascript representation of
557 To define the callables that compute the Javascript representation of
554 your objects, define a :meth:`_repr_javascript_` method or use the
558 your objects, define a :meth:`_repr_javascript_` method or use the
555 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
559 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
556 that handle this.
560 that handle this.
557
561
558 The return value of this formatter should be valid Javascript code and
562 The return value of this formatter should be valid Javascript code and
559 should *not* be enclosed in ```<script>``` tags.
563 should *not* be enclosed in ```<script>``` tags.
560 """
564 """
561 format_type = Unicode('application/javascript')
565 format_type = Unicode('application/javascript')
562
566
563 print_method = ObjectName('_repr_javascript_')
567 print_method = ObjectName('_repr_javascript_')
564
568
565 FormatterABC.register(BaseFormatter)
569 FormatterABC.register(BaseFormatter)
566 FormatterABC.register(PlainTextFormatter)
570 FormatterABC.register(PlainTextFormatter)
567 FormatterABC.register(HTMLFormatter)
571 FormatterABC.register(HTMLFormatter)
568 FormatterABC.register(SVGFormatter)
572 FormatterABC.register(SVGFormatter)
569 FormatterABC.register(PNGFormatter)
573 FormatterABC.register(PNGFormatter)
570 FormatterABC.register(JPEGFormatter)
574 FormatterABC.register(JPEGFormatter)
571 FormatterABC.register(LatexFormatter)
575 FormatterABC.register(LatexFormatter)
572 FormatterABC.register(JSONFormatter)
576 FormatterABC.register(JSONFormatter)
573 FormatterABC.register(JavascriptFormatter)
577 FormatterABC.register(JavascriptFormatter)
574
578
575
579
576 def format_display_data(obj, include=None, exclude=None):
580 def format_display_data(obj, include=None, exclude=None):
577 """Return a format data dict for an object.
581 """Return a format data dict for an object.
578
582
579 By default all format types will be computed.
583 By default all format types will be computed.
580
584
581 The following MIME types are currently implemented:
585 The following MIME types are currently implemented:
582
586
583 * text/plain
587 * text/plain
584 * text/html
588 * text/html
585 * text/latex
589 * text/latex
586 * application/json
590 * application/json
587 * application/javascript
591 * application/javascript
588 * image/png
592 * image/png
589 * image/jpeg
593 * image/jpeg
590 * image/svg+xml
594 * image/svg+xml
591
595
592 Parameters
596 Parameters
593 ----------
597 ----------
594 obj : object
598 obj : object
595 The Python object whose format data will be computed.
599 The Python object whose format data will be computed.
596
600
597 Returns
601 Returns
598 -------
602 -------
599 format_dict : dict
603 format_dict : dict
600 A dictionary of key/value pairs, one or each format that was
604 A dictionary of key/value pairs, one or each format that was
601 generated for the object. The keys are the format types, which
605 generated for the object. The keys are the format types, which
602 will usually be MIME type strings and the values and JSON'able
606 will usually be MIME type strings and the values and JSON'able
603 data structure containing the raw data for the representation in
607 data structure containing the raw data for the representation in
604 that format.
608 that format.
605 include : list or tuple, optional
609 include : list or tuple, optional
606 A list of format type strings (MIME types) to include in the
610 A list of format type strings (MIME types) to include in the
607 format data dict. If this is set *only* the format types included
611 format data dict. If this is set *only* the format types included
608 in this list will be computed.
612 in this list will be computed.
609 exclude : list or tuple, optional
613 exclude : list or tuple, optional
610 A list of format type string (MIME types) to exclue in the format
614 A list of format type string (MIME types) to exclue in the format
611 data dict. If this is set all format types will be computed,
615 data dict. If this is set all format types will be computed,
612 except for those included in this argument.
616 except for those included in this argument.
613 """
617 """
614 from IPython.core.interactiveshell import InteractiveShell
618 from IPython.core.interactiveshell import InteractiveShell
615
619
616 InteractiveShell.instance().display_formatter.format(
620 InteractiveShell.instance().display_formatter.format(
617 obj,
621 obj,
618 include,
622 include,
619 exclude
623 exclude
620 )
624 )
621
625
@@ -1,241 +1,246 b''
1 ''' A decorator-based method of constructing IPython magics with `argparse`
1 ''' A decorator-based method of constructing IPython magics with `argparse`
2 option handling.
2 option handling.
3
3
4 New magic functions can be defined like so::
4 New magic functions can be defined like so::
5
5
6 from IPython.core.magic_arguments import (argument, magic_arguments,
6 from IPython.core.magic_arguments import (argument, magic_arguments,
7 parse_argstring)
7 parse_argstring)
8
8
9 @magic_arguments()
9 @magic_arguments()
10 @argument('-o', '--option', help='An optional argument.')
10 @argument('-o', '--option', help='An optional argument.')
11 @argument('arg', type=int, help='An integer positional argument.')
11 @argument('arg', type=int, help='An integer positional argument.')
12 def magic_cool(self, arg):
12 def magic_cool(self, arg):
13 """ A really cool magic command.
13 """ A really cool magic command.
14
14
15 """
15 """
16 args = parse_argstring(magic_cool, arg)
16 args = parse_argstring(magic_cool, arg)
17 ...
17 ...
18
18
19 The `@magic_arguments` decorator marks the function as having argparse arguments.
19 The `@magic_arguments` decorator marks the function as having argparse arguments.
20 The `@argument` decorator adds an argument using the same syntax as argparse's
20 The `@argument` decorator adds an argument using the same syntax as argparse's
21 `add_argument()` method. More sophisticated uses may also require the
21 `add_argument()` method. More sophisticated uses may also require the
22 `@argument_group` or `@kwds` decorator to customize the formatting and the
22 `@argument_group` or `@kwds` decorator to customize the formatting and the
23 parsing.
23 parsing.
24
24
25 Help text for the magic is automatically generated from the docstring and the
25 Help text for the magic is automatically generated from the docstring and the
26 arguments::
26 arguments::
27
27
28 In[1]: %cool?
28 In[1]: %cool?
29 %cool [-o OPTION] arg
29 %cool [-o OPTION] arg
30
30
31 A really cool magic command.
31 A really cool magic command.
32
32
33 positional arguments:
33 positional arguments:
34 arg An integer positional argument.
34 arg An integer positional argument.
35
35
36 optional arguments:
36 optional arguments:
37 -o OPTION, --option OPTION
37 -o OPTION, --option OPTION
38 An optional argument.
38 An optional argument.
39
39
40 Inheritance diagram:
41
42 .. inheritance-diagram:: IPython.core.magic_arguments
43 :parts: 3
44
40 '''
45 '''
41 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
42 # Copyright (C) 2010-2011, IPython Development Team.
47 # Copyright (C) 2010-2011, IPython Development Team.
43 #
48 #
44 # Distributed under the terms of the Modified BSD License.
49 # Distributed under the terms of the Modified BSD License.
45 #
50 #
46 # The full license is in the file COPYING.txt, distributed with this software.
51 # The full license is in the file COPYING.txt, distributed with this software.
47 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
48
53
49 # Our own imports
54 # Our own imports
50 from IPython.external import argparse
55 from IPython.external import argparse
51 from IPython.core.error import UsageError
56 from IPython.core.error import UsageError
52 from IPython.utils.process import arg_split
57 from IPython.utils.process import arg_split
53 from IPython.utils.text import dedent
58 from IPython.utils.text import dedent
54
59
55 class MagicHelpFormatter(argparse.RawDescriptionHelpFormatter):
60 class MagicHelpFormatter(argparse.RawDescriptionHelpFormatter):
56 """ A HelpFormatter which dedents but otherwise preserves indentation.
61 """ A HelpFormatter which dedents but otherwise preserves indentation.
57 """
62 """
58 def _fill_text(self, text, width, indent):
63 def _fill_text(self, text, width, indent):
59 return argparse.RawDescriptionHelpFormatter._fill_text(self, dedent(text), width, indent)
64 return argparse.RawDescriptionHelpFormatter._fill_text(self, dedent(text), width, indent)
60
65
61 class MagicArgumentParser(argparse.ArgumentParser):
66 class MagicArgumentParser(argparse.ArgumentParser):
62 """ An ArgumentParser tweaked for use by IPython magics.
67 """ An ArgumentParser tweaked for use by IPython magics.
63 """
68 """
64 def __init__(self,
69 def __init__(self,
65 prog=None,
70 prog=None,
66 usage=None,
71 usage=None,
67 description=None,
72 description=None,
68 epilog=None,
73 epilog=None,
69 parents=None,
74 parents=None,
70 formatter_class=MagicHelpFormatter,
75 formatter_class=MagicHelpFormatter,
71 prefix_chars='-',
76 prefix_chars='-',
72 argument_default=None,
77 argument_default=None,
73 conflict_handler='error',
78 conflict_handler='error',
74 add_help=False):
79 add_help=False):
75 if parents is None:
80 if parents is None:
76 parents = []
81 parents = []
77 super(MagicArgumentParser, self).__init__(prog=prog, usage=usage,
82 super(MagicArgumentParser, self).__init__(prog=prog, usage=usage,
78 description=description, epilog=epilog,
83 description=description, epilog=epilog,
79 parents=parents, formatter_class=formatter_class,
84 parents=parents, formatter_class=formatter_class,
80 prefix_chars=prefix_chars, argument_default=argument_default,
85 prefix_chars=prefix_chars, argument_default=argument_default,
81 conflict_handler=conflict_handler, add_help=add_help)
86 conflict_handler=conflict_handler, add_help=add_help)
82
87
83 def error(self, message):
88 def error(self, message):
84 """ Raise a catchable error instead of exiting.
89 """ Raise a catchable error instead of exiting.
85 """
90 """
86 raise UsageError(message)
91 raise UsageError(message)
87
92
88 def parse_argstring(self, argstring):
93 def parse_argstring(self, argstring):
89 """ Split a string into an argument list and parse that argument list.
94 """ Split a string into an argument list and parse that argument list.
90 """
95 """
91 argv = arg_split(argstring)
96 argv = arg_split(argstring)
92 return self.parse_args(argv)
97 return self.parse_args(argv)
93
98
94
99
95 def construct_parser(magic_func):
100 def construct_parser(magic_func):
96 """ Construct an argument parser using the function decorations.
101 """ Construct an argument parser using the function decorations.
97 """
102 """
98 kwds = getattr(magic_func, 'argcmd_kwds', {})
103 kwds = getattr(magic_func, 'argcmd_kwds', {})
99 if 'description' not in kwds:
104 if 'description' not in kwds:
100 kwds['description'] = getattr(magic_func, '__doc__', None)
105 kwds['description'] = getattr(magic_func, '__doc__', None)
101 arg_name = real_name(magic_func)
106 arg_name = real_name(magic_func)
102 parser = MagicArgumentParser(arg_name, **kwds)
107 parser = MagicArgumentParser(arg_name, **kwds)
103 # Reverse the list of decorators in order to apply them in the
108 # Reverse the list of decorators in order to apply them in the
104 # order in which they appear in the source.
109 # order in which they appear in the source.
105 group = None
110 group = None
106 for deco in magic_func.decorators[::-1]:
111 for deco in magic_func.decorators[::-1]:
107 result = deco.add_to_parser(parser, group)
112 result = deco.add_to_parser(parser, group)
108 if result is not None:
113 if result is not None:
109 group = result
114 group = result
110
115
111 # Replace the starting 'usage: ' with IPython's %.
116 # Replace the starting 'usage: ' with IPython's %.
112 help_text = parser.format_help()
117 help_text = parser.format_help()
113 if help_text.startswith('usage: '):
118 if help_text.startswith('usage: '):
114 help_text = help_text.replace('usage: ', '%', 1)
119 help_text = help_text.replace('usage: ', '%', 1)
115 else:
120 else:
116 help_text = '%' + help_text
121 help_text = '%' + help_text
117
122
118 # Replace the magic function's docstring with the full help text.
123 # Replace the magic function's docstring with the full help text.
119 magic_func.__doc__ = help_text
124 magic_func.__doc__ = help_text
120
125
121 return parser
126 return parser
122
127
123
128
124 def parse_argstring(magic_func, argstring):
129 def parse_argstring(magic_func, argstring):
125 """ Parse the string of arguments for the given magic function.
130 """ Parse the string of arguments for the given magic function.
126 """
131 """
127 return magic_func.parser.parse_argstring(argstring)
132 return magic_func.parser.parse_argstring(argstring)
128
133
129
134
130 def real_name(magic_func):
135 def real_name(magic_func):
131 """ Find the real name of the magic.
136 """ Find the real name of the magic.
132 """
137 """
133 magic_name = magic_func.__name__
138 magic_name = magic_func.__name__
134 if magic_name.startswith('magic_'):
139 if magic_name.startswith('magic_'):
135 magic_name = magic_name[len('magic_'):]
140 magic_name = magic_name[len('magic_'):]
136 return getattr(magic_func, 'argcmd_name', magic_name)
141 return getattr(magic_func, 'argcmd_name', magic_name)
137
142
138
143
139 class ArgDecorator(object):
144 class ArgDecorator(object):
140 """ Base class for decorators to add ArgumentParser information to a method.
145 """ Base class for decorators to add ArgumentParser information to a method.
141 """
146 """
142
147
143 def __call__(self, func):
148 def __call__(self, func):
144 if not getattr(func, 'has_arguments', False):
149 if not getattr(func, 'has_arguments', False):
145 func.has_arguments = True
150 func.has_arguments = True
146 func.decorators = []
151 func.decorators = []
147 func.decorators.append(self)
152 func.decorators.append(self)
148 return func
153 return func
149
154
150 def add_to_parser(self, parser, group):
155 def add_to_parser(self, parser, group):
151 """ Add this object's information to the parser, if necessary.
156 """ Add this object's information to the parser, if necessary.
152 """
157 """
153 pass
158 pass
154
159
155
160
156 class magic_arguments(ArgDecorator):
161 class magic_arguments(ArgDecorator):
157 """ Mark the magic as having argparse arguments and possibly adjust the
162 """ Mark the magic as having argparse arguments and possibly adjust the
158 name.
163 name.
159 """
164 """
160
165
161 def __init__(self, name=None):
166 def __init__(self, name=None):
162 self.name = name
167 self.name = name
163
168
164 def __call__(self, func):
169 def __call__(self, func):
165 if not getattr(func, 'has_arguments', False):
170 if not getattr(func, 'has_arguments', False):
166 func.has_arguments = True
171 func.has_arguments = True
167 func.decorators = []
172 func.decorators = []
168 if self.name is not None:
173 if self.name is not None:
169 func.argcmd_name = self.name
174 func.argcmd_name = self.name
170 # This should be the first decorator in the list of decorators, thus the
175 # This should be the first decorator in the list of decorators, thus the
171 # last to execute. Build the parser.
176 # last to execute. Build the parser.
172 func.parser = construct_parser(func)
177 func.parser = construct_parser(func)
173 return func
178 return func
174
179
175
180
176 class ArgMethodWrapper(ArgDecorator):
181 class ArgMethodWrapper(ArgDecorator):
177
182
178 """
183 """
179 Base class to define a wrapper for ArgumentParser method.
184 Base class to define a wrapper for ArgumentParser method.
180
185
181 Child class must define either `_method_name` or `add_to_parser`.
186 Child class must define either `_method_name` or `add_to_parser`.
182
187
183 """
188 """
184
189
185 _method_name = None
190 _method_name = None
186
191
187 def __init__(self, *args, **kwds):
192 def __init__(self, *args, **kwds):
188 self.args = args
193 self.args = args
189 self.kwds = kwds
194 self.kwds = kwds
190
195
191 def add_to_parser(self, parser, group):
196 def add_to_parser(self, parser, group):
192 """ Add this object's information to the parser.
197 """ Add this object's information to the parser.
193 """
198 """
194 if group is not None:
199 if group is not None:
195 parser = group
200 parser = group
196 getattr(parser, self._method_name)(*self.args, **self.kwds)
201 getattr(parser, self._method_name)(*self.args, **self.kwds)
197 return None
202 return None
198
203
199
204
200 class argument(ArgMethodWrapper):
205 class argument(ArgMethodWrapper):
201 """ Store arguments and keywords to pass to add_argument().
206 """ Store arguments and keywords to pass to add_argument().
202
207
203 Instances also serve to decorate command methods.
208 Instances also serve to decorate command methods.
204 """
209 """
205 _method_name = 'add_argument'
210 _method_name = 'add_argument'
206
211
207
212
208 class defaults(ArgMethodWrapper):
213 class defaults(ArgMethodWrapper):
209 """ Store arguments and keywords to pass to set_defaults().
214 """ Store arguments and keywords to pass to set_defaults().
210
215
211 Instances also serve to decorate command methods.
216 Instances also serve to decorate command methods.
212 """
217 """
213 _method_name = 'set_defaults'
218 _method_name = 'set_defaults'
214
219
215
220
216 class argument_group(ArgMethodWrapper):
221 class argument_group(ArgMethodWrapper):
217 """ Store arguments and keywords to pass to add_argument_group().
222 """ Store arguments and keywords to pass to add_argument_group().
218
223
219 Instances also serve to decorate command methods.
224 Instances also serve to decorate command methods.
220 """
225 """
221
226
222 def add_to_parser(self, parser, group):
227 def add_to_parser(self, parser, group):
223 """ Add this object's information to the parser.
228 """ Add this object's information to the parser.
224 """
229 """
225 return parser.add_argument_group(*self.args, **self.kwds)
230 return parser.add_argument_group(*self.args, **self.kwds)
226
231
227
232
228 class kwds(ArgDecorator):
233 class kwds(ArgDecorator):
229 """ Provide other keywords to the sub-parser constructor.
234 """ Provide other keywords to the sub-parser constructor.
230 """
235 """
231 def __init__(self, **kwds):
236 def __init__(self, **kwds):
232 self.kwds = kwds
237 self.kwds = kwds
233
238
234 def __call__(self, func):
239 def __call__(self, func):
235 func = super(kwds, self).__call__(func)
240 func = super(kwds, self).__call__(func)
236 func.argcmd_kwds = self.kwds
241 func.argcmd_kwds = self.kwds
237 return func
242 return func
238
243
239
244
240 __all__ = ['magic_arguments', 'argument', 'argument_group', 'kwds',
245 __all__ = ['magic_arguments', 'argument', 'argument_group', 'kwds',
241 'parse_argstring']
246 'parse_argstring']
@@ -1,1242 +1,1247 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 ultratb.py -- Spice up your tracebacks!
3 ultratb.py -- Spice up your tracebacks!
4
4
5 * ColorTB
5 * ColorTB
6 I've always found it a bit hard to visually parse tracebacks in Python. The
6 I've always found it a bit hard to visually parse tracebacks in Python. The
7 ColorTB class is a solution to that problem. It colors the different parts of a
7 ColorTB class is a solution to that problem. It colors the different parts of a
8 traceback in a manner similar to what you would expect from a syntax-highlighting
8 traceback in a manner similar to what you would expect from a syntax-highlighting
9 text editor.
9 text editor.
10
10
11 Installation instructions for ColorTB:
11 Installation instructions for ColorTB:
12 import sys,ultratb
12 import sys,ultratb
13 sys.excepthook = ultratb.ColorTB()
13 sys.excepthook = ultratb.ColorTB()
14
14
15 * VerboseTB
15 * VerboseTB
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
18 and intended it for CGI programmers, but why should they have all the fun? I
18 and intended it for CGI programmers, but why should they have all the fun? I
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
20 but kind of neat, and maybe useful for long-running programs that you believe
20 but kind of neat, and maybe useful for long-running programs that you believe
21 are bug-free. If a crash *does* occur in that type of program you want details.
21 are bug-free. If a crash *does* occur in that type of program you want details.
22 Give it a shot--you'll love it or you'll hate it.
22 Give it a shot--you'll love it or you'll hate it.
23
23
24 Note:
24 Note:
25
25
26 The Verbose mode prints the variables currently visible where the exception
26 The Verbose mode prints the variables currently visible where the exception
27 happened (shortening their strings if too long). This can potentially be
27 happened (shortening their strings if too long). This can potentially be
28 very slow, if you happen to have a huge data structure whose string
28 very slow, if you happen to have a huge data structure whose string
29 representation is complex to compute. Your computer may appear to freeze for
29 representation is complex to compute. Your computer may appear to freeze for
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
31 with Ctrl-C (maybe hitting it more than once).
31 with Ctrl-C (maybe hitting it more than once).
32
32
33 If you encounter this kind of situation often, you may want to use the
33 If you encounter this kind of situation often, you may want to use the
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
35 variables (but otherwise includes the information and context given by
35 variables (but otherwise includes the information and context given by
36 Verbose).
36 Verbose).
37
37
38
38
39 Installation instructions for ColorTB:
39 Installation instructions for ColorTB:
40 import sys,ultratb
40 import sys,ultratb
41 sys.excepthook = ultratb.VerboseTB()
41 sys.excepthook = ultratb.VerboseTB()
42
42
43 Note: Much of the code in this module was lifted verbatim from the standard
43 Note: Much of the code in this module was lifted verbatim from the standard
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
45
45
46 * Color schemes
46 * Color schemes
47 The colors are defined in the class TBTools through the use of the
47 The colors are defined in the class TBTools through the use of the
48 ColorSchemeTable class. Currently the following exist:
48 ColorSchemeTable class. Currently the following exist:
49
49
50 - NoColor: allows all of this module to be used in any terminal (the color
50 - NoColor: allows all of this module to be used in any terminal (the color
51 escapes are just dummy blank strings).
51 escapes are just dummy blank strings).
52
52
53 - Linux: is meant to look good in a terminal like the Linux console (black
53 - Linux: is meant to look good in a terminal like the Linux console (black
54 or very dark background).
54 or very dark background).
55
55
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
57 in light background terminals.
57 in light background terminals.
58
58
59 You can implement other color schemes easily, the syntax is fairly
59 You can implement other color schemes easily, the syntax is fairly
60 self-explanatory. Please send back new schemes you develop to the author for
60 self-explanatory. Please send back new schemes you develop to the author for
61 possible inclusion in future releases.
61 possible inclusion in future releases.
62
63 Inheritance diagram:
64
65 .. inheritance-diagram:: IPython.core.ultratb
66 :parts: 3
62 """
67 """
63
68
64 #*****************************************************************************
69 #*****************************************************************************
65 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
70 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
66 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
71 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
67 #
72 #
68 # Distributed under the terms of the BSD License. The full license is in
73 # Distributed under the terms of the BSD License. The full license is in
69 # the file COPYING, distributed as part of this software.
74 # the file COPYING, distributed as part of this software.
70 #*****************************************************************************
75 #*****************************************************************************
71
76
72 from __future__ import unicode_literals
77 from __future__ import unicode_literals
73
78
74 import inspect
79 import inspect
75 import keyword
80 import keyword
76 import linecache
81 import linecache
77 import os
82 import os
78 import pydoc
83 import pydoc
79 import re
84 import re
80 import sys
85 import sys
81 import time
86 import time
82 import tokenize
87 import tokenize
83 import traceback
88 import traceback
84 import types
89 import types
85
90
86 try: # Python 2
91 try: # Python 2
87 generate_tokens = tokenize.generate_tokens
92 generate_tokens = tokenize.generate_tokens
88 except AttributeError: # Python 3
93 except AttributeError: # Python 3
89 generate_tokens = tokenize.tokenize
94 generate_tokens = tokenize.tokenize
90
95
91 # For purposes of monkeypatching inspect to fix a bug in it.
96 # For purposes of monkeypatching inspect to fix a bug in it.
92 from inspect import getsourcefile, getfile, getmodule,\
97 from inspect import getsourcefile, getfile, getmodule,\
93 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
98 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
94
99
95 # IPython's own modules
100 # IPython's own modules
96 # Modified pdb which doesn't damage IPython's readline handling
101 # Modified pdb which doesn't damage IPython's readline handling
97 from IPython.core import debugger, ipapi
102 from IPython.core import debugger, ipapi
98 from IPython.core.display_trap import DisplayTrap
103 from IPython.core.display_trap import DisplayTrap
99 from IPython.core.excolors import exception_colors
104 from IPython.core.excolors import exception_colors
100 from IPython.utils import PyColorize
105 from IPython.utils import PyColorize
101 from IPython.utils import io
106 from IPython.utils import io
102 from IPython.utils import path as util_path
107 from IPython.utils import path as util_path
103 from IPython.utils import py3compat
108 from IPython.utils import py3compat
104 from IPython.utils import pyfile
109 from IPython.utils import pyfile
105 from IPython.utils import ulinecache
110 from IPython.utils import ulinecache
106 from IPython.utils.data import uniq_stable
111 from IPython.utils.data import uniq_stable
107 from IPython.utils.openpy import read_py_file
112 from IPython.utils.openpy import read_py_file
108 from IPython.utils.warn import info, error
113 from IPython.utils.warn import info, error
109
114
110 # Globals
115 # Globals
111 # amount of space to put line numbers before verbose tracebacks
116 # amount of space to put line numbers before verbose tracebacks
112 INDENT_SIZE = 8
117 INDENT_SIZE = 8
113
118
114 # Default color scheme. This is used, for example, by the traceback
119 # Default color scheme. This is used, for example, by the traceback
115 # formatter. When running in an actual IPython instance, the user's rc.colors
120 # formatter. When running in an actual IPython instance, the user's rc.colors
116 # value is used, but havinga module global makes this functionality available
121 # value is used, but havinga module global makes this functionality available
117 # to users of ultratb who are NOT running inside ipython.
122 # to users of ultratb who are NOT running inside ipython.
118 DEFAULT_SCHEME = 'NoColor'
123 DEFAULT_SCHEME = 'NoColor'
119
124
120 #---------------------------------------------------------------------------
125 #---------------------------------------------------------------------------
121 # Code begins
126 # Code begins
122
127
123 # Utility functions
128 # Utility functions
124 def inspect_error():
129 def inspect_error():
125 """Print a message about internal inspect errors.
130 """Print a message about internal inspect errors.
126
131
127 These are unfortunately quite common."""
132 These are unfortunately quite common."""
128
133
129 error('Internal Python error in the inspect module.\n'
134 error('Internal Python error in the inspect module.\n'
130 'Below is the traceback from this internal error.\n')
135 'Below is the traceback from this internal error.\n')
131
136
132 # This function is a monkeypatch we apply to the Python inspect module. We have
137 # This function is a monkeypatch we apply to the Python inspect module. We have
133 # now found when it's needed (see discussion on issue gh-1456), and we have a
138 # now found when it's needed (see discussion on issue gh-1456), and we have a
134 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
139 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
135 # the monkeypatch is not applied. TK, Aug 2012.
140 # the monkeypatch is not applied. TK, Aug 2012.
136 def findsource(object):
141 def findsource(object):
137 """Return the entire source file and starting line number for an object.
142 """Return the entire source file and starting line number for an object.
138
143
139 The argument may be a module, class, method, function, traceback, frame,
144 The argument may be a module, class, method, function, traceback, frame,
140 or code object. The source code is returned as a list of all the lines
145 or code object. The source code is returned as a list of all the lines
141 in the file and the line number indexes a line in that list. An IOError
146 in the file and the line number indexes a line in that list. An IOError
142 is raised if the source code cannot be retrieved.
147 is raised if the source code cannot be retrieved.
143
148
144 FIXED version with which we monkeypatch the stdlib to work around a bug."""
149 FIXED version with which we monkeypatch the stdlib to work around a bug."""
145
150
146 file = getsourcefile(object) or getfile(object)
151 file = getsourcefile(object) or getfile(object)
147 # If the object is a frame, then trying to get the globals dict from its
152 # If the object is a frame, then trying to get the globals dict from its
148 # module won't work. Instead, the frame object itself has the globals
153 # module won't work. Instead, the frame object itself has the globals
149 # dictionary.
154 # dictionary.
150 globals_dict = None
155 globals_dict = None
151 if inspect.isframe(object):
156 if inspect.isframe(object):
152 # XXX: can this ever be false?
157 # XXX: can this ever be false?
153 globals_dict = object.f_globals
158 globals_dict = object.f_globals
154 else:
159 else:
155 module = getmodule(object, file)
160 module = getmodule(object, file)
156 if module:
161 if module:
157 globals_dict = module.__dict__
162 globals_dict = module.__dict__
158 lines = linecache.getlines(file, globals_dict)
163 lines = linecache.getlines(file, globals_dict)
159 if not lines:
164 if not lines:
160 raise IOError('could not get source code')
165 raise IOError('could not get source code')
161
166
162 if ismodule(object):
167 if ismodule(object):
163 return lines, 0
168 return lines, 0
164
169
165 if isclass(object):
170 if isclass(object):
166 name = object.__name__
171 name = object.__name__
167 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
172 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
168 # make some effort to find the best matching class definition:
173 # make some effort to find the best matching class definition:
169 # use the one with the least indentation, which is the one
174 # use the one with the least indentation, which is the one
170 # that's most probably not inside a function definition.
175 # that's most probably not inside a function definition.
171 candidates = []
176 candidates = []
172 for i in range(len(lines)):
177 for i in range(len(lines)):
173 match = pat.match(lines[i])
178 match = pat.match(lines[i])
174 if match:
179 if match:
175 # if it's at toplevel, it's already the best one
180 # if it's at toplevel, it's already the best one
176 if lines[i][0] == 'c':
181 if lines[i][0] == 'c':
177 return lines, i
182 return lines, i
178 # else add whitespace to candidate list
183 # else add whitespace to candidate list
179 candidates.append((match.group(1), i))
184 candidates.append((match.group(1), i))
180 if candidates:
185 if candidates:
181 # this will sort by whitespace, and by line number,
186 # this will sort by whitespace, and by line number,
182 # less whitespace first
187 # less whitespace first
183 candidates.sort()
188 candidates.sort()
184 return lines, candidates[0][1]
189 return lines, candidates[0][1]
185 else:
190 else:
186 raise IOError('could not find class definition')
191 raise IOError('could not find class definition')
187
192
188 if ismethod(object):
193 if ismethod(object):
189 object = object.im_func
194 object = object.im_func
190 if isfunction(object):
195 if isfunction(object):
191 object = object.func_code
196 object = object.func_code
192 if istraceback(object):
197 if istraceback(object):
193 object = object.tb_frame
198 object = object.tb_frame
194 if isframe(object):
199 if isframe(object):
195 object = object.f_code
200 object = object.f_code
196 if iscode(object):
201 if iscode(object):
197 if not hasattr(object, 'co_firstlineno'):
202 if not hasattr(object, 'co_firstlineno'):
198 raise IOError('could not find function definition')
203 raise IOError('could not find function definition')
199 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
204 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
200 pmatch = pat.match
205 pmatch = pat.match
201 # fperez - fix: sometimes, co_firstlineno can give a number larger than
206 # fperez - fix: sometimes, co_firstlineno can give a number larger than
202 # the length of lines, which causes an error. Safeguard against that.
207 # the length of lines, which causes an error. Safeguard against that.
203 lnum = min(object.co_firstlineno,len(lines))-1
208 lnum = min(object.co_firstlineno,len(lines))-1
204 while lnum > 0:
209 while lnum > 0:
205 if pmatch(lines[lnum]): break
210 if pmatch(lines[lnum]): break
206 lnum -= 1
211 lnum -= 1
207
212
208 return lines, lnum
213 return lines, lnum
209 raise IOError('could not find code object')
214 raise IOError('could not find code object')
210
215
211 # Monkeypatch inspect to apply our bugfix. This code only works with Python >= 2.5
216 # Monkeypatch inspect to apply our bugfix. This code only works with Python >= 2.5
212 inspect.findsource = findsource
217 inspect.findsource = findsource
213
218
214 def fix_frame_records_filenames(records):
219 def fix_frame_records_filenames(records):
215 """Try to fix the filenames in each record from inspect.getinnerframes().
220 """Try to fix the filenames in each record from inspect.getinnerframes().
216
221
217 Particularly, modules loaded from within zip files have useless filenames
222 Particularly, modules loaded from within zip files have useless filenames
218 attached to their code object, and inspect.getinnerframes() just uses it.
223 attached to their code object, and inspect.getinnerframes() just uses it.
219 """
224 """
220 fixed_records = []
225 fixed_records = []
221 for frame, filename, line_no, func_name, lines, index in records:
226 for frame, filename, line_no, func_name, lines, index in records:
222 # Look inside the frame's globals dictionary for __file__, which should
227 # Look inside the frame's globals dictionary for __file__, which should
223 # be better.
228 # be better.
224 better_fn = frame.f_globals.get('__file__', None)
229 better_fn = frame.f_globals.get('__file__', None)
225 if isinstance(better_fn, str):
230 if isinstance(better_fn, str):
226 # Check the type just in case someone did something weird with
231 # Check the type just in case someone did something weird with
227 # __file__. It might also be None if the error occurred during
232 # __file__. It might also be None if the error occurred during
228 # import.
233 # import.
229 filename = better_fn
234 filename = better_fn
230 fixed_records.append((frame, filename, line_no, func_name, lines, index))
235 fixed_records.append((frame, filename, line_no, func_name, lines, index))
231 return fixed_records
236 return fixed_records
232
237
233
238
234 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
239 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
235 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
240 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
236
241
237 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
242 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
238
243
239 # If the error is at the console, don't build any context, since it would
244 # If the error is at the console, don't build any context, since it would
240 # otherwise produce 5 blank lines printed out (there is no file at the
245 # otherwise produce 5 blank lines printed out (there is no file at the
241 # console)
246 # console)
242 rec_check = records[tb_offset:]
247 rec_check = records[tb_offset:]
243 try:
248 try:
244 rname = rec_check[0][1]
249 rname = rec_check[0][1]
245 if rname == '<ipython console>' or rname.endswith('<string>'):
250 if rname == '<ipython console>' or rname.endswith('<string>'):
246 return rec_check
251 return rec_check
247 except IndexError:
252 except IndexError:
248 pass
253 pass
249
254
250 aux = traceback.extract_tb(etb)
255 aux = traceback.extract_tb(etb)
251 assert len(records) == len(aux)
256 assert len(records) == len(aux)
252 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
257 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
253 maybeStart = lnum-1 - context//2
258 maybeStart = lnum-1 - context//2
254 start = max(maybeStart, 0)
259 start = max(maybeStart, 0)
255 end = start + context
260 end = start + context
256 lines = ulinecache.getlines(file)[start:end]
261 lines = ulinecache.getlines(file)[start:end]
257 buf = list(records[i])
262 buf = list(records[i])
258 buf[LNUM_POS] = lnum
263 buf[LNUM_POS] = lnum
259 buf[INDEX_POS] = lnum - 1 - start
264 buf[INDEX_POS] = lnum - 1 - start
260 buf[LINES_POS] = lines
265 buf[LINES_POS] = lines
261 records[i] = tuple(buf)
266 records[i] = tuple(buf)
262 return records[tb_offset:]
267 return records[tb_offset:]
263
268
264 # Helper function -- largely belongs to VerboseTB, but we need the same
269 # Helper function -- largely belongs to VerboseTB, but we need the same
265 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
270 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
266 # can be recognized properly by ipython.el's py-traceback-line-re
271 # can be recognized properly by ipython.el's py-traceback-line-re
267 # (SyntaxErrors have to be treated specially because they have no traceback)
272 # (SyntaxErrors have to be treated specially because they have no traceback)
268
273
269 _parser = PyColorize.Parser()
274 _parser = PyColorize.Parser()
270
275
271 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
276 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
272 numbers_width = INDENT_SIZE - 1
277 numbers_width = INDENT_SIZE - 1
273 res = []
278 res = []
274 i = lnum - index
279 i = lnum - index
275
280
276 # This lets us get fully syntax-highlighted tracebacks.
281 # This lets us get fully syntax-highlighted tracebacks.
277 if scheme is None:
282 if scheme is None:
278 ipinst = ipapi.get()
283 ipinst = ipapi.get()
279 if ipinst is not None:
284 if ipinst is not None:
280 scheme = ipinst.colors
285 scheme = ipinst.colors
281 else:
286 else:
282 scheme = DEFAULT_SCHEME
287 scheme = DEFAULT_SCHEME
283
288
284 _line_format = _parser.format2
289 _line_format = _parser.format2
285
290
286 for line in lines:
291 for line in lines:
287 line = py3compat.cast_unicode(line)
292 line = py3compat.cast_unicode(line)
288
293
289 new_line, err = _line_format(line, 'str', scheme)
294 new_line, err = _line_format(line, 'str', scheme)
290 if not err: line = new_line
295 if not err: line = new_line
291
296
292 if i == lnum:
297 if i == lnum:
293 # This is the line with the error
298 # This is the line with the error
294 pad = numbers_width - len(str(i))
299 pad = numbers_width - len(str(i))
295 if pad >= 3:
300 if pad >= 3:
296 marker = '-'*(pad-3) + '-> '
301 marker = '-'*(pad-3) + '-> '
297 elif pad == 2:
302 elif pad == 2:
298 marker = '> '
303 marker = '> '
299 elif pad == 1:
304 elif pad == 1:
300 marker = '>'
305 marker = '>'
301 else:
306 else:
302 marker = ''
307 marker = ''
303 num = marker + str(i)
308 num = marker + str(i)
304 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
309 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
305 Colors.line, line, Colors.Normal)
310 Colors.line, line, Colors.Normal)
306 else:
311 else:
307 num = '%*s' % (numbers_width,i)
312 num = '%*s' % (numbers_width,i)
308 line = '%s%s%s %s' %(Colors.lineno, num,
313 line = '%s%s%s %s' %(Colors.lineno, num,
309 Colors.Normal, line)
314 Colors.Normal, line)
310
315
311 res.append(line)
316 res.append(line)
312 if lvals and i == lnum:
317 if lvals and i == lnum:
313 res.append(lvals + '\n')
318 res.append(lvals + '\n')
314 i = i + 1
319 i = i + 1
315 return res
320 return res
316
321
317
322
318 #---------------------------------------------------------------------------
323 #---------------------------------------------------------------------------
319 # Module classes
324 # Module classes
320 class TBTools(object):
325 class TBTools(object):
321 """Basic tools used by all traceback printer classes."""
326 """Basic tools used by all traceback printer classes."""
322
327
323 # Number of frames to skip when reporting tracebacks
328 # Number of frames to skip when reporting tracebacks
324 tb_offset = 0
329 tb_offset = 0
325
330
326 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
331 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
327 # Whether to call the interactive pdb debugger after printing
332 # Whether to call the interactive pdb debugger after printing
328 # tracebacks or not
333 # tracebacks or not
329 self.call_pdb = call_pdb
334 self.call_pdb = call_pdb
330
335
331 # Output stream to write to. Note that we store the original value in
336 # Output stream to write to. Note that we store the original value in
332 # a private attribute and then make the public ostream a property, so
337 # a private attribute and then make the public ostream a property, so
333 # that we can delay accessing io.stdout until runtime. The way
338 # that we can delay accessing io.stdout until runtime. The way
334 # things are written now, the io.stdout object is dynamically managed
339 # things are written now, the io.stdout object is dynamically managed
335 # so a reference to it should NEVER be stored statically. This
340 # so a reference to it should NEVER be stored statically. This
336 # property approach confines this detail to a single location, and all
341 # property approach confines this detail to a single location, and all
337 # subclasses can simply access self.ostream for writing.
342 # subclasses can simply access self.ostream for writing.
338 self._ostream = ostream
343 self._ostream = ostream
339
344
340 # Create color table
345 # Create color table
341 self.color_scheme_table = exception_colors()
346 self.color_scheme_table = exception_colors()
342
347
343 self.set_colors(color_scheme)
348 self.set_colors(color_scheme)
344 self.old_scheme = color_scheme # save initial value for toggles
349 self.old_scheme = color_scheme # save initial value for toggles
345
350
346 if call_pdb:
351 if call_pdb:
347 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
352 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
348 else:
353 else:
349 self.pdb = None
354 self.pdb = None
350
355
351 def _get_ostream(self):
356 def _get_ostream(self):
352 """Output stream that exceptions are written to.
357 """Output stream that exceptions are written to.
353
358
354 Valid values are:
359 Valid values are:
355
360
356 - None: the default, which means that IPython will dynamically resolve
361 - None: the default, which means that IPython will dynamically resolve
357 to io.stdout. This ensures compatibility with most tools, including
362 to io.stdout. This ensures compatibility with most tools, including
358 Windows (where plain stdout doesn't recognize ANSI escapes).
363 Windows (where plain stdout doesn't recognize ANSI escapes).
359
364
360 - Any object with 'write' and 'flush' attributes.
365 - Any object with 'write' and 'flush' attributes.
361 """
366 """
362 return io.stdout if self._ostream is None else self._ostream
367 return io.stdout if self._ostream is None else self._ostream
363
368
364 def _set_ostream(self, val):
369 def _set_ostream(self, val):
365 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
370 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
366 self._ostream = val
371 self._ostream = val
367
372
368 ostream = property(_get_ostream, _set_ostream)
373 ostream = property(_get_ostream, _set_ostream)
369
374
370 def set_colors(self,*args,**kw):
375 def set_colors(self,*args,**kw):
371 """Shorthand access to the color table scheme selector method."""
376 """Shorthand access to the color table scheme selector method."""
372
377
373 # Set own color table
378 # Set own color table
374 self.color_scheme_table.set_active_scheme(*args,**kw)
379 self.color_scheme_table.set_active_scheme(*args,**kw)
375 # for convenience, set Colors to the active scheme
380 # for convenience, set Colors to the active scheme
376 self.Colors = self.color_scheme_table.active_colors
381 self.Colors = self.color_scheme_table.active_colors
377 # Also set colors of debugger
382 # Also set colors of debugger
378 if hasattr(self,'pdb') and self.pdb is not None:
383 if hasattr(self,'pdb') and self.pdb is not None:
379 self.pdb.set_colors(*args,**kw)
384 self.pdb.set_colors(*args,**kw)
380
385
381 def color_toggle(self):
386 def color_toggle(self):
382 """Toggle between the currently active color scheme and NoColor."""
387 """Toggle between the currently active color scheme and NoColor."""
383
388
384 if self.color_scheme_table.active_scheme_name == 'NoColor':
389 if self.color_scheme_table.active_scheme_name == 'NoColor':
385 self.color_scheme_table.set_active_scheme(self.old_scheme)
390 self.color_scheme_table.set_active_scheme(self.old_scheme)
386 self.Colors = self.color_scheme_table.active_colors
391 self.Colors = self.color_scheme_table.active_colors
387 else:
392 else:
388 self.old_scheme = self.color_scheme_table.active_scheme_name
393 self.old_scheme = self.color_scheme_table.active_scheme_name
389 self.color_scheme_table.set_active_scheme('NoColor')
394 self.color_scheme_table.set_active_scheme('NoColor')
390 self.Colors = self.color_scheme_table.active_colors
395 self.Colors = self.color_scheme_table.active_colors
391
396
392 def stb2text(self, stb):
397 def stb2text(self, stb):
393 """Convert a structured traceback (a list) to a string."""
398 """Convert a structured traceback (a list) to a string."""
394 return '\n'.join(stb)
399 return '\n'.join(stb)
395
400
396 def text(self, etype, value, tb, tb_offset=None, context=5):
401 def text(self, etype, value, tb, tb_offset=None, context=5):
397 """Return formatted traceback.
402 """Return formatted traceback.
398
403
399 Subclasses may override this if they add extra arguments.
404 Subclasses may override this if they add extra arguments.
400 """
405 """
401 tb_list = self.structured_traceback(etype, value, tb,
406 tb_list = self.structured_traceback(etype, value, tb,
402 tb_offset, context)
407 tb_offset, context)
403 return self.stb2text(tb_list)
408 return self.stb2text(tb_list)
404
409
405 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
410 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
406 context=5, mode=None):
411 context=5, mode=None):
407 """Return a list of traceback frames.
412 """Return a list of traceback frames.
408
413
409 Must be implemented by each class.
414 Must be implemented by each class.
410 """
415 """
411 raise NotImplementedError()
416 raise NotImplementedError()
412
417
413
418
414 #---------------------------------------------------------------------------
419 #---------------------------------------------------------------------------
415 class ListTB(TBTools):
420 class ListTB(TBTools):
416 """Print traceback information from a traceback list, with optional color.
421 """Print traceback information from a traceback list, with optional color.
417
422
418 Calling: requires 3 arguments:
423 Calling: requires 3 arguments:
419 (etype, evalue, elist)
424 (etype, evalue, elist)
420 as would be obtained by:
425 as would be obtained by:
421 etype, evalue, tb = sys.exc_info()
426 etype, evalue, tb = sys.exc_info()
422 if tb:
427 if tb:
423 elist = traceback.extract_tb(tb)
428 elist = traceback.extract_tb(tb)
424 else:
429 else:
425 elist = None
430 elist = None
426
431
427 It can thus be used by programs which need to process the traceback before
432 It can thus be used by programs which need to process the traceback before
428 printing (such as console replacements based on the code module from the
433 printing (such as console replacements based on the code module from the
429 standard library).
434 standard library).
430
435
431 Because they are meant to be called without a full traceback (only a
436 Because they are meant to be called without a full traceback (only a
432 list), instances of this class can't call the interactive pdb debugger."""
437 list), instances of this class can't call the interactive pdb debugger."""
433
438
434 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
439 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
435 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
440 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
436 ostream=ostream)
441 ostream=ostream)
437
442
438 def __call__(self, etype, value, elist):
443 def __call__(self, etype, value, elist):
439 self.ostream.flush()
444 self.ostream.flush()
440 self.ostream.write(self.text(etype, value, elist))
445 self.ostream.write(self.text(etype, value, elist))
441 self.ostream.write('\n')
446 self.ostream.write('\n')
442
447
443 def structured_traceback(self, etype, value, elist, tb_offset=None,
448 def structured_traceback(self, etype, value, elist, tb_offset=None,
444 context=5):
449 context=5):
445 """Return a color formatted string with the traceback info.
450 """Return a color formatted string with the traceback info.
446
451
447 Parameters
452 Parameters
448 ----------
453 ----------
449 etype : exception type
454 etype : exception type
450 Type of the exception raised.
455 Type of the exception raised.
451
456
452 value : object
457 value : object
453 Data stored in the exception
458 Data stored in the exception
454
459
455 elist : list
460 elist : list
456 List of frames, see class docstring for details.
461 List of frames, see class docstring for details.
457
462
458 tb_offset : int, optional
463 tb_offset : int, optional
459 Number of frames in the traceback to skip. If not given, the
464 Number of frames in the traceback to skip. If not given, the
460 instance value is used (set in constructor).
465 instance value is used (set in constructor).
461
466
462 context : int, optional
467 context : int, optional
463 Number of lines of context information to print.
468 Number of lines of context information to print.
464
469
465 Returns
470 Returns
466 -------
471 -------
467 String with formatted exception.
472 String with formatted exception.
468 """
473 """
469 tb_offset = self.tb_offset if tb_offset is None else tb_offset
474 tb_offset = self.tb_offset if tb_offset is None else tb_offset
470 Colors = self.Colors
475 Colors = self.Colors
471 out_list = []
476 out_list = []
472 if elist:
477 if elist:
473
478
474 if tb_offset and len(elist) > tb_offset:
479 if tb_offset and len(elist) > tb_offset:
475 elist = elist[tb_offset:]
480 elist = elist[tb_offset:]
476
481
477 out_list.append('Traceback %s(most recent call last)%s:' %
482 out_list.append('Traceback %s(most recent call last)%s:' %
478 (Colors.normalEm, Colors.Normal) + '\n')
483 (Colors.normalEm, Colors.Normal) + '\n')
479 out_list.extend(self._format_list(elist))
484 out_list.extend(self._format_list(elist))
480 # The exception info should be a single entry in the list.
485 # The exception info should be a single entry in the list.
481 lines = ''.join(self._format_exception_only(etype, value))
486 lines = ''.join(self._format_exception_only(etype, value))
482 out_list.append(lines)
487 out_list.append(lines)
483
488
484 # Note: this code originally read:
489 # Note: this code originally read:
485
490
486 ## for line in lines[:-1]:
491 ## for line in lines[:-1]:
487 ## out_list.append(" "+line)
492 ## out_list.append(" "+line)
488 ## out_list.append(lines[-1])
493 ## out_list.append(lines[-1])
489
494
490 # This means it was indenting everything but the last line by a little
495 # This means it was indenting everything but the last line by a little
491 # bit. I've disabled this for now, but if we see ugliness somewhre we
496 # bit. I've disabled this for now, but if we see ugliness somewhre we
492 # can restore it.
497 # can restore it.
493
498
494 return out_list
499 return out_list
495
500
496 def _format_list(self, extracted_list):
501 def _format_list(self, extracted_list):
497 """Format a list of traceback entry tuples for printing.
502 """Format a list of traceback entry tuples for printing.
498
503
499 Given a list of tuples as returned by extract_tb() or
504 Given a list of tuples as returned by extract_tb() or
500 extract_stack(), return a list of strings ready for printing.
505 extract_stack(), return a list of strings ready for printing.
501 Each string in the resulting list corresponds to the item with the
506 Each string in the resulting list corresponds to the item with the
502 same index in the argument list. Each string ends in a newline;
507 same index in the argument list. Each string ends in a newline;
503 the strings may contain internal newlines as well, for those items
508 the strings may contain internal newlines as well, for those items
504 whose source text line is not None.
509 whose source text line is not None.
505
510
506 Lifted almost verbatim from traceback.py
511 Lifted almost verbatim from traceback.py
507 """
512 """
508
513
509 Colors = self.Colors
514 Colors = self.Colors
510 list = []
515 list = []
511 for filename, lineno, name, line in extracted_list[:-1]:
516 for filename, lineno, name, line in extracted_list[:-1]:
512 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
517 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
513 (Colors.filename, filename, Colors.Normal,
518 (Colors.filename, filename, Colors.Normal,
514 Colors.lineno, lineno, Colors.Normal,
519 Colors.lineno, lineno, Colors.Normal,
515 Colors.name, name, Colors.Normal)
520 Colors.name, name, Colors.Normal)
516 if line:
521 if line:
517 item += ' %s\n' % line.strip()
522 item += ' %s\n' % line.strip()
518 list.append(item)
523 list.append(item)
519 # Emphasize the last entry
524 # Emphasize the last entry
520 filename, lineno, name, line = extracted_list[-1]
525 filename, lineno, name, line = extracted_list[-1]
521 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
526 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
522 (Colors.normalEm,
527 (Colors.normalEm,
523 Colors.filenameEm, filename, Colors.normalEm,
528 Colors.filenameEm, filename, Colors.normalEm,
524 Colors.linenoEm, lineno, Colors.normalEm,
529 Colors.linenoEm, lineno, Colors.normalEm,
525 Colors.nameEm, name, Colors.normalEm,
530 Colors.nameEm, name, Colors.normalEm,
526 Colors.Normal)
531 Colors.Normal)
527 if line:
532 if line:
528 item += '%s %s%s\n' % (Colors.line, line.strip(),
533 item += '%s %s%s\n' % (Colors.line, line.strip(),
529 Colors.Normal)
534 Colors.Normal)
530 list.append(item)
535 list.append(item)
531 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
536 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
532 return list
537 return list
533
538
534 def _format_exception_only(self, etype, value):
539 def _format_exception_only(self, etype, value):
535 """Format the exception part of a traceback.
540 """Format the exception part of a traceback.
536
541
537 The arguments are the exception type and value such as given by
542 The arguments are the exception type and value such as given by
538 sys.exc_info()[:2]. The return value is a list of strings, each ending
543 sys.exc_info()[:2]. The return value is a list of strings, each ending
539 in a newline. Normally, the list contains a single string; however,
544 in a newline. Normally, the list contains a single string; however,
540 for SyntaxError exceptions, it contains several lines that (when
545 for SyntaxError exceptions, it contains several lines that (when
541 printed) display detailed information about where the syntax error
546 printed) display detailed information about where the syntax error
542 occurred. The message indicating which exception occurred is the
547 occurred. The message indicating which exception occurred is the
543 always last string in the list.
548 always last string in the list.
544
549
545 Also lifted nearly verbatim from traceback.py
550 Also lifted nearly verbatim from traceback.py
546 """
551 """
547 have_filedata = False
552 have_filedata = False
548 Colors = self.Colors
553 Colors = self.Colors
549 list = []
554 list = []
550 stype = Colors.excName + etype.__name__ + Colors.Normal
555 stype = Colors.excName + etype.__name__ + Colors.Normal
551 if value is None:
556 if value is None:
552 # Not sure if this can still happen in Python 2.6 and above
557 # Not sure if this can still happen in Python 2.6 and above
553 list.append( py3compat.cast_unicode(stype) + '\n')
558 list.append( py3compat.cast_unicode(stype) + '\n')
554 else:
559 else:
555 if issubclass(etype, SyntaxError):
560 if issubclass(etype, SyntaxError):
556 have_filedata = True
561 have_filedata = True
557 #print 'filename is',filename # dbg
562 #print 'filename is',filename # dbg
558 if not value.filename: value.filename = "<string>"
563 if not value.filename: value.filename = "<string>"
559 if value.lineno:
564 if value.lineno:
560 lineno = value.lineno
565 lineno = value.lineno
561 textline = ulinecache.getline(value.filename, value.lineno)
566 textline = ulinecache.getline(value.filename, value.lineno)
562 else:
567 else:
563 lineno = 'unknown'
568 lineno = 'unknown'
564 textline = ''
569 textline = ''
565 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
570 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
566 (Colors.normalEm,
571 (Colors.normalEm,
567 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
572 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
568 Colors.linenoEm, lineno, Colors.Normal ))
573 Colors.linenoEm, lineno, Colors.Normal ))
569 if textline == '':
574 if textline == '':
570 textline = py3compat.cast_unicode(value.text, "utf-8")
575 textline = py3compat.cast_unicode(value.text, "utf-8")
571
576
572 if textline is not None:
577 if textline is not None:
573 i = 0
578 i = 0
574 while i < len(textline) and textline[i].isspace():
579 while i < len(textline) and textline[i].isspace():
575 i += 1
580 i += 1
576 list.append('%s %s%s\n' % (Colors.line,
581 list.append('%s %s%s\n' % (Colors.line,
577 textline.strip(),
582 textline.strip(),
578 Colors.Normal))
583 Colors.Normal))
579 if value.offset is not None:
584 if value.offset is not None:
580 s = ' '
585 s = ' '
581 for c in textline[i:value.offset-1]:
586 for c in textline[i:value.offset-1]:
582 if c.isspace():
587 if c.isspace():
583 s += c
588 s += c
584 else:
589 else:
585 s += ' '
590 s += ' '
586 list.append('%s%s^%s\n' % (Colors.caret, s,
591 list.append('%s%s^%s\n' % (Colors.caret, s,
587 Colors.Normal) )
592 Colors.Normal) )
588
593
589 try:
594 try:
590 s = value.msg
595 s = value.msg
591 except Exception:
596 except Exception:
592 s = self._some_str(value)
597 s = self._some_str(value)
593 if s:
598 if s:
594 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
599 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
595 Colors.Normal, s))
600 Colors.Normal, s))
596 else:
601 else:
597 list.append('%s\n' % str(stype))
602 list.append('%s\n' % str(stype))
598
603
599 # sync with user hooks
604 # sync with user hooks
600 if have_filedata:
605 if have_filedata:
601 ipinst = ipapi.get()
606 ipinst = ipapi.get()
602 if ipinst is not None:
607 if ipinst is not None:
603 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
608 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
604
609
605 return list
610 return list
606
611
607 def get_exception_only(self, etype, value):
612 def get_exception_only(self, etype, value):
608 """Only print the exception type and message, without a traceback.
613 """Only print the exception type and message, without a traceback.
609
614
610 Parameters
615 Parameters
611 ----------
616 ----------
612 etype : exception type
617 etype : exception type
613 value : exception value
618 value : exception value
614 """
619 """
615 return ListTB.structured_traceback(self, etype, value, [])
620 return ListTB.structured_traceback(self, etype, value, [])
616
621
617
622
618 def show_exception_only(self, etype, evalue):
623 def show_exception_only(self, etype, evalue):
619 """Only print the exception type and message, without a traceback.
624 """Only print the exception type and message, without a traceback.
620
625
621 Parameters
626 Parameters
622 ----------
627 ----------
623 etype : exception type
628 etype : exception type
624 value : exception value
629 value : exception value
625 """
630 """
626 # This method needs to use __call__ from *this* class, not the one from
631 # This method needs to use __call__ from *this* class, not the one from
627 # a subclass whose signature or behavior may be different
632 # a subclass whose signature or behavior may be different
628 ostream = self.ostream
633 ostream = self.ostream
629 ostream.flush()
634 ostream.flush()
630 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
635 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
631 ostream.flush()
636 ostream.flush()
632
637
633 def _some_str(self, value):
638 def _some_str(self, value):
634 # Lifted from traceback.py
639 # Lifted from traceback.py
635 try:
640 try:
636 return str(value)
641 return str(value)
637 except:
642 except:
638 return '<unprintable %s object>' % type(value).__name__
643 return '<unprintable %s object>' % type(value).__name__
639
644
640 #----------------------------------------------------------------------------
645 #----------------------------------------------------------------------------
641 class VerboseTB(TBTools):
646 class VerboseTB(TBTools):
642 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
647 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
643 of HTML. Requires inspect and pydoc. Crazy, man.
648 of HTML. Requires inspect and pydoc. Crazy, man.
644
649
645 Modified version which optionally strips the topmost entries from the
650 Modified version which optionally strips the topmost entries from the
646 traceback, to be used with alternate interpreters (because their own code
651 traceback, to be used with alternate interpreters (because their own code
647 would appear in the traceback)."""
652 would appear in the traceback)."""
648
653
649 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
654 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
650 tb_offset=0, long_header=False, include_vars=True,
655 tb_offset=0, long_header=False, include_vars=True,
651 check_cache=None):
656 check_cache=None):
652 """Specify traceback offset, headers and color scheme.
657 """Specify traceback offset, headers and color scheme.
653
658
654 Define how many frames to drop from the tracebacks. Calling it with
659 Define how many frames to drop from the tracebacks. Calling it with
655 tb_offset=1 allows use of this handler in interpreters which will have
660 tb_offset=1 allows use of this handler in interpreters which will have
656 their own code at the top of the traceback (VerboseTB will first
661 their own code at the top of the traceback (VerboseTB will first
657 remove that frame before printing the traceback info)."""
662 remove that frame before printing the traceback info)."""
658 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
663 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
659 ostream=ostream)
664 ostream=ostream)
660 self.tb_offset = tb_offset
665 self.tb_offset = tb_offset
661 self.long_header = long_header
666 self.long_header = long_header
662 self.include_vars = include_vars
667 self.include_vars = include_vars
663 # By default we use linecache.checkcache, but the user can provide a
668 # By default we use linecache.checkcache, but the user can provide a
664 # different check_cache implementation. This is used by the IPython
669 # different check_cache implementation. This is used by the IPython
665 # kernel to provide tracebacks for interactive code that is cached,
670 # kernel to provide tracebacks for interactive code that is cached,
666 # by a compiler instance that flushes the linecache but preserves its
671 # by a compiler instance that flushes the linecache but preserves its
667 # own code cache.
672 # own code cache.
668 if check_cache is None:
673 if check_cache is None:
669 check_cache = linecache.checkcache
674 check_cache = linecache.checkcache
670 self.check_cache = check_cache
675 self.check_cache = check_cache
671
676
672 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
677 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
673 context=5):
678 context=5):
674 """Return a nice text document describing the traceback."""
679 """Return a nice text document describing the traceback."""
675
680
676 tb_offset = self.tb_offset if tb_offset is None else tb_offset
681 tb_offset = self.tb_offset if tb_offset is None else tb_offset
677
682
678 # some locals
683 # some locals
679 try:
684 try:
680 etype = etype.__name__
685 etype = etype.__name__
681 except AttributeError:
686 except AttributeError:
682 pass
687 pass
683 Colors = self.Colors # just a shorthand + quicker name lookup
688 Colors = self.Colors # just a shorthand + quicker name lookup
684 ColorsNormal = Colors.Normal # used a lot
689 ColorsNormal = Colors.Normal # used a lot
685 col_scheme = self.color_scheme_table.active_scheme_name
690 col_scheme = self.color_scheme_table.active_scheme_name
686 indent = ' '*INDENT_SIZE
691 indent = ' '*INDENT_SIZE
687 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
692 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
688 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
693 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
689 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
694 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
690
695
691 # some internal-use functions
696 # some internal-use functions
692 def text_repr(value):
697 def text_repr(value):
693 """Hopefully pretty robust repr equivalent."""
698 """Hopefully pretty robust repr equivalent."""
694 # this is pretty horrible but should always return *something*
699 # this is pretty horrible but should always return *something*
695 try:
700 try:
696 return pydoc.text.repr(value)
701 return pydoc.text.repr(value)
697 except KeyboardInterrupt:
702 except KeyboardInterrupt:
698 raise
703 raise
699 except:
704 except:
700 try:
705 try:
701 return repr(value)
706 return repr(value)
702 except KeyboardInterrupt:
707 except KeyboardInterrupt:
703 raise
708 raise
704 except:
709 except:
705 try:
710 try:
706 # all still in an except block so we catch
711 # all still in an except block so we catch
707 # getattr raising
712 # getattr raising
708 name = getattr(value, '__name__', None)
713 name = getattr(value, '__name__', None)
709 if name:
714 if name:
710 # ick, recursion
715 # ick, recursion
711 return text_repr(name)
716 return text_repr(name)
712 klass = getattr(value, '__class__', None)
717 klass = getattr(value, '__class__', None)
713 if klass:
718 if klass:
714 return '%s instance' % text_repr(klass)
719 return '%s instance' % text_repr(klass)
715 except KeyboardInterrupt:
720 except KeyboardInterrupt:
716 raise
721 raise
717 except:
722 except:
718 return 'UNRECOVERABLE REPR FAILURE'
723 return 'UNRECOVERABLE REPR FAILURE'
719 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
724 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
720 def nullrepr(value, repr=text_repr): return ''
725 def nullrepr(value, repr=text_repr): return ''
721
726
722 # meat of the code begins
727 # meat of the code begins
723 try:
728 try:
724 etype = etype.__name__
729 etype = etype.__name__
725 except AttributeError:
730 except AttributeError:
726 pass
731 pass
727
732
728 if self.long_header:
733 if self.long_header:
729 # Header with the exception type, python version, and date
734 # Header with the exception type, python version, and date
730 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
735 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
731 date = time.ctime(time.time())
736 date = time.ctime(time.time())
732
737
733 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
738 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
734 exc, ' '*(75-len(str(etype))-len(pyver)),
739 exc, ' '*(75-len(str(etype))-len(pyver)),
735 pyver, date.rjust(75) )
740 pyver, date.rjust(75) )
736 head += "\nA problem occured executing Python code. Here is the sequence of function"\
741 head += "\nA problem occured executing Python code. Here is the sequence of function"\
737 "\ncalls leading up to the error, with the most recent (innermost) call last."
742 "\ncalls leading up to the error, with the most recent (innermost) call last."
738 else:
743 else:
739 # Simplified header
744 # Simplified header
740 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
745 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
741 'Traceback (most recent call last)'.\
746 'Traceback (most recent call last)'.\
742 rjust(75 - len(str(etype)) ) )
747 rjust(75 - len(str(etype)) ) )
743 frames = []
748 frames = []
744 # Flush cache before calling inspect. This helps alleviate some of the
749 # Flush cache before calling inspect. This helps alleviate some of the
745 # problems with python 2.3's inspect.py.
750 # problems with python 2.3's inspect.py.
746 ##self.check_cache()
751 ##self.check_cache()
747 # Drop topmost frames if requested
752 # Drop topmost frames if requested
748 try:
753 try:
749 # Try the default getinnerframes and Alex's: Alex's fixes some
754 # Try the default getinnerframes and Alex's: Alex's fixes some
750 # problems, but it generates empty tracebacks for console errors
755 # problems, but it generates empty tracebacks for console errors
751 # (5 blanks lines) where none should be returned.
756 # (5 blanks lines) where none should be returned.
752 #records = inspect.getinnerframes(etb, context)[tb_offset:]
757 #records = inspect.getinnerframes(etb, context)[tb_offset:]
753 #print 'python records:', records # dbg
758 #print 'python records:', records # dbg
754 records = _fixed_getinnerframes(etb, context, tb_offset)
759 records = _fixed_getinnerframes(etb, context, tb_offset)
755 #print 'alex records:', records # dbg
760 #print 'alex records:', records # dbg
756 except:
761 except:
757
762
758 # FIXME: I've been getting many crash reports from python 2.3
763 # FIXME: I've been getting many crash reports from python 2.3
759 # users, traceable to inspect.py. If I can find a small test-case
764 # users, traceable to inspect.py. If I can find a small test-case
760 # to reproduce this, I should either write a better workaround or
765 # to reproduce this, I should either write a better workaround or
761 # file a bug report against inspect (if that's the real problem).
766 # file a bug report against inspect (if that's the real problem).
762 # So far, I haven't been able to find an isolated example to
767 # So far, I haven't been able to find an isolated example to
763 # reproduce the problem.
768 # reproduce the problem.
764 inspect_error()
769 inspect_error()
765 traceback.print_exc(file=self.ostream)
770 traceback.print_exc(file=self.ostream)
766 info('\nUnfortunately, your original traceback can not be constructed.\n')
771 info('\nUnfortunately, your original traceback can not be constructed.\n')
767 return ''
772 return ''
768
773
769 # build some color string templates outside these nested loops
774 # build some color string templates outside these nested loops
770 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
775 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
771 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
776 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
772 ColorsNormal)
777 ColorsNormal)
773 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
778 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
774 (Colors.vName, Colors.valEm, ColorsNormal)
779 (Colors.vName, Colors.valEm, ColorsNormal)
775 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
780 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
776 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
781 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
777 Colors.vName, ColorsNormal)
782 Colors.vName, ColorsNormal)
778 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
783 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
779 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
784 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
780 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
785 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
781 ColorsNormal)
786 ColorsNormal)
782
787
783 # now, loop over all records printing context and info
788 # now, loop over all records printing context and info
784 abspath = os.path.abspath
789 abspath = os.path.abspath
785 for frame, file, lnum, func, lines, index in records:
790 for frame, file, lnum, func, lines, index in records:
786 #print '*** record:',file,lnum,func,lines,index # dbg
791 #print '*** record:',file,lnum,func,lines,index # dbg
787 if not file:
792 if not file:
788 file = '?'
793 file = '?'
789 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
794 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
790 # Guess that filenames like <string> aren't real filenames, so
795 # Guess that filenames like <string> aren't real filenames, so
791 # don't call abspath on them.
796 # don't call abspath on them.
792 try:
797 try:
793 file = abspath(file)
798 file = abspath(file)
794 except OSError:
799 except OSError:
795 # Not sure if this can still happen: abspath now works with
800 # Not sure if this can still happen: abspath now works with
796 # file names like <string>
801 # file names like <string>
797 pass
802 pass
798 file = py3compat.cast_unicode(file, util_path.fs_encoding)
803 file = py3compat.cast_unicode(file, util_path.fs_encoding)
799 link = tpl_link % file
804 link = tpl_link % file
800 args, varargs, varkw, locals = inspect.getargvalues(frame)
805 args, varargs, varkw, locals = inspect.getargvalues(frame)
801
806
802 if func == '?':
807 if func == '?':
803 call = ''
808 call = ''
804 else:
809 else:
805 # Decide whether to include variable details or not
810 # Decide whether to include variable details or not
806 var_repr = self.include_vars and eqrepr or nullrepr
811 var_repr = self.include_vars and eqrepr or nullrepr
807 try:
812 try:
808 call = tpl_call % (func,inspect.formatargvalues(args,
813 call = tpl_call % (func,inspect.formatargvalues(args,
809 varargs, varkw,
814 varargs, varkw,
810 locals,formatvalue=var_repr))
815 locals,formatvalue=var_repr))
811 except KeyError:
816 except KeyError:
812 # This happens in situations like errors inside generator
817 # This happens in situations like errors inside generator
813 # expressions, where local variables are listed in the
818 # expressions, where local variables are listed in the
814 # line, but can't be extracted from the frame. I'm not
819 # line, but can't be extracted from the frame. I'm not
815 # 100% sure this isn't actually a bug in inspect itself,
820 # 100% sure this isn't actually a bug in inspect itself,
816 # but since there's no info for us to compute with, the
821 # but since there's no info for us to compute with, the
817 # best we can do is report the failure and move on. Here
822 # best we can do is report the failure and move on. Here
818 # we must *not* call any traceback construction again,
823 # we must *not* call any traceback construction again,
819 # because that would mess up use of %debug later on. So we
824 # because that would mess up use of %debug later on. So we
820 # simply report the failure and move on. The only
825 # simply report the failure and move on. The only
821 # limitation will be that this frame won't have locals
826 # limitation will be that this frame won't have locals
822 # listed in the call signature. Quite subtle problem...
827 # listed in the call signature. Quite subtle problem...
823 # I can't think of a good way to validate this in a unit
828 # I can't think of a good way to validate this in a unit
824 # test, but running a script consisting of:
829 # test, but running a script consisting of:
825 # dict( (k,v.strip()) for (k,v) in range(10) )
830 # dict( (k,v.strip()) for (k,v) in range(10) )
826 # will illustrate the error, if this exception catch is
831 # will illustrate the error, if this exception catch is
827 # disabled.
832 # disabled.
828 call = tpl_call_fail % func
833 call = tpl_call_fail % func
829
834
830 # Don't attempt to tokenize binary files.
835 # Don't attempt to tokenize binary files.
831 if file.endswith(('.so', '.pyd', '.dll')):
836 if file.endswith(('.so', '.pyd', '.dll')):
832 frames.append('%s %s\n' % (link,call))
837 frames.append('%s %s\n' % (link,call))
833 continue
838 continue
834 elif file.endswith(('.pyc','.pyo')):
839 elif file.endswith(('.pyc','.pyo')):
835 # Look up the corresponding source file.
840 # Look up the corresponding source file.
836 file = pyfile.source_from_cache(file)
841 file = pyfile.source_from_cache(file)
837
842
838 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
843 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
839 line = getline(file, lnum[0])
844 line = getline(file, lnum[0])
840 lnum[0] += 1
845 lnum[0] += 1
841 return line
846 return line
842
847
843 # Build the list of names on this line of code where the exception
848 # Build the list of names on this line of code where the exception
844 # occurred.
849 # occurred.
845 try:
850 try:
846 names = []
851 names = []
847 name_cont = False
852 name_cont = False
848
853
849 for token_type, token, start, end, line in generate_tokens(linereader):
854 for token_type, token, start, end, line in generate_tokens(linereader):
850 # build composite names
855 # build composite names
851 if token_type == tokenize.NAME and token not in keyword.kwlist:
856 if token_type == tokenize.NAME and token not in keyword.kwlist:
852 if name_cont:
857 if name_cont:
853 # Continuation of a dotted name
858 # Continuation of a dotted name
854 try:
859 try:
855 names[-1].append(token)
860 names[-1].append(token)
856 except IndexError:
861 except IndexError:
857 names.append([token])
862 names.append([token])
858 name_cont = False
863 name_cont = False
859 else:
864 else:
860 # Regular new names. We append everything, the caller
865 # Regular new names. We append everything, the caller
861 # will be responsible for pruning the list later. It's
866 # will be responsible for pruning the list later. It's
862 # very tricky to try to prune as we go, b/c composite
867 # very tricky to try to prune as we go, b/c composite
863 # names can fool us. The pruning at the end is easy
868 # names can fool us. The pruning at the end is easy
864 # to do (or the caller can print a list with repeated
869 # to do (or the caller can print a list with repeated
865 # names if so desired.
870 # names if so desired.
866 names.append([token])
871 names.append([token])
867 elif token == '.':
872 elif token == '.':
868 name_cont = True
873 name_cont = True
869 elif token_type == tokenize.NEWLINE:
874 elif token_type == tokenize.NEWLINE:
870 break
875 break
871
876
872 except (IndexError, UnicodeDecodeError):
877 except (IndexError, UnicodeDecodeError):
873 # signals exit of tokenizer
878 # signals exit of tokenizer
874 pass
879 pass
875 except tokenize.TokenError as msg:
880 except tokenize.TokenError as msg:
876 _m = ("An unexpected error occurred while tokenizing input\n"
881 _m = ("An unexpected error occurred while tokenizing input\n"
877 "The following traceback may be corrupted or invalid\n"
882 "The following traceback may be corrupted or invalid\n"
878 "The error message is: %s\n" % msg)
883 "The error message is: %s\n" % msg)
879 error(_m)
884 error(_m)
880
885
881 # Join composite names (e.g. "dict.fromkeys")
886 # Join composite names (e.g. "dict.fromkeys")
882 names = ['.'.join(n) for n in names]
887 names = ['.'.join(n) for n in names]
883 # prune names list of duplicates, but keep the right order
888 # prune names list of duplicates, but keep the right order
884 unique_names = uniq_stable(names)
889 unique_names = uniq_stable(names)
885
890
886 # Start loop over vars
891 # Start loop over vars
887 lvals = []
892 lvals = []
888 if self.include_vars:
893 if self.include_vars:
889 for name_full in unique_names:
894 for name_full in unique_names:
890 name_base = name_full.split('.',1)[0]
895 name_base = name_full.split('.',1)[0]
891 if name_base in frame.f_code.co_varnames:
896 if name_base in frame.f_code.co_varnames:
892 if name_base in locals:
897 if name_base in locals:
893 try:
898 try:
894 value = repr(eval(name_full,locals))
899 value = repr(eval(name_full,locals))
895 except:
900 except:
896 value = undefined
901 value = undefined
897 else:
902 else:
898 value = undefined
903 value = undefined
899 name = tpl_local_var % name_full
904 name = tpl_local_var % name_full
900 else:
905 else:
901 if name_base in frame.f_globals:
906 if name_base in frame.f_globals:
902 try:
907 try:
903 value = repr(eval(name_full,frame.f_globals))
908 value = repr(eval(name_full,frame.f_globals))
904 except:
909 except:
905 value = undefined
910 value = undefined
906 else:
911 else:
907 value = undefined
912 value = undefined
908 name = tpl_global_var % name_full
913 name = tpl_global_var % name_full
909 lvals.append(tpl_name_val % (name,value))
914 lvals.append(tpl_name_val % (name,value))
910 if lvals:
915 if lvals:
911 lvals = '%s%s' % (indent,em_normal.join(lvals))
916 lvals = '%s%s' % (indent,em_normal.join(lvals))
912 else:
917 else:
913 lvals = ''
918 lvals = ''
914
919
915 level = '%s %s\n' % (link,call)
920 level = '%s %s\n' % (link,call)
916
921
917 if index is None:
922 if index is None:
918 frames.append(level)
923 frames.append(level)
919 else:
924 else:
920 frames.append('%s%s' % (level,''.join(
925 frames.append('%s%s' % (level,''.join(
921 _format_traceback_lines(lnum,index,lines,Colors,lvals,
926 _format_traceback_lines(lnum,index,lines,Colors,lvals,
922 col_scheme))))
927 col_scheme))))
923
928
924 # Get (safely) a string form of the exception info
929 # Get (safely) a string form of the exception info
925 try:
930 try:
926 etype_str,evalue_str = map(str,(etype,evalue))
931 etype_str,evalue_str = map(str,(etype,evalue))
927 except:
932 except:
928 # User exception is improperly defined.
933 # User exception is improperly defined.
929 etype,evalue = str,sys.exc_info()[:2]
934 etype,evalue = str,sys.exc_info()[:2]
930 etype_str,evalue_str = map(str,(etype,evalue))
935 etype_str,evalue_str = map(str,(etype,evalue))
931 # ... and format it
936 # ... and format it
932 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
937 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
933 ColorsNormal, py3compat.cast_unicode(evalue_str))]
938 ColorsNormal, py3compat.cast_unicode(evalue_str))]
934 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
939 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
935 try:
940 try:
936 names = [w for w in dir(evalue) if isinstance(w, basestring)]
941 names = [w for w in dir(evalue) if isinstance(w, basestring)]
937 except:
942 except:
938 # Every now and then, an object with funny inernals blows up
943 # Every now and then, an object with funny inernals blows up
939 # when dir() is called on it. We do the best we can to report
944 # when dir() is called on it. We do the best we can to report
940 # the problem and continue
945 # the problem and continue
941 _m = '%sException reporting error (object with broken dir())%s:'
946 _m = '%sException reporting error (object with broken dir())%s:'
942 exception.append(_m % (Colors.excName,ColorsNormal))
947 exception.append(_m % (Colors.excName,ColorsNormal))
943 etype_str,evalue_str = map(str,sys.exc_info()[:2])
948 etype_str,evalue_str = map(str,sys.exc_info()[:2])
944 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
949 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
945 ColorsNormal, py3compat.cast_unicode(evalue_str)))
950 ColorsNormal, py3compat.cast_unicode(evalue_str)))
946 names = []
951 names = []
947 for name in names:
952 for name in names:
948 value = text_repr(getattr(evalue, name))
953 value = text_repr(getattr(evalue, name))
949 exception.append('\n%s%s = %s' % (indent, name, value))
954 exception.append('\n%s%s = %s' % (indent, name, value))
950
955
951 # vds: >>
956 # vds: >>
952 if records:
957 if records:
953 filepath, lnum = records[-1][1:3]
958 filepath, lnum = records[-1][1:3]
954 #print "file:", str(file), "linenb", str(lnum) # dbg
959 #print "file:", str(file), "linenb", str(lnum) # dbg
955 filepath = os.path.abspath(filepath)
960 filepath = os.path.abspath(filepath)
956 ipinst = ipapi.get()
961 ipinst = ipapi.get()
957 if ipinst is not None:
962 if ipinst is not None:
958 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
963 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
959 # vds: <<
964 # vds: <<
960
965
961 # return all our info assembled as a single string
966 # return all our info assembled as a single string
962 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
967 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
963 return [head] + frames + [''.join(exception[0])]
968 return [head] + frames + [''.join(exception[0])]
964
969
965 def debugger(self,force=False):
970 def debugger(self,force=False):
966 """Call up the pdb debugger if desired, always clean up the tb
971 """Call up the pdb debugger if desired, always clean up the tb
967 reference.
972 reference.
968
973
969 Keywords:
974 Keywords:
970
975
971 - force(False): by default, this routine checks the instance call_pdb
976 - force(False): by default, this routine checks the instance call_pdb
972 flag and does not actually invoke the debugger if the flag is false.
977 flag and does not actually invoke the debugger if the flag is false.
973 The 'force' option forces the debugger to activate even if the flag
978 The 'force' option forces the debugger to activate even if the flag
974 is false.
979 is false.
975
980
976 If the call_pdb flag is set, the pdb interactive debugger is
981 If the call_pdb flag is set, the pdb interactive debugger is
977 invoked. In all cases, the self.tb reference to the current traceback
982 invoked. In all cases, the self.tb reference to the current traceback
978 is deleted to prevent lingering references which hamper memory
983 is deleted to prevent lingering references which hamper memory
979 management.
984 management.
980
985
981 Note that each call to pdb() does an 'import readline', so if your app
986 Note that each call to pdb() does an 'import readline', so if your app
982 requires a special setup for the readline completers, you'll have to
987 requires a special setup for the readline completers, you'll have to
983 fix that by hand after invoking the exception handler."""
988 fix that by hand after invoking the exception handler."""
984
989
985 if force or self.call_pdb:
990 if force or self.call_pdb:
986 if self.pdb is None:
991 if self.pdb is None:
987 self.pdb = debugger.Pdb(
992 self.pdb = debugger.Pdb(
988 self.color_scheme_table.active_scheme_name)
993 self.color_scheme_table.active_scheme_name)
989 # the system displayhook may have changed, restore the original
994 # the system displayhook may have changed, restore the original
990 # for pdb
995 # for pdb
991 display_trap = DisplayTrap(hook=sys.__displayhook__)
996 display_trap = DisplayTrap(hook=sys.__displayhook__)
992 with display_trap:
997 with display_trap:
993 self.pdb.reset()
998 self.pdb.reset()
994 # Find the right frame so we don't pop up inside ipython itself
999 # Find the right frame so we don't pop up inside ipython itself
995 if hasattr(self,'tb') and self.tb is not None:
1000 if hasattr(self,'tb') and self.tb is not None:
996 etb = self.tb
1001 etb = self.tb
997 else:
1002 else:
998 etb = self.tb = sys.last_traceback
1003 etb = self.tb = sys.last_traceback
999 while self.tb is not None and self.tb.tb_next is not None:
1004 while self.tb is not None and self.tb.tb_next is not None:
1000 self.tb = self.tb.tb_next
1005 self.tb = self.tb.tb_next
1001 if etb and etb.tb_next:
1006 if etb and etb.tb_next:
1002 etb = etb.tb_next
1007 etb = etb.tb_next
1003 self.pdb.botframe = etb.tb_frame
1008 self.pdb.botframe = etb.tb_frame
1004 self.pdb.interaction(self.tb.tb_frame, self.tb)
1009 self.pdb.interaction(self.tb.tb_frame, self.tb)
1005
1010
1006 if hasattr(self,'tb'):
1011 if hasattr(self,'tb'):
1007 del self.tb
1012 del self.tb
1008
1013
1009 def handler(self, info=None):
1014 def handler(self, info=None):
1010 (etype, evalue, etb) = info or sys.exc_info()
1015 (etype, evalue, etb) = info or sys.exc_info()
1011 self.tb = etb
1016 self.tb = etb
1012 ostream = self.ostream
1017 ostream = self.ostream
1013 ostream.flush()
1018 ostream.flush()
1014 ostream.write(self.text(etype, evalue, etb))
1019 ostream.write(self.text(etype, evalue, etb))
1015 ostream.write('\n')
1020 ostream.write('\n')
1016 ostream.flush()
1021 ostream.flush()
1017
1022
1018 # Changed so an instance can just be called as VerboseTB_inst() and print
1023 # Changed so an instance can just be called as VerboseTB_inst() and print
1019 # out the right info on its own.
1024 # out the right info on its own.
1020 def __call__(self, etype=None, evalue=None, etb=None):
1025 def __call__(self, etype=None, evalue=None, etb=None):
1021 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1026 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1022 if etb is None:
1027 if etb is None:
1023 self.handler()
1028 self.handler()
1024 else:
1029 else:
1025 self.handler((etype, evalue, etb))
1030 self.handler((etype, evalue, etb))
1026 try:
1031 try:
1027 self.debugger()
1032 self.debugger()
1028 except KeyboardInterrupt:
1033 except KeyboardInterrupt:
1029 print "\nKeyboardInterrupt"
1034 print "\nKeyboardInterrupt"
1030
1035
1031 #----------------------------------------------------------------------------
1036 #----------------------------------------------------------------------------
1032 class FormattedTB(VerboseTB, ListTB):
1037 class FormattedTB(VerboseTB, ListTB):
1033 """Subclass ListTB but allow calling with a traceback.
1038 """Subclass ListTB but allow calling with a traceback.
1034
1039
1035 It can thus be used as a sys.excepthook for Python > 2.1.
1040 It can thus be used as a sys.excepthook for Python > 2.1.
1036
1041
1037 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1042 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1038
1043
1039 Allows a tb_offset to be specified. This is useful for situations where
1044 Allows a tb_offset to be specified. This is useful for situations where
1040 one needs to remove a number of topmost frames from the traceback (such as
1045 one needs to remove a number of topmost frames from the traceback (such as
1041 occurs with python programs that themselves execute other python code,
1046 occurs with python programs that themselves execute other python code,
1042 like Python shells). """
1047 like Python shells). """
1043
1048
1044 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1049 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1045 ostream=None,
1050 ostream=None,
1046 tb_offset=0, long_header=False, include_vars=False,
1051 tb_offset=0, long_header=False, include_vars=False,
1047 check_cache=None):
1052 check_cache=None):
1048
1053
1049 # NEVER change the order of this list. Put new modes at the end:
1054 # NEVER change the order of this list. Put new modes at the end:
1050 self.valid_modes = ['Plain','Context','Verbose']
1055 self.valid_modes = ['Plain','Context','Verbose']
1051 self.verbose_modes = self.valid_modes[1:3]
1056 self.verbose_modes = self.valid_modes[1:3]
1052
1057
1053 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1058 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1054 ostream=ostream, tb_offset=tb_offset,
1059 ostream=ostream, tb_offset=tb_offset,
1055 long_header=long_header, include_vars=include_vars,
1060 long_header=long_header, include_vars=include_vars,
1056 check_cache=check_cache)
1061 check_cache=check_cache)
1057
1062
1058 # Different types of tracebacks are joined with different separators to
1063 # Different types of tracebacks are joined with different separators to
1059 # form a single string. They are taken from this dict
1064 # form a single string. They are taken from this dict
1060 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1065 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1061 # set_mode also sets the tb_join_char attribute
1066 # set_mode also sets the tb_join_char attribute
1062 self.set_mode(mode)
1067 self.set_mode(mode)
1063
1068
1064 def _extract_tb(self,tb):
1069 def _extract_tb(self,tb):
1065 if tb:
1070 if tb:
1066 return traceback.extract_tb(tb)
1071 return traceback.extract_tb(tb)
1067 else:
1072 else:
1068 return None
1073 return None
1069
1074
1070 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1075 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1071 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1076 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1072 mode = self.mode
1077 mode = self.mode
1073 if mode in self.verbose_modes:
1078 if mode in self.verbose_modes:
1074 # Verbose modes need a full traceback
1079 # Verbose modes need a full traceback
1075 return VerboseTB.structured_traceback(
1080 return VerboseTB.structured_traceback(
1076 self, etype, value, tb, tb_offset, context
1081 self, etype, value, tb, tb_offset, context
1077 )
1082 )
1078 else:
1083 else:
1079 # We must check the source cache because otherwise we can print
1084 # We must check the source cache because otherwise we can print
1080 # out-of-date source code.
1085 # out-of-date source code.
1081 self.check_cache()
1086 self.check_cache()
1082 # Now we can extract and format the exception
1087 # Now we can extract and format the exception
1083 elist = self._extract_tb(tb)
1088 elist = self._extract_tb(tb)
1084 return ListTB.structured_traceback(
1089 return ListTB.structured_traceback(
1085 self, etype, value, elist, tb_offset, context
1090 self, etype, value, elist, tb_offset, context
1086 )
1091 )
1087
1092
1088 def stb2text(self, stb):
1093 def stb2text(self, stb):
1089 """Convert a structured traceback (a list) to a string."""
1094 """Convert a structured traceback (a list) to a string."""
1090 return self.tb_join_char.join(stb)
1095 return self.tb_join_char.join(stb)
1091
1096
1092
1097
1093 def set_mode(self,mode=None):
1098 def set_mode(self,mode=None):
1094 """Switch to the desired mode.
1099 """Switch to the desired mode.
1095
1100
1096 If mode is not specified, cycles through the available modes."""
1101 If mode is not specified, cycles through the available modes."""
1097
1102
1098 if not mode:
1103 if not mode:
1099 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1104 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1100 len(self.valid_modes)
1105 len(self.valid_modes)
1101 self.mode = self.valid_modes[new_idx]
1106 self.mode = self.valid_modes[new_idx]
1102 elif mode not in self.valid_modes:
1107 elif mode not in self.valid_modes:
1103 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1108 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1104 'Valid modes: '+str(self.valid_modes))
1109 'Valid modes: '+str(self.valid_modes))
1105 else:
1110 else:
1106 self.mode = mode
1111 self.mode = mode
1107 # include variable details only in 'Verbose' mode
1112 # include variable details only in 'Verbose' mode
1108 self.include_vars = (self.mode == self.valid_modes[2])
1113 self.include_vars = (self.mode == self.valid_modes[2])
1109 # Set the join character for generating text tracebacks
1114 # Set the join character for generating text tracebacks
1110 self.tb_join_char = self._join_chars[self.mode]
1115 self.tb_join_char = self._join_chars[self.mode]
1111
1116
1112 # some convenient shorcuts
1117 # some convenient shorcuts
1113 def plain(self):
1118 def plain(self):
1114 self.set_mode(self.valid_modes[0])
1119 self.set_mode(self.valid_modes[0])
1115
1120
1116 def context(self):
1121 def context(self):
1117 self.set_mode(self.valid_modes[1])
1122 self.set_mode(self.valid_modes[1])
1118
1123
1119 def verbose(self):
1124 def verbose(self):
1120 self.set_mode(self.valid_modes[2])
1125 self.set_mode(self.valid_modes[2])
1121
1126
1122 #----------------------------------------------------------------------------
1127 #----------------------------------------------------------------------------
1123 class AutoFormattedTB(FormattedTB):
1128 class AutoFormattedTB(FormattedTB):
1124 """A traceback printer which can be called on the fly.
1129 """A traceback printer which can be called on the fly.
1125
1130
1126 It will find out about exceptions by itself.
1131 It will find out about exceptions by itself.
1127
1132
1128 A brief example:
1133 A brief example:
1129
1134
1130 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1135 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1131 try:
1136 try:
1132 ...
1137 ...
1133 except:
1138 except:
1134 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1139 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1135 """
1140 """
1136
1141
1137 def __call__(self,etype=None,evalue=None,etb=None,
1142 def __call__(self,etype=None,evalue=None,etb=None,
1138 out=None,tb_offset=None):
1143 out=None,tb_offset=None):
1139 """Print out a formatted exception traceback.
1144 """Print out a formatted exception traceback.
1140
1145
1141 Optional arguments:
1146 Optional arguments:
1142 - out: an open file-like object to direct output to.
1147 - out: an open file-like object to direct output to.
1143
1148
1144 - tb_offset: the number of frames to skip over in the stack, on a
1149 - tb_offset: the number of frames to skip over in the stack, on a
1145 per-call basis (this overrides temporarily the instance's tb_offset
1150 per-call basis (this overrides temporarily the instance's tb_offset
1146 given at initialization time. """
1151 given at initialization time. """
1147
1152
1148
1153
1149 if out is None:
1154 if out is None:
1150 out = self.ostream
1155 out = self.ostream
1151 out.flush()
1156 out.flush()
1152 out.write(self.text(etype, evalue, etb, tb_offset))
1157 out.write(self.text(etype, evalue, etb, tb_offset))
1153 out.write('\n')
1158 out.write('\n')
1154 out.flush()
1159 out.flush()
1155 # FIXME: we should remove the auto pdb behavior from here and leave
1160 # FIXME: we should remove the auto pdb behavior from here and leave
1156 # that to the clients.
1161 # that to the clients.
1157 try:
1162 try:
1158 self.debugger()
1163 self.debugger()
1159 except KeyboardInterrupt:
1164 except KeyboardInterrupt:
1160 print "\nKeyboardInterrupt"
1165 print "\nKeyboardInterrupt"
1161
1166
1162 def structured_traceback(self, etype=None, value=None, tb=None,
1167 def structured_traceback(self, etype=None, value=None, tb=None,
1163 tb_offset=None, context=5):
1168 tb_offset=None, context=5):
1164 if etype is None:
1169 if etype is None:
1165 etype,value,tb = sys.exc_info()
1170 etype,value,tb = sys.exc_info()
1166 self.tb = tb
1171 self.tb = tb
1167 return FormattedTB.structured_traceback(
1172 return FormattedTB.structured_traceback(
1168 self, etype, value, tb, tb_offset, context)
1173 self, etype, value, tb, tb_offset, context)
1169
1174
1170 #---------------------------------------------------------------------------
1175 #---------------------------------------------------------------------------
1171
1176
1172 # A simple class to preserve Nathan's original functionality.
1177 # A simple class to preserve Nathan's original functionality.
1173 class ColorTB(FormattedTB):
1178 class ColorTB(FormattedTB):
1174 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1179 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1175 def __init__(self,color_scheme='Linux',call_pdb=0):
1180 def __init__(self,color_scheme='Linux',call_pdb=0):
1176 FormattedTB.__init__(self,color_scheme=color_scheme,
1181 FormattedTB.__init__(self,color_scheme=color_scheme,
1177 call_pdb=call_pdb)
1182 call_pdb=call_pdb)
1178
1183
1179
1184
1180 class SyntaxTB(ListTB):
1185 class SyntaxTB(ListTB):
1181 """Extension which holds some state: the last exception value"""
1186 """Extension which holds some state: the last exception value"""
1182
1187
1183 def __init__(self,color_scheme = 'NoColor'):
1188 def __init__(self,color_scheme = 'NoColor'):
1184 ListTB.__init__(self,color_scheme)
1189 ListTB.__init__(self,color_scheme)
1185 self.last_syntax_error = None
1190 self.last_syntax_error = None
1186
1191
1187 def __call__(self, etype, value, elist):
1192 def __call__(self, etype, value, elist):
1188 self.last_syntax_error = value
1193 self.last_syntax_error = value
1189 ListTB.__call__(self,etype,value,elist)
1194 ListTB.__call__(self,etype,value,elist)
1190
1195
1191 def clear_err_state(self):
1196 def clear_err_state(self):
1192 """Return the current error state and clear it"""
1197 """Return the current error state and clear it"""
1193 e = self.last_syntax_error
1198 e = self.last_syntax_error
1194 self.last_syntax_error = None
1199 self.last_syntax_error = None
1195 return e
1200 return e
1196
1201
1197 def stb2text(self, stb):
1202 def stb2text(self, stb):
1198 """Convert a structured traceback (a list) to a string."""
1203 """Convert a structured traceback (a list) to a string."""
1199 return ''.join(stb)
1204 return ''.join(stb)
1200
1205
1201
1206
1202 #----------------------------------------------------------------------------
1207 #----------------------------------------------------------------------------
1203 # module testing (minimal)
1208 # module testing (minimal)
1204 if __name__ == "__main__":
1209 if __name__ == "__main__":
1205 def spam(c, d_e):
1210 def spam(c, d_e):
1206 (d, e) = d_e
1211 (d, e) = d_e
1207 x = c + d
1212 x = c + d
1208 y = c * d
1213 y = c * d
1209 foo(x, y)
1214 foo(x, y)
1210
1215
1211 def foo(a, b, bar=1):
1216 def foo(a, b, bar=1):
1212 eggs(a, b + bar)
1217 eggs(a, b + bar)
1213
1218
1214 def eggs(f, g, z=globals()):
1219 def eggs(f, g, z=globals()):
1215 h = f + g
1220 h = f + g
1216 i = f - g
1221 i = f - g
1217 return h / i
1222 return h / i
1218
1223
1219 print ''
1224 print ''
1220 print '*** Before ***'
1225 print '*** Before ***'
1221 try:
1226 try:
1222 print spam(1, (2, 3))
1227 print spam(1, (2, 3))
1223 except:
1228 except:
1224 traceback.print_exc()
1229 traceback.print_exc()
1225 print ''
1230 print ''
1226
1231
1227 handler = ColorTB()
1232 handler = ColorTB()
1228 print '*** ColorTB ***'
1233 print '*** ColorTB ***'
1229 try:
1234 try:
1230 print spam(1, (2, 3))
1235 print spam(1, (2, 3))
1231 except:
1236 except:
1232 handler(*sys.exc_info())
1237 handler(*sys.exc_info())
1233 print ''
1238 print ''
1234
1239
1235 handler = VerboseTB()
1240 handler = VerboseTB()
1236 print '*** VerboseTB ***'
1241 print '*** VerboseTB ***'
1237 try:
1242 try:
1238 print spam(1, (2, 3))
1243 print spam(1, (2, 3))
1239 except:
1244 except:
1240 handler(*sys.exc_info())
1245 handler(*sys.exc_info())
1241 print ''
1246 print ''
1242
1247
@@ -1,578 +1,583 b''
1 from __future__ import unicode_literals
2
3
4 """Module for interactive demos using IPython.
1 """Module for interactive demos using IPython.
5
2
6 This module implements a few classes for running Python scripts interactively
3 This module implements a few classes for running Python scripts interactively
7 in IPython for demonstrations. With very simple markup (a few tags in
4 in IPython for demonstrations. With very simple markup (a few tags in
8 comments), you can control points where the script stops executing and returns
5 comments), you can control points where the script stops executing and returns
9 control to IPython.
6 control to IPython.
10
7
11
8
12 Provided classes
9 Provided classes
13 ================
10 ----------------
14
11
15 The classes are (see their docstrings for further details):
12 The classes are (see their docstrings for further details):
16
13
17 - Demo: pure python demos
14 - Demo: pure python demos
18
15
19 - IPythonDemo: demos with input to be processed by IPython as if it had been
16 - IPythonDemo: demos with input to be processed by IPython as if it had been
20 typed interactively (so magics work, as well as any other special syntax you
17 typed interactively (so magics work, as well as any other special syntax you
21 may have added via input prefilters).
18 may have added via input prefilters).
22
19
23 - LineDemo: single-line version of the Demo class. These demos are executed
20 - LineDemo: single-line version of the Demo class. These demos are executed
24 one line at a time, and require no markup.
21 one line at a time, and require no markup.
25
22
26 - IPythonLineDemo: IPython version of the LineDemo class (the demo is
23 - IPythonLineDemo: IPython version of the LineDemo class (the demo is
27 executed a line at a time, but processed via IPython).
24 executed a line at a time, but processed via IPython).
28
25
29 - ClearMixin: mixin to make Demo classes with less visual clutter. It
26 - ClearMixin: mixin to make Demo classes with less visual clutter. It
30 declares an empty marquee and a pre_cmd that clears the screen before each
27 declares an empty marquee and a pre_cmd that clears the screen before each
31 block (see Subclassing below).
28 block (see Subclassing below).
32
29
33 - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
30 - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
34 classes.
31 classes.
35
32
33 Inheritance diagram:
34
35 .. inheritance-diagram:: IPython.lib.demo
36 :parts: 3
36
37
37 Subclassing
38 Subclassing
38 ===========
39 -----------
39
40
40 The classes here all include a few methods meant to make customization by
41 The classes here all include a few methods meant to make customization by
41 subclassing more convenient. Their docstrings below have some more details:
42 subclassing more convenient. Their docstrings below have some more details:
42
43
43 - marquee(): generates a marquee to provide visible on-screen markers at each
44 - marquee(): generates a marquee to provide visible on-screen markers at each
44 block start and end.
45 block start and end.
45
46
46 - pre_cmd(): run right before the execution of each block.
47 - pre_cmd(): run right before the execution of each block.
47
48
48 - post_cmd(): run right after the execution of each block. If the block
49 - post_cmd(): run right after the execution of each block. If the block
49 raises an exception, this is NOT called.
50 raises an exception, this is NOT called.
50
51
51
52
52 Operation
53 Operation
53 =========
54 ---------
54
55
55 The file is run in its own empty namespace (though you can pass it a string of
56 The file is run in its own empty namespace (though you can pass it a string of
56 arguments as if in a command line environment, and it will see those as
57 arguments as if in a command line environment, and it will see those as
57 sys.argv). But at each stop, the global IPython namespace is updated with the
58 sys.argv). But at each stop, the global IPython namespace is updated with the
58 current internal demo namespace, so you can work interactively with the data
59 current internal demo namespace, so you can work interactively with the data
59 accumulated so far.
60 accumulated so far.
60
61
61 By default, each block of code is printed (with syntax highlighting) before
62 By default, each block of code is printed (with syntax highlighting) before
62 executing it and you have to confirm execution. This is intended to show the
63 executing it and you have to confirm execution. This is intended to show the
63 code to an audience first so you can discuss it, and only proceed with
64 code to an audience first so you can discuss it, and only proceed with
64 execution once you agree. There are a few tags which allow you to modify this
65 execution once you agree. There are a few tags which allow you to modify this
65 behavior.
66 behavior.
66
67
67 The supported tags are:
68 The supported tags are:
68
69
69 # <demo> stop
70 # <demo> stop
70
71
71 Defines block boundaries, the points where IPython stops execution of the
72 Defines block boundaries, the points where IPython stops execution of the
72 file and returns to the interactive prompt.
73 file and returns to the interactive prompt.
73
74
74 You can optionally mark the stop tag with extra dashes before and after the
75 You can optionally mark the stop tag with extra dashes before and after the
75 word 'stop', to help visually distinguish the blocks in a text editor:
76 word 'stop', to help visually distinguish the blocks in a text editor:
76
77
77 # <demo> --- stop ---
78 # <demo> --- stop ---
78
79
79
80
80 # <demo> silent
81 # <demo> silent
81
82
82 Make a block execute silently (and hence automatically). Typically used in
83 Make a block execute silently (and hence automatically). Typically used in
83 cases where you have some boilerplate or initialization code which you need
84 cases where you have some boilerplate or initialization code which you need
84 executed but do not want to be seen in the demo.
85 executed but do not want to be seen in the demo.
85
86
86 # <demo> auto
87 # <demo> auto
87
88
88 Make a block execute automatically, but still being printed. Useful for
89 Make a block execute automatically, but still being printed. Useful for
89 simple code which does not warrant discussion, since it avoids the extra
90 simple code which does not warrant discussion, since it avoids the extra
90 manual confirmation.
91 manual confirmation.
91
92
92 # <demo> auto_all
93 # <demo> auto_all
93
94
94 This tag can _only_ be in the first block, and if given it overrides the
95 This tag can _only_ be in the first block, and if given it overrides the
95 individual auto tags to make the whole demo fully automatic (no block asks
96 individual auto tags to make the whole demo fully automatic (no block asks
96 for confirmation). It can also be given at creation time (or the attribute
97 for confirmation). It can also be given at creation time (or the attribute
97 set later) to override what's in the file.
98 set later) to override what's in the file.
98
99
99 While _any_ python file can be run as a Demo instance, if there are no stop
100 While _any_ python file can be run as a Demo instance, if there are no stop
100 tags the whole file will run in a single block (no different that calling
101 tags the whole file will run in a single block (no different that calling
101 first %pycat and then %run). The minimal markup to make this useful is to
102 first %pycat and then %run). The minimal markup to make this useful is to
102 place a set of stop tags; the other tags are only there to let you fine-tune
103 place a set of stop tags; the other tags are only there to let you fine-tune
103 the execution.
104 the execution.
104
105
105 This is probably best explained with the simple example file below. You can
106 This is probably best explained with the simple example file below. You can
106 copy this into a file named ex_demo.py, and try running it via:
107 copy this into a file named ex_demo.py, and try running it via:
107
108
108 from IPython.demo import Demo
109 from IPython.demo import Demo
109 d = Demo('ex_demo.py')
110 d = Demo('ex_demo.py')
110 d() <--- Call the d object (omit the parens if you have autocall set to 2).
111 d() <--- Call the d object (omit the parens if you have autocall set to 2).
111
112
112 Each time you call the demo object, it runs the next block. The demo object
113 Each time you call the demo object, it runs the next block. The demo object
113 has a few useful methods for navigation, like again(), edit(), jump(), seek()
114 has a few useful methods for navigation, like again(), edit(), jump(), seek()
114 and back(). It can be reset for a new run via reset() or reloaded from disk
115 and back(). It can be reset for a new run via reset() or reloaded from disk
115 (in case you've edited the source) via reload(). See their docstrings below.
116 (in case you've edited the source) via reload(). See their docstrings below.
116
117
117 Note: To make this simpler to explore, a file called "demo-exercizer.py" has
118 Note: To make this simpler to explore, a file called "demo-exercizer.py" has
118 been added to the "docs/examples/core" directory. Just cd to this directory in
119 been added to the "docs/examples/core" directory. Just cd to this directory in
119 an IPython session, and type::
120 an IPython session, and type::
120
121
121 %run demo-exercizer.py
122 %run demo-exercizer.py
122
123
123 and then follow the directions.
124 and then follow the directions.
124
125
125 Example
126 Example
126 =======
127 -------
127
128
128 The following is a very simple example of a valid demo file.
129 The following is a very simple example of a valid demo file.
129
130
130 #################### EXAMPLE DEMO <ex_demo.py> ###############################
131 ::
131 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
132
132
133 print 'Hello, welcome to an interactive IPython demo.'
133 #################### EXAMPLE DEMO <ex_demo.py> ###############################
134 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
134
135
135 # The mark below defines a block boundary, which is a point where IPython will
136 print 'Hello, welcome to an interactive IPython demo.'
136 # stop execution and return to the interactive prompt. The dashes are actually
137 # optional and used only as a visual aid to clearly separate blocks while
138 # editing the demo code.
139 # <demo> stop
140
137
141 x = 1
138 # The mark below defines a block boundary, which is a point where IPython will
142 y = 2
139 # stop execution and return to the interactive prompt. The dashes are actually
140 # optional and used only as a visual aid to clearly separate blocks while
141 # editing the demo code.
142 # <demo> stop
143
143
144 # <demo> stop
144 x = 1
145 y = 2
145
146
146 # the mark below makes this block as silent
147 # <demo> stop
147 # <demo> silent
148
148
149 print 'This is a silent block, which gets executed but not printed.'
149 # the mark below makes this block as silent
150 # <demo> silent
150
151
151 # <demo> stop
152 print 'This is a silent block, which gets executed but not printed.'
152 # <demo> auto
153 print 'This is an automatic block.'
154 print 'It is executed without asking for confirmation, but printed.'
155 z = x+y
156
153
157 print 'z=',x
154 # <demo> stop
155 # <demo> auto
156 print 'This is an automatic block.'
157 print 'It is executed without asking for confirmation, but printed.'
158 z = x+y
158
159
159 # <demo> stop
160 print 'z=',x
160 # This is just another normal block.
161 print 'z is now:', z
162
161
163 print 'bye!'
162 # <demo> stop
164 ################### END EXAMPLE DEMO <ex_demo.py> ############################
163 # This is just another normal block.
164 print 'z is now:', z
165
166 print 'bye!'
167 ################### END EXAMPLE DEMO <ex_demo.py> ############################
165 """
168 """
166
169
170 from __future__ import unicode_literals
171
167 #*****************************************************************************
172 #*****************************************************************************
168 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
173 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
169 #
174 #
170 # Distributed under the terms of the BSD License. The full license is in
175 # Distributed under the terms of the BSD License. The full license is in
171 # the file COPYING, distributed as part of this software.
176 # the file COPYING, distributed as part of this software.
172 #
177 #
173 #*****************************************************************************
178 #*****************************************************************************
174 from __future__ import print_function
179 from __future__ import print_function
175
180
176 import os
181 import os
177 import re
182 import re
178 import shlex
183 import shlex
179 import sys
184 import sys
180
185
181 from IPython.utils.PyColorize import Parser
186 from IPython.utils.PyColorize import Parser
182 from IPython.utils import io
187 from IPython.utils import io
183 from IPython.utils.io import file_read, file_readlines
188 from IPython.utils.io import file_read, file_readlines
184 from IPython.utils.text import marquee
189 from IPython.utils.text import marquee
185 from IPython.utils import openpy
190 from IPython.utils import openpy
186 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
191 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
187
192
188 class DemoError(Exception): pass
193 class DemoError(Exception): pass
189
194
190 def re_mark(mark):
195 def re_mark(mark):
191 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
196 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
192
197
193 class Demo(object):
198 class Demo(object):
194
199
195 re_stop = re_mark('-*\s?stop\s?-*')
200 re_stop = re_mark('-*\s?stop\s?-*')
196 re_silent = re_mark('silent')
201 re_silent = re_mark('silent')
197 re_auto = re_mark('auto')
202 re_auto = re_mark('auto')
198 re_auto_all = re_mark('auto_all')
203 re_auto_all = re_mark('auto_all')
199
204
200 def __init__(self,src,title='',arg_str='',auto_all=None):
205 def __init__(self,src,title='',arg_str='',auto_all=None):
201 """Make a new demo object. To run the demo, simply call the object.
206 """Make a new demo object. To run the demo, simply call the object.
202
207
203 See the module docstring for full details and an example (you can use
208 See the module docstring for full details and an example (you can use
204 IPython.Demo? in IPython to see it).
209 IPython.Demo? in IPython to see it).
205
210
206 Inputs:
211 Inputs:
207
212
208 - src is either a file, or file-like object, or a
213 - src is either a file, or file-like object, or a
209 string that can be resolved to a filename.
214 string that can be resolved to a filename.
210
215
211 Optional inputs:
216 Optional inputs:
212
217
213 - title: a string to use as the demo name. Of most use when the demo
218 - title: a string to use as the demo name. Of most use when the demo
214 you are making comes from an object that has no filename, or if you
219 you are making comes from an object that has no filename, or if you
215 want an alternate denotation distinct from the filename.
220 want an alternate denotation distinct from the filename.
216
221
217 - arg_str(''): a string of arguments, internally converted to a list
222 - arg_str(''): a string of arguments, internally converted to a list
218 just like sys.argv, so the demo script can see a similar
223 just like sys.argv, so the demo script can see a similar
219 environment.
224 environment.
220
225
221 - auto_all(None): global flag to run all blocks automatically without
226 - auto_all(None): global flag to run all blocks automatically without
222 confirmation. This attribute overrides the block-level tags and
227 confirmation. This attribute overrides the block-level tags and
223 applies to the whole demo. It is an attribute of the object, and
228 applies to the whole demo. It is an attribute of the object, and
224 can be changed at runtime simply by reassigning it to a boolean
229 can be changed at runtime simply by reassigning it to a boolean
225 value.
230 value.
226 """
231 """
227 if hasattr(src, "read"):
232 if hasattr(src, "read"):
228 # It seems to be a file or a file-like object
233 # It seems to be a file or a file-like object
229 self.fname = "from a file-like object"
234 self.fname = "from a file-like object"
230 if title == '':
235 if title == '':
231 self.title = "from a file-like object"
236 self.title = "from a file-like object"
232 else:
237 else:
233 self.title = title
238 self.title = title
234 else:
239 else:
235 # Assume it's a string or something that can be converted to one
240 # Assume it's a string or something that can be converted to one
236 self.fname = src
241 self.fname = src
237 if title == '':
242 if title == '':
238 (filepath, filename) = os.path.split(src)
243 (filepath, filename) = os.path.split(src)
239 self.title = filename
244 self.title = filename
240 else:
245 else:
241 self.title = title
246 self.title = title
242 self.sys_argv = [src] + shlex.split(arg_str)
247 self.sys_argv = [src] + shlex.split(arg_str)
243 self.auto_all = auto_all
248 self.auto_all = auto_all
244 self.src = src
249 self.src = src
245
250
246 # get a few things from ipython. While it's a bit ugly design-wise,
251 # get a few things from ipython. While it's a bit ugly design-wise,
247 # it ensures that things like color scheme and the like are always in
252 # it ensures that things like color scheme and the like are always in
248 # sync with the ipython mode being used. This class is only meant to
253 # sync with the ipython mode being used. This class is only meant to
249 # be used inside ipython anyways, so it's OK.
254 # be used inside ipython anyways, so it's OK.
250 ip = get_ipython() # this is in builtins whenever IPython is running
255 ip = get_ipython() # this is in builtins whenever IPython is running
251 self.ip_ns = ip.user_ns
256 self.ip_ns = ip.user_ns
252 self.ip_colorize = ip.pycolorize
257 self.ip_colorize = ip.pycolorize
253 self.ip_showtb = ip.showtraceback
258 self.ip_showtb = ip.showtraceback
254 self.ip_run_cell = ip.run_cell
259 self.ip_run_cell = ip.run_cell
255 self.shell = ip
260 self.shell = ip
256
261
257 # load user data and initialize data structures
262 # load user data and initialize data structures
258 self.reload()
263 self.reload()
259
264
260 def fload(self):
265 def fload(self):
261 """Load file object."""
266 """Load file object."""
262 # read data and parse into blocks
267 # read data and parse into blocks
263 if hasattr(self, 'fobj') and self.fobj is not None:
268 if hasattr(self, 'fobj') and self.fobj is not None:
264 self.fobj.close()
269 self.fobj.close()
265 if hasattr(self.src, "read"):
270 if hasattr(self.src, "read"):
266 # It seems to be a file or a file-like object
271 # It seems to be a file or a file-like object
267 self.fobj = self.src
272 self.fobj = self.src
268 else:
273 else:
269 # Assume it's a string or something that can be converted to one
274 # Assume it's a string or something that can be converted to one
270 self.fobj = openpy.open(self.fname)
275 self.fobj = openpy.open(self.fname)
271
276
272 def reload(self):
277 def reload(self):
273 """Reload source from disk and initialize state."""
278 """Reload source from disk and initialize state."""
274 self.fload()
279 self.fload()
275
280
276 self.src = "".join(openpy.strip_encoding_cookie(self.fobj))
281 self.src = "".join(openpy.strip_encoding_cookie(self.fobj))
277 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
282 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
278 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
283 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
279 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
284 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
280
285
281 # if auto_all is not given (def. None), we read it from the file
286 # if auto_all is not given (def. None), we read it from the file
282 if self.auto_all is None:
287 if self.auto_all is None:
283 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
288 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
284 else:
289 else:
285 self.auto_all = bool(self.auto_all)
290 self.auto_all = bool(self.auto_all)
286
291
287 # Clean the sources from all markup so it doesn't get displayed when
292 # Clean the sources from all markup so it doesn't get displayed when
288 # running the demo
293 # running the demo
289 src_blocks = []
294 src_blocks = []
290 auto_strip = lambda s: self.re_auto.sub('',s)
295 auto_strip = lambda s: self.re_auto.sub('',s)
291 for i,b in enumerate(src_b):
296 for i,b in enumerate(src_b):
292 if self._auto[i]:
297 if self._auto[i]:
293 src_blocks.append(auto_strip(b))
298 src_blocks.append(auto_strip(b))
294 else:
299 else:
295 src_blocks.append(b)
300 src_blocks.append(b)
296 # remove the auto_all marker
301 # remove the auto_all marker
297 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
302 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
298
303
299 self.nblocks = len(src_blocks)
304 self.nblocks = len(src_blocks)
300 self.src_blocks = src_blocks
305 self.src_blocks = src_blocks
301
306
302 # also build syntax-highlighted source
307 # also build syntax-highlighted source
303 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
308 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
304
309
305 # ensure clean namespace and seek offset
310 # ensure clean namespace and seek offset
306 self.reset()
311 self.reset()
307
312
308 def reset(self):
313 def reset(self):
309 """Reset the namespace and seek pointer to restart the demo"""
314 """Reset the namespace and seek pointer to restart the demo"""
310 self.user_ns = {}
315 self.user_ns = {}
311 self.finished = False
316 self.finished = False
312 self.block_index = 0
317 self.block_index = 0
313
318
314 def _validate_index(self,index):
319 def _validate_index(self,index):
315 if index<0 or index>=self.nblocks:
320 if index<0 or index>=self.nblocks:
316 raise ValueError('invalid block index %s' % index)
321 raise ValueError('invalid block index %s' % index)
317
322
318 def _get_index(self,index):
323 def _get_index(self,index):
319 """Get the current block index, validating and checking status.
324 """Get the current block index, validating and checking status.
320
325
321 Returns None if the demo is finished"""
326 Returns None if the demo is finished"""
322
327
323 if index is None:
328 if index is None:
324 if self.finished:
329 if self.finished:
325 print('Demo finished. Use <demo_name>.reset() if you want to rerun it.', file=io.stdout)
330 print('Demo finished. Use <demo_name>.reset() if you want to rerun it.', file=io.stdout)
326 return None
331 return None
327 index = self.block_index
332 index = self.block_index
328 else:
333 else:
329 self._validate_index(index)
334 self._validate_index(index)
330 return index
335 return index
331
336
332 def seek(self,index):
337 def seek(self,index):
333 """Move the current seek pointer to the given block.
338 """Move the current seek pointer to the given block.
334
339
335 You can use negative indices to seek from the end, with identical
340 You can use negative indices to seek from the end, with identical
336 semantics to those of Python lists."""
341 semantics to those of Python lists."""
337 if index<0:
342 if index<0:
338 index = self.nblocks + index
343 index = self.nblocks + index
339 self._validate_index(index)
344 self._validate_index(index)
340 self.block_index = index
345 self.block_index = index
341 self.finished = False
346 self.finished = False
342
347
343 def back(self,num=1):
348 def back(self,num=1):
344 """Move the seek pointer back num blocks (default is 1)."""
349 """Move the seek pointer back num blocks (default is 1)."""
345 self.seek(self.block_index-num)
350 self.seek(self.block_index-num)
346
351
347 def jump(self,num=1):
352 def jump(self,num=1):
348 """Jump a given number of blocks relative to the current one.
353 """Jump a given number of blocks relative to the current one.
349
354
350 The offset can be positive or negative, defaults to 1."""
355 The offset can be positive or negative, defaults to 1."""
351 self.seek(self.block_index+num)
356 self.seek(self.block_index+num)
352
357
353 def again(self):
358 def again(self):
354 """Move the seek pointer back one block and re-execute."""
359 """Move the seek pointer back one block and re-execute."""
355 self.back(1)
360 self.back(1)
356 self()
361 self()
357
362
358 def edit(self,index=None):
363 def edit(self,index=None):
359 """Edit a block.
364 """Edit a block.
360
365
361 If no number is given, use the last block executed.
366 If no number is given, use the last block executed.
362
367
363 This edits the in-memory copy of the demo, it does NOT modify the
368 This edits the in-memory copy of the demo, it does NOT modify the
364 original source file. If you want to do that, simply open the file in
369 original source file. If you want to do that, simply open the file in
365 an editor and use reload() when you make changes to the file. This
370 an editor and use reload() when you make changes to the file. This
366 method is meant to let you change a block during a demonstration for
371 method is meant to let you change a block during a demonstration for
367 explanatory purposes, without damaging your original script."""
372 explanatory purposes, without damaging your original script."""
368
373
369 index = self._get_index(index)
374 index = self._get_index(index)
370 if index is None:
375 if index is None:
371 return
376 return
372 # decrease the index by one (unless we're at the very beginning), so
377 # decrease the index by one (unless we're at the very beginning), so
373 # that the default demo.edit() call opens up the sblock we've last run
378 # that the default demo.edit() call opens up the sblock we've last run
374 if index>0:
379 if index>0:
375 index -= 1
380 index -= 1
376
381
377 filename = self.shell.mktempfile(self.src_blocks[index])
382 filename = self.shell.mktempfile(self.src_blocks[index])
378 self.shell.hooks.editor(filename,1)
383 self.shell.hooks.editor(filename,1)
379 new_block = file_read(filename)
384 new_block = file_read(filename)
380 # update the source and colored block
385 # update the source and colored block
381 self.src_blocks[index] = new_block
386 self.src_blocks[index] = new_block
382 self.src_blocks_colored[index] = self.ip_colorize(new_block)
387 self.src_blocks_colored[index] = self.ip_colorize(new_block)
383 self.block_index = index
388 self.block_index = index
384 # call to run with the newly edited index
389 # call to run with the newly edited index
385 self()
390 self()
386
391
387 def show(self,index=None):
392 def show(self,index=None):
388 """Show a single block on screen"""
393 """Show a single block on screen"""
389
394
390 index = self._get_index(index)
395 index = self._get_index(index)
391 if index is None:
396 if index is None:
392 return
397 return
393
398
394 print(self.marquee('<%s> block # %s (%s remaining)' %
399 print(self.marquee('<%s> block # %s (%s remaining)' %
395 (self.title,index,self.nblocks-index-1)), file=io.stdout)
400 (self.title,index,self.nblocks-index-1)), file=io.stdout)
396 print((self.src_blocks_colored[index]), file=io.stdout)
401 print((self.src_blocks_colored[index]), file=io.stdout)
397 sys.stdout.flush()
402 sys.stdout.flush()
398
403
399 def show_all(self):
404 def show_all(self):
400 """Show entire demo on screen, block by block"""
405 """Show entire demo on screen, block by block"""
401
406
402 fname = self.title
407 fname = self.title
403 title = self.title
408 title = self.title
404 nblocks = self.nblocks
409 nblocks = self.nblocks
405 silent = self._silent
410 silent = self._silent
406 marquee = self.marquee
411 marquee = self.marquee
407 for index,block in enumerate(self.src_blocks_colored):
412 for index,block in enumerate(self.src_blocks_colored):
408 if silent[index]:
413 if silent[index]:
409 print(marquee('<%s> SILENT block # %s (%s remaining)' %
414 print(marquee('<%s> SILENT block # %s (%s remaining)' %
410 (title,index,nblocks-index-1)), file=io.stdout)
415 (title,index,nblocks-index-1)), file=io.stdout)
411 else:
416 else:
412 print(marquee('<%s> block # %s (%s remaining)' %
417 print(marquee('<%s> block # %s (%s remaining)' %
413 (title,index,nblocks-index-1)), file=io.stdout)
418 (title,index,nblocks-index-1)), file=io.stdout)
414 print(block, end=' ', file=io.stdout)
419 print(block, end=' ', file=io.stdout)
415 sys.stdout.flush()
420 sys.stdout.flush()
416
421
417 def run_cell(self,source):
422 def run_cell(self,source):
418 """Execute a string with one or more lines of code"""
423 """Execute a string with one or more lines of code"""
419
424
420 exec source in self.user_ns
425 exec source in self.user_ns
421
426
422 def __call__(self,index=None):
427 def __call__(self,index=None):
423 """run a block of the demo.
428 """run a block of the demo.
424
429
425 If index is given, it should be an integer >=1 and <= nblocks. This
430 If index is given, it should be an integer >=1 and <= nblocks. This
426 means that the calling convention is one off from typical Python
431 means that the calling convention is one off from typical Python
427 lists. The reason for the inconsistency is that the demo always
432 lists. The reason for the inconsistency is that the demo always
428 prints 'Block n/N, and N is the total, so it would be very odd to use
433 prints 'Block n/N, and N is the total, so it would be very odd to use
429 zero-indexing here."""
434 zero-indexing here."""
430
435
431 index = self._get_index(index)
436 index = self._get_index(index)
432 if index is None:
437 if index is None:
433 return
438 return
434 try:
439 try:
435 marquee = self.marquee
440 marquee = self.marquee
436 next_block = self.src_blocks[index]
441 next_block = self.src_blocks[index]
437 self.block_index += 1
442 self.block_index += 1
438 if self._silent[index]:
443 if self._silent[index]:
439 print(marquee('Executing silent block # %s (%s remaining)' %
444 print(marquee('Executing silent block # %s (%s remaining)' %
440 (index,self.nblocks-index-1)), file=io.stdout)
445 (index,self.nblocks-index-1)), file=io.stdout)
441 else:
446 else:
442 self.pre_cmd()
447 self.pre_cmd()
443 self.show(index)
448 self.show(index)
444 if self.auto_all or self._auto[index]:
449 if self.auto_all or self._auto[index]:
445 print(marquee('output:'), file=io.stdout)
450 print(marquee('output:'), file=io.stdout)
446 else:
451 else:
447 print(marquee('Press <q> to quit, <Enter> to execute...'), end=' ', file=io.stdout)
452 print(marquee('Press <q> to quit, <Enter> to execute...'), end=' ', file=io.stdout)
448 ans = raw_input().strip()
453 ans = raw_input().strip()
449 if ans:
454 if ans:
450 print(marquee('Block NOT executed'), file=io.stdout)
455 print(marquee('Block NOT executed'), file=io.stdout)
451 return
456 return
452 try:
457 try:
453 save_argv = sys.argv
458 save_argv = sys.argv
454 sys.argv = self.sys_argv
459 sys.argv = self.sys_argv
455 self.run_cell(next_block)
460 self.run_cell(next_block)
456 self.post_cmd()
461 self.post_cmd()
457 finally:
462 finally:
458 sys.argv = save_argv
463 sys.argv = save_argv
459
464
460 except:
465 except:
461 self.ip_showtb(filename=self.fname)
466 self.ip_showtb(filename=self.fname)
462 else:
467 else:
463 self.ip_ns.update(self.user_ns)
468 self.ip_ns.update(self.user_ns)
464
469
465 if self.block_index == self.nblocks:
470 if self.block_index == self.nblocks:
466 mq1 = self.marquee('END OF DEMO')
471 mq1 = self.marquee('END OF DEMO')
467 if mq1:
472 if mq1:
468 # avoid spurious print >>io.stdout,s if empty marquees are used
473 # avoid spurious print >>io.stdout,s if empty marquees are used
469 print(file=io.stdout)
474 print(file=io.stdout)
470 print(mq1, file=io.stdout)
475 print(mq1, file=io.stdout)
471 print(self.marquee('Use <demo_name>.reset() if you want to rerun it.'), file=io.stdout)
476 print(self.marquee('Use <demo_name>.reset() if you want to rerun it.'), file=io.stdout)
472 self.finished = True
477 self.finished = True
473
478
474 # These methods are meant to be overridden by subclasses who may wish to
479 # These methods are meant to be overridden by subclasses who may wish to
475 # customize the behavior of of their demos.
480 # customize the behavior of of their demos.
476 def marquee(self,txt='',width=78,mark='*'):
481 def marquee(self,txt='',width=78,mark='*'):
477 """Return the input string centered in a 'marquee'."""
482 """Return the input string centered in a 'marquee'."""
478 return marquee(txt,width,mark)
483 return marquee(txt,width,mark)
479
484
480 def pre_cmd(self):
485 def pre_cmd(self):
481 """Method called before executing each block."""
486 """Method called before executing each block."""
482 pass
487 pass
483
488
484 def post_cmd(self):
489 def post_cmd(self):
485 """Method called after executing each block."""
490 """Method called after executing each block."""
486 pass
491 pass
487
492
488
493
489 class IPythonDemo(Demo):
494 class IPythonDemo(Demo):
490 """Class for interactive demos with IPython's input processing applied.
495 """Class for interactive demos with IPython's input processing applied.
491
496
492 This subclasses Demo, but instead of executing each block by the Python
497 This subclasses Demo, but instead of executing each block by the Python
493 interpreter (via exec), it actually calls IPython on it, so that any input
498 interpreter (via exec), it actually calls IPython on it, so that any input
494 filters which may be in place are applied to the input block.
499 filters which may be in place are applied to the input block.
495
500
496 If you have an interactive environment which exposes special input
501 If you have an interactive environment which exposes special input
497 processing, you can use this class instead to write demo scripts which
502 processing, you can use this class instead to write demo scripts which
498 operate exactly as if you had typed them interactively. The default Demo
503 operate exactly as if you had typed them interactively. The default Demo
499 class requires the input to be valid, pure Python code.
504 class requires the input to be valid, pure Python code.
500 """
505 """
501
506
502 def run_cell(self,source):
507 def run_cell(self,source):
503 """Execute a string with one or more lines of code"""
508 """Execute a string with one or more lines of code"""
504
509
505 self.shell.run_cell(source)
510 self.shell.run_cell(source)
506
511
507 class LineDemo(Demo):
512 class LineDemo(Demo):
508 """Demo where each line is executed as a separate block.
513 """Demo where each line is executed as a separate block.
509
514
510 The input script should be valid Python code.
515 The input script should be valid Python code.
511
516
512 This class doesn't require any markup at all, and it's meant for simple
517 This class doesn't require any markup at all, and it's meant for simple
513 scripts (with no nesting or any kind of indentation) which consist of
518 scripts (with no nesting or any kind of indentation) which consist of
514 multiple lines of input to be executed, one at a time, as if they had been
519 multiple lines of input to be executed, one at a time, as if they had been
515 typed in the interactive prompt.
520 typed in the interactive prompt.
516
521
517 Note: the input can not have *any* indentation, which means that only
522 Note: the input can not have *any* indentation, which means that only
518 single-lines of input are accepted, not even function definitions are
523 single-lines of input are accepted, not even function definitions are
519 valid."""
524 valid."""
520
525
521 def reload(self):
526 def reload(self):
522 """Reload source from disk and initialize state."""
527 """Reload source from disk and initialize state."""
523 # read data and parse into blocks
528 # read data and parse into blocks
524 self.fload()
529 self.fload()
525 lines = self.fobj.readlines()
530 lines = self.fobj.readlines()
526 src_b = [l for l in lines if l.strip()]
531 src_b = [l for l in lines if l.strip()]
527 nblocks = len(src_b)
532 nblocks = len(src_b)
528 self.src = ''.join(lines)
533 self.src = ''.join(lines)
529 self._silent = [False]*nblocks
534 self._silent = [False]*nblocks
530 self._auto = [True]*nblocks
535 self._auto = [True]*nblocks
531 self.auto_all = True
536 self.auto_all = True
532 self.nblocks = nblocks
537 self.nblocks = nblocks
533 self.src_blocks = src_b
538 self.src_blocks = src_b
534
539
535 # also build syntax-highlighted source
540 # also build syntax-highlighted source
536 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
541 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
537
542
538 # ensure clean namespace and seek offset
543 # ensure clean namespace and seek offset
539 self.reset()
544 self.reset()
540
545
541
546
542 class IPythonLineDemo(IPythonDemo,LineDemo):
547 class IPythonLineDemo(IPythonDemo,LineDemo):
543 """Variant of the LineDemo class whose input is processed by IPython."""
548 """Variant of the LineDemo class whose input is processed by IPython."""
544 pass
549 pass
545
550
546
551
547 class ClearMixin(object):
552 class ClearMixin(object):
548 """Use this mixin to make Demo classes with less visual clutter.
553 """Use this mixin to make Demo classes with less visual clutter.
549
554
550 Demos using this mixin will clear the screen before every block and use
555 Demos using this mixin will clear the screen before every block and use
551 blank marquees.
556 blank marquees.
552
557
553 Note that in order for the methods defined here to actually override those
558 Note that in order for the methods defined here to actually override those
554 of the classes it's mixed with, it must go /first/ in the inheritance
559 of the classes it's mixed with, it must go /first/ in the inheritance
555 tree. For example:
560 tree. For example:
556
561
557 class ClearIPDemo(ClearMixin,IPythonDemo): pass
562 class ClearIPDemo(ClearMixin,IPythonDemo): pass
558
563
559 will provide an IPythonDemo class with the mixin's features.
564 will provide an IPythonDemo class with the mixin's features.
560 """
565 """
561
566
562 def marquee(self,txt='',width=78,mark='*'):
567 def marquee(self,txt='',width=78,mark='*'):
563 """Blank marquee that returns '' no matter what the input."""
568 """Blank marquee that returns '' no matter what the input."""
564 return ''
569 return ''
565
570
566 def pre_cmd(self):
571 def pre_cmd(self):
567 """Method called before executing each block.
572 """Method called before executing each block.
568
573
569 This one simply clears the screen."""
574 This one simply clears the screen."""
570 from IPython.utils.terminal import term_clear
575 from IPython.utils.terminal import term_clear
571 term_clear()
576 term_clear()
572
577
573 class ClearDemo(ClearMixin,Demo):
578 class ClearDemo(ClearMixin,Demo):
574 pass
579 pass
575
580
576
581
577 class ClearIPDemo(ClearMixin,IPythonDemo):
582 class ClearIPDemo(ClearMixin,IPythonDemo):
578 pass
583 pass
@@ -1,443 +1,441 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """Module for interactively running scripts.
2 """Module for interactively running scripts.
3
3
4 This module implements classes for interactively running scripts written for
4 This module implements classes for interactively running scripts written for
5 any system with a prompt which can be matched by a regexp suitable for
5 any system with a prompt which can be matched by a regexp suitable for
6 pexpect. It can be used to run as if they had been typed up interactively, an
6 pexpect. It can be used to run as if they had been typed up interactively, an
7 arbitrary series of commands for the target system.
7 arbitrary series of commands for the target system.
8
8
9 The module includes classes ready for IPython (with the default prompts),
9 The module includes classes ready for IPython (with the default prompts),
10 plain Python and SAGE, but making a new one is trivial. To see how to use it,
10 plain Python and SAGE, but making a new one is trivial. To see how to use it,
11 simply run the module as a script:
11 simply run the module as a script:
12
12
13 ./irunner.py --help
13 ./irunner.py --help
14
14
15
15
16 This is an extension of Ken Schutte <kschutte-AT-csail.mit.edu>'s script
16 This is an extension of Ken Schutte <kschutte-AT-csail.mit.edu>'s script
17 contributed on the ipython-user list:
17 contributed on the ipython-user list:
18
18
19 http://mail.scipy.org/pipermail/ipython-user/2006-May/003539.html
19 http://mail.scipy.org/pipermail/ipython-user/2006-May/003539.html
20
20
21
21 Notes
22 NOTES:
22 -----
23
23
24 - This module requires pexpect, available in most linux distros, or which can
24 - This module requires pexpect, available in most linux distros, or which can
25 be downloaded from
25 be downloaded from http://pexpect.sourceforge.net
26
27 http://pexpect.sourceforge.net
28
26
29 - Because pexpect only works under Unix or Windows-Cygwin, this has the same
27 - Because pexpect only works under Unix or Windows-Cygwin, this has the same
30 limitations. This means that it will NOT work under native windows Python.
28 limitations. This means that it will NOT work under native windows Python.
31 """
29 """
32 from __future__ import print_function
30 from __future__ import print_function
33
31
34 # Stdlib imports
32 # Stdlib imports
35 import optparse
33 import optparse
36 import os
34 import os
37 import sys
35 import sys
38
36
39 # Third-party modules: we carry a copy of pexpect to reduce the need for
37 # Third-party modules: we carry a copy of pexpect to reduce the need for
40 # external dependencies, but our import checks for a system version first.
38 # external dependencies, but our import checks for a system version first.
41 from IPython.external import pexpect
39 from IPython.external import pexpect
42 from IPython.utils import py3compat
40 from IPython.utils import py3compat
43
41
44 # Global usage strings, to avoid indentation issues when typing it below.
42 # Global usage strings, to avoid indentation issues when typing it below.
45 USAGE = """
43 USAGE = """
46 Interactive script runner, type: %s
44 Interactive script runner, type: %s
47
45
48 runner [opts] script_name
46 runner [opts] script_name
49 """
47 """
50
48
51 def pexpect_monkeypatch():
49 def pexpect_monkeypatch():
52 """Patch pexpect to prevent unhandled exceptions at VM teardown.
50 """Patch pexpect to prevent unhandled exceptions at VM teardown.
53
51
54 Calling this function will monkeypatch the pexpect.spawn class and modify
52 Calling this function will monkeypatch the pexpect.spawn class and modify
55 its __del__ method to make it more robust in the face of failures that can
53 its __del__ method to make it more robust in the face of failures that can
56 occur if it is called when the Python VM is shutting down.
54 occur if it is called when the Python VM is shutting down.
57
55
58 Since Python may fire __del__ methods arbitrarily late, it's possible for
56 Since Python may fire __del__ methods arbitrarily late, it's possible for
59 them to execute during the teardown of the Python VM itself. At this
57 them to execute during the teardown of the Python VM itself. At this
60 point, various builtin modules have been reset to None. Thus, the call to
58 point, various builtin modules have been reset to None. Thus, the call to
61 self.close() will trigger an exception because it tries to call os.close(),
59 self.close() will trigger an exception because it tries to call os.close(),
62 and os is now None.
60 and os is now None.
63 """
61 """
64
62
65 if pexpect.__version__[:3] >= '2.2':
63 if pexpect.__version__[:3] >= '2.2':
66 # No need to patch, fix is already the upstream version.
64 # No need to patch, fix is already the upstream version.
67 return
65 return
68
66
69 def __del__(self):
67 def __del__(self):
70 """This makes sure that no system resources are left open.
68 """This makes sure that no system resources are left open.
71 Python only garbage collects Python objects. OS file descriptors
69 Python only garbage collects Python objects. OS file descriptors
72 are not Python objects, so they must be handled explicitly.
70 are not Python objects, so they must be handled explicitly.
73 If the child file descriptor was opened outside of this class
71 If the child file descriptor was opened outside of this class
74 (passed to the constructor) then this does not close it.
72 (passed to the constructor) then this does not close it.
75 """
73 """
76 if not self.closed:
74 if not self.closed:
77 try:
75 try:
78 self.close()
76 self.close()
79 except AttributeError:
77 except AttributeError:
80 pass
78 pass
81
79
82 pexpect.spawn.__del__ = __del__
80 pexpect.spawn.__del__ = __del__
83
81
84 pexpect_monkeypatch()
82 pexpect_monkeypatch()
85
83
86 # The generic runner class
84 # The generic runner class
87 class InteractiveRunner(object):
85 class InteractiveRunner(object):
88 """Class to run a sequence of commands through an interactive program."""
86 """Class to run a sequence of commands through an interactive program."""
89
87
90 def __init__(self,program,prompts,args=None,out=sys.stdout,echo=True):
88 def __init__(self,program,prompts,args=None,out=sys.stdout,echo=True):
91 """Construct a runner.
89 """Construct a runner.
92
90
93 Inputs:
91 Inputs:
94
92
95 - program: command to execute the given program.
93 - program: command to execute the given program.
96
94
97 - prompts: a list of patterns to match as valid prompts, in the
95 - prompts: a list of patterns to match as valid prompts, in the
98 format used by pexpect. This basically means that it can be either
96 format used by pexpect. This basically means that it can be either
99 a string (to be compiled as a regular expression) or a list of such
97 a string (to be compiled as a regular expression) or a list of such
100 (it must be a true list, as pexpect does type checks).
98 (it must be a true list, as pexpect does type checks).
101
99
102 If more than one prompt is given, the first is treated as the main
100 If more than one prompt is given, the first is treated as the main
103 program prompt and the others as 'continuation' prompts, like
101 program prompt and the others as 'continuation' prompts, like
104 python's. This means that blank lines in the input source are
102 python's. This means that blank lines in the input source are
105 ommitted when the first prompt is matched, but are NOT ommitted when
103 ommitted when the first prompt is matched, but are NOT ommitted when
106 the continuation one matches, since this is how python signals the
104 the continuation one matches, since this is how python signals the
107 end of multiline input interactively.
105 end of multiline input interactively.
108
106
109 Optional inputs:
107 Optional inputs:
110
108
111 - args(None): optional list of strings to pass as arguments to the
109 - args(None): optional list of strings to pass as arguments to the
112 child program.
110 child program.
113
111
114 - out(sys.stdout): if given, an output stream to be used when writing
112 - out(sys.stdout): if given, an output stream to be used when writing
115 output. The only requirement is that it must have a .write() method.
113 output. The only requirement is that it must have a .write() method.
116
114
117 Public members not parameterized in the constructor:
115 Public members not parameterized in the constructor:
118
116
119 - delaybeforesend(0): Newer versions of pexpect have a delay before
117 - delaybeforesend(0): Newer versions of pexpect have a delay before
120 sending each new input. For our purposes here, it's typically best
118 sending each new input. For our purposes here, it's typically best
121 to just set this to zero, but if you encounter reliability problems
119 to just set this to zero, but if you encounter reliability problems
122 or want an interactive run to pause briefly at each prompt, just
120 or want an interactive run to pause briefly at each prompt, just
123 increase this value (it is measured in seconds). Note that this
121 increase this value (it is measured in seconds). Note that this
124 variable is not honored at all by older versions of pexpect.
122 variable is not honored at all by older versions of pexpect.
125 """
123 """
126
124
127 self.program = program
125 self.program = program
128 self.prompts = prompts
126 self.prompts = prompts
129 if args is None: args = []
127 if args is None: args = []
130 self.args = args
128 self.args = args
131 self.out = out
129 self.out = out
132 self.echo = echo
130 self.echo = echo
133 # Other public members which we don't make as parameters, but which
131 # Other public members which we don't make as parameters, but which
134 # users may occasionally want to tweak
132 # users may occasionally want to tweak
135 self.delaybeforesend = 0
133 self.delaybeforesend = 0
136
134
137 # Create child process and hold on to it so we don't have to re-create
135 # Create child process and hold on to it so we don't have to re-create
138 # for every single execution call
136 # for every single execution call
139 c = self.child = pexpect.spawn(self.program,self.args,timeout=None)
137 c = self.child = pexpect.spawn(self.program,self.args,timeout=None)
140 c.delaybeforesend = self.delaybeforesend
138 c.delaybeforesend = self.delaybeforesend
141 # pexpect hard-codes the terminal size as (24,80) (rows,columns).
139 # pexpect hard-codes the terminal size as (24,80) (rows,columns).
142 # This causes problems because any line longer than 80 characters gets
140 # This causes problems because any line longer than 80 characters gets
143 # completely overwrapped on the printed outptut (even though
141 # completely overwrapped on the printed outptut (even though
144 # internally the code runs fine). We reset this to 99 rows X 200
142 # internally the code runs fine). We reset this to 99 rows X 200
145 # columns (arbitrarily chosen), which should avoid problems in all
143 # columns (arbitrarily chosen), which should avoid problems in all
146 # reasonable cases.
144 # reasonable cases.
147 c.setwinsize(99,200)
145 c.setwinsize(99,200)
148
146
149 def close(self):
147 def close(self):
150 """close child process"""
148 """close child process"""
151
149
152 self.child.close()
150 self.child.close()
153
151
154 def run_file(self,fname,interact=False,get_output=False):
152 def run_file(self,fname,interact=False,get_output=False):
155 """Run the given file interactively.
153 """Run the given file interactively.
156
154
157 Inputs:
155 Inputs:
158
156
159 -fname: name of the file to execute.
157 -fname: name of the file to execute.
160
158
161 See the run_source docstring for the meaning of the optional
159 See the run_source docstring for the meaning of the optional
162 arguments."""
160 arguments."""
163
161
164 fobj = open(fname,'r')
162 fobj = open(fname,'r')
165 try:
163 try:
166 out = self.run_source(fobj,interact,get_output)
164 out = self.run_source(fobj,interact,get_output)
167 finally:
165 finally:
168 fobj.close()
166 fobj.close()
169 if get_output:
167 if get_output:
170 return out
168 return out
171
169
172 def run_source(self,source,interact=False,get_output=False):
170 def run_source(self,source,interact=False,get_output=False):
173 """Run the given source code interactively.
171 """Run the given source code interactively.
174
172
175 Inputs:
173 Inputs:
176
174
177 - source: a string of code to be executed, or an open file object we
175 - source: a string of code to be executed, or an open file object we
178 can iterate over.
176 can iterate over.
179
177
180 Optional inputs:
178 Optional inputs:
181
179
182 - interact(False): if true, start to interact with the running
180 - interact(False): if true, start to interact with the running
183 program at the end of the script. Otherwise, just exit.
181 program at the end of the script. Otherwise, just exit.
184
182
185 - get_output(False): if true, capture the output of the child process
183 - get_output(False): if true, capture the output of the child process
186 (filtering the input commands out) and return it as a string.
184 (filtering the input commands out) and return it as a string.
187
185
188 Returns:
186 Returns:
189 A string containing the process output, but only if requested.
187 A string containing the process output, but only if requested.
190 """
188 """
191
189
192 # if the source is a string, chop it up in lines so we can iterate
190 # if the source is a string, chop it up in lines so we can iterate
193 # over it just as if it were an open file.
191 # over it just as if it were an open file.
194 if isinstance(source, basestring):
192 if isinstance(source, basestring):
195 source = source.splitlines(True)
193 source = source.splitlines(True)
196
194
197 if self.echo:
195 if self.echo:
198 # normalize all strings we write to use the native OS line
196 # normalize all strings we write to use the native OS line
199 # separators.
197 # separators.
200 linesep = os.linesep
198 linesep = os.linesep
201 stdwrite = self.out.write
199 stdwrite = self.out.write
202 write = lambda s: stdwrite(s.replace('\r\n',linesep))
200 write = lambda s: stdwrite(s.replace('\r\n',linesep))
203 else:
201 else:
204 # Quiet mode, all writes are no-ops
202 # Quiet mode, all writes are no-ops
205 write = lambda s: None
203 write = lambda s: None
206
204
207 c = self.child
205 c = self.child
208 prompts = c.compile_pattern_list(self.prompts)
206 prompts = c.compile_pattern_list(self.prompts)
209 prompt_idx = c.expect_list(prompts)
207 prompt_idx = c.expect_list(prompts)
210
208
211 # Flag whether the script ends normally or not, to know whether we can
209 # Flag whether the script ends normally or not, to know whether we can
212 # do anything further with the underlying process.
210 # do anything further with the underlying process.
213 end_normal = True
211 end_normal = True
214
212
215 # If the output was requested, store it in a list for return at the end
213 # If the output was requested, store it in a list for return at the end
216 if get_output:
214 if get_output:
217 output = []
215 output = []
218 store_output = output.append
216 store_output = output.append
219
217
220 for cmd in source:
218 for cmd in source:
221 # skip blank lines for all matches to the 'main' prompt, while the
219 # skip blank lines for all matches to the 'main' prompt, while the
222 # secondary prompts do not
220 # secondary prompts do not
223 if prompt_idx==0 and \
221 if prompt_idx==0 and \
224 (cmd.isspace() or cmd.lstrip().startswith('#')):
222 (cmd.isspace() or cmd.lstrip().startswith('#')):
225 write(cmd)
223 write(cmd)
226 continue
224 continue
227
225
228 # write('AFTER: '+c.after) # dbg
226 # write('AFTER: '+c.after) # dbg
229 write(c.after)
227 write(c.after)
230 c.send(cmd)
228 c.send(cmd)
231 try:
229 try:
232 prompt_idx = c.expect_list(prompts)
230 prompt_idx = c.expect_list(prompts)
233 except pexpect.EOF:
231 except pexpect.EOF:
234 # this will happen if the child dies unexpectedly
232 # this will happen if the child dies unexpectedly
235 write(c.before)
233 write(c.before)
236 end_normal = False
234 end_normal = False
237 break
235 break
238
236
239 write(c.before)
237 write(c.before)
240
238
241 # With an echoing process, the output we get in c.before contains
239 # With an echoing process, the output we get in c.before contains
242 # the command sent, a newline, and then the actual process output
240 # the command sent, a newline, and then the actual process output
243 if get_output:
241 if get_output:
244 store_output(c.before[len(cmd+'\n'):])
242 store_output(c.before[len(cmd+'\n'):])
245 #write('CMD: <<%s>>' % cmd) # dbg
243 #write('CMD: <<%s>>' % cmd) # dbg
246 #write('OUTPUT: <<%s>>' % output[-1]) # dbg
244 #write('OUTPUT: <<%s>>' % output[-1]) # dbg
247
245
248 self.out.flush()
246 self.out.flush()
249 if end_normal:
247 if end_normal:
250 if interact:
248 if interact:
251 c.send('\n')
249 c.send('\n')
252 print('<< Starting interactive mode >>', end=' ')
250 print('<< Starting interactive mode >>', end=' ')
253 try:
251 try:
254 c.interact()
252 c.interact()
255 except OSError:
253 except OSError:
256 # This is what fires when the child stops. Simply print a
254 # This is what fires when the child stops. Simply print a
257 # newline so the system prompt is aligned. The extra
255 # newline so the system prompt is aligned. The extra
258 # space is there to make sure it gets printed, otherwise
256 # space is there to make sure it gets printed, otherwise
259 # OS buffering sometimes just suppresses it.
257 # OS buffering sometimes just suppresses it.
260 write(' \n')
258 write(' \n')
261 self.out.flush()
259 self.out.flush()
262 else:
260 else:
263 if interact:
261 if interact:
264 e="Further interaction is not possible: child process is dead."
262 e="Further interaction is not possible: child process is dead."
265 print(e, file=sys.stderr)
263 print(e, file=sys.stderr)
266
264
267 # Leave the child ready for more input later on, otherwise select just
265 # Leave the child ready for more input later on, otherwise select just
268 # hangs on the second invocation.
266 # hangs on the second invocation.
269 if c.isalive():
267 if c.isalive():
270 c.send('\n')
268 c.send('\n')
271
269
272 # Return any requested output
270 # Return any requested output
273 if get_output:
271 if get_output:
274 return ''.join(output)
272 return ''.join(output)
275
273
276 def main(self,argv=None):
274 def main(self,argv=None):
277 """Run as a command-line script."""
275 """Run as a command-line script."""
278
276
279 parser = optparse.OptionParser(usage=USAGE % self.__class__.__name__)
277 parser = optparse.OptionParser(usage=USAGE % self.__class__.__name__)
280 newopt = parser.add_option
278 newopt = parser.add_option
281 newopt('-i','--interact',action='store_true',default=False,
279 newopt('-i','--interact',action='store_true',default=False,
282 help='Interact with the program after the script is run.')
280 help='Interact with the program after the script is run.')
283
281
284 opts,args = parser.parse_args(argv)
282 opts,args = parser.parse_args(argv)
285
283
286 if len(args) != 1:
284 if len(args) != 1:
287 print("You must supply exactly one file to run.", file=sys.stderr)
285 print("You must supply exactly one file to run.", file=sys.stderr)
288 sys.exit(1)
286 sys.exit(1)
289
287
290 self.run_file(args[0],opts.interact)
288 self.run_file(args[0],opts.interact)
291
289
292 _ipython_cmd = "ipython3" if py3compat.PY3 else "ipython"
290 _ipython_cmd = "ipython3" if py3compat.PY3 else "ipython"
293
291
294 # Specific runners for particular programs
292 # Specific runners for particular programs
295 class IPythonRunner(InteractiveRunner):
293 class IPythonRunner(InteractiveRunner):
296 """Interactive IPython runner.
294 """Interactive IPython runner.
297
295
298 This initalizes IPython in 'nocolor' mode for simplicity. This lets us
296 This initalizes IPython in 'nocolor' mode for simplicity. This lets us
299 avoid having to write a regexp that matches ANSI sequences, though pexpect
297 avoid having to write a regexp that matches ANSI sequences, though pexpect
300 does support them. If anyone contributes patches for ANSI color support,
298 does support them. If anyone contributes patches for ANSI color support,
301 they will be welcome.
299 they will be welcome.
302
300
303 It also sets the prompts manually, since the prompt regexps for
301 It also sets the prompts manually, since the prompt regexps for
304 pexpect need to be matched to the actual prompts, so user-customized
302 pexpect need to be matched to the actual prompts, so user-customized
305 prompts would break this.
303 prompts would break this.
306 """
304 """
307
305
308 def __init__(self,program = _ipython_cmd, args=None, out=sys.stdout, echo=True):
306 def __init__(self,program = _ipython_cmd, args=None, out=sys.stdout, echo=True):
309 """New runner, optionally passing the ipython command to use."""
307 """New runner, optionally passing the ipython command to use."""
310 args0 = ['--colors=NoColor',
308 args0 = ['--colors=NoColor',
311 '--no-term-title',
309 '--no-term-title',
312 '--no-autoindent',
310 '--no-autoindent',
313 # '--quick' is important, to prevent loading default config:
311 # '--quick' is important, to prevent loading default config:
314 '--quick']
312 '--quick']
315 if args is None: args = args0
313 if args is None: args = args0
316 else: args = args0 + args
314 else: args = args0 + args
317 prompts = [r'In \[\d+\]: ',r' \.*: ']
315 prompts = [r'In \[\d+\]: ',r' \.*: ']
318 InteractiveRunner.__init__(self,program,prompts,args,out,echo)
316 InteractiveRunner.__init__(self,program,prompts,args,out,echo)
319
317
320
318
321 class PythonRunner(InteractiveRunner):
319 class PythonRunner(InteractiveRunner):
322 """Interactive Python runner."""
320 """Interactive Python runner."""
323
321
324 def __init__(self,program=sys.executable, args=None, out=sys.stdout, echo=True):
322 def __init__(self,program=sys.executable, args=None, out=sys.stdout, echo=True):
325 """New runner, optionally passing the python command to use."""
323 """New runner, optionally passing the python command to use."""
326
324
327 prompts = [r'>>> ',r'\.\.\. ']
325 prompts = [r'>>> ',r'\.\.\. ']
328 InteractiveRunner.__init__(self,program,prompts,args,out,echo)
326 InteractiveRunner.__init__(self,program,prompts,args,out,echo)
329
327
330
328
331 class SAGERunner(InteractiveRunner):
329 class SAGERunner(InteractiveRunner):
332 """Interactive SAGE runner.
330 """Interactive SAGE runner.
333
331
334 WARNING: this runner only works if you manually adjust your SAGE
332 WARNING: this runner only works if you manually adjust your SAGE
335 configuration so that the 'color' option in the configuration file is set to
333 configuration so that the 'color' option in the configuration file is set to
336 'NoColor', because currently the prompt matching regexp does not identify
334 'NoColor', because currently the prompt matching regexp does not identify
337 color sequences."""
335 color sequences."""
338
336
339 def __init__(self,program='sage',args=None,out=sys.stdout,echo=True):
337 def __init__(self,program='sage',args=None,out=sys.stdout,echo=True):
340 """New runner, optionally passing the sage command to use."""
338 """New runner, optionally passing the sage command to use."""
341
339
342 prompts = ['sage: ',r'\s*\.\.\. ']
340 prompts = ['sage: ',r'\s*\.\.\. ']
343 InteractiveRunner.__init__(self,program,prompts,args,out,echo)
341 InteractiveRunner.__init__(self,program,prompts,args,out,echo)
344
342
345
343
346 class RunnerFactory(object):
344 class RunnerFactory(object):
347 """Code runner factory.
345 """Code runner factory.
348
346
349 This class provides an IPython code runner, but enforces that only one
347 This class provides an IPython code runner, but enforces that only one
350 runner is ever instantiated. The runner is created based on the extension
348 runner is ever instantiated. The runner is created based on the extension
351 of the first file to run, and it raises an exception if a runner is later
349 of the first file to run, and it raises an exception if a runner is later
352 requested for a different extension type.
350 requested for a different extension type.
353
351
354 This ensures that we don't generate example files for doctest with a mix of
352 This ensures that we don't generate example files for doctest with a mix of
355 python and ipython syntax.
353 python and ipython syntax.
356 """
354 """
357
355
358 def __init__(self,out=sys.stdout):
356 def __init__(self,out=sys.stdout):
359 """Instantiate a code runner."""
357 """Instantiate a code runner."""
360
358
361 self.out = out
359 self.out = out
362 self.runner = None
360 self.runner = None
363 self.runnerClass = None
361 self.runnerClass = None
364
362
365 def _makeRunner(self,runnerClass):
363 def _makeRunner(self,runnerClass):
366 self.runnerClass = runnerClass
364 self.runnerClass = runnerClass
367 self.runner = runnerClass(out=self.out)
365 self.runner = runnerClass(out=self.out)
368 return self.runner
366 return self.runner
369
367
370 def __call__(self,fname):
368 def __call__(self,fname):
371 """Return a runner for the given filename."""
369 """Return a runner for the given filename."""
372
370
373 if fname.endswith('.py'):
371 if fname.endswith('.py'):
374 runnerClass = PythonRunner
372 runnerClass = PythonRunner
375 elif fname.endswith('.ipy'):
373 elif fname.endswith('.ipy'):
376 runnerClass = IPythonRunner
374 runnerClass = IPythonRunner
377 else:
375 else:
378 raise ValueError('Unknown file type for Runner: %r' % fname)
376 raise ValueError('Unknown file type for Runner: %r' % fname)
379
377
380 if self.runner is None:
378 if self.runner is None:
381 return self._makeRunner(runnerClass)
379 return self._makeRunner(runnerClass)
382 else:
380 else:
383 if runnerClass==self.runnerClass:
381 if runnerClass==self.runnerClass:
384 return self.runner
382 return self.runner
385 else:
383 else:
386 e='A runner of type %r can not run file %r' % \
384 e='A runner of type %r can not run file %r' % \
387 (self.runnerClass,fname)
385 (self.runnerClass,fname)
388 raise ValueError(e)
386 raise ValueError(e)
389
387
390
388
391 # Global usage string, to avoid indentation issues if typed in a function def.
389 # Global usage string, to avoid indentation issues if typed in a function def.
392 MAIN_USAGE = """
390 MAIN_USAGE = """
393 %prog [options] file_to_run
391 %prog [options] file_to_run
394
392
395 This is an interface to the various interactive runners available in this
393 This is an interface to the various interactive runners available in this
396 module. If you want to pass specific options to one of the runners, you need
394 module. If you want to pass specific options to one of the runners, you need
397 to first terminate the main options with a '--', and then provide the runner's
395 to first terminate the main options with a '--', and then provide the runner's
398 options. For example:
396 options. For example:
399
397
400 irunner.py --python -- --help
398 irunner.py --python -- --help
401
399
402 will pass --help to the python runner. Similarly,
400 will pass --help to the python runner. Similarly,
403
401
404 irunner.py --ipython -- --interact script.ipy
402 irunner.py --ipython -- --interact script.ipy
405
403
406 will run the script.ipy file under the IPython runner, and then will start to
404 will run the script.ipy file under the IPython runner, and then will start to
407 interact with IPython at the end of the script (instead of exiting).
405 interact with IPython at the end of the script (instead of exiting).
408
406
409 The already implemented runners are listed below; adding one for a new program
407 The already implemented runners are listed below; adding one for a new program
410 is a trivial task, see the source for examples.
408 is a trivial task, see the source for examples.
411 """
409 """
412
410
413 def main():
411 def main():
414 """Run as a command-line script."""
412 """Run as a command-line script."""
415
413
416 parser = optparse.OptionParser(usage=MAIN_USAGE)
414 parser = optparse.OptionParser(usage=MAIN_USAGE)
417 newopt = parser.add_option
415 newopt = parser.add_option
418 newopt('--ipython',action='store_const',dest='mode',const='ipython',
416 newopt('--ipython',action='store_const',dest='mode',const='ipython',
419 help='IPython interactive runner (default).')
417 help='IPython interactive runner (default).')
420 newopt('--python',action='store_const',dest='mode',const='python',
418 newopt('--python',action='store_const',dest='mode',const='python',
421 help='Python interactive runner.')
419 help='Python interactive runner.')
422 newopt('--sage',action='store_const',dest='mode',const='sage',
420 newopt('--sage',action='store_const',dest='mode',const='sage',
423 help='SAGE interactive runner.')
421 help='SAGE interactive runner.')
424
422
425 opts,args = parser.parse_args()
423 opts,args = parser.parse_args()
426 runners = dict(ipython=IPythonRunner,
424 runners = dict(ipython=IPythonRunner,
427 python=PythonRunner,
425 python=PythonRunner,
428 sage=SAGERunner)
426 sage=SAGERunner)
429
427
430 try:
428 try:
431 ext = os.path.splitext(args[0])[-1]
429 ext = os.path.splitext(args[0])[-1]
432 except IndexError:
430 except IndexError:
433 ext = ''
431 ext = ''
434 modes = {'.ipy':'ipython',
432 modes = {'.ipy':'ipython',
435 '.py':'python',
433 '.py':'python',
436 '.sage':'sage'}
434 '.sage':'sage'}
437 mode = modes.get(ext,"ipython")
435 mode = modes.get(ext,"ipython")
438 if opts.mode:
436 if opts.mode:
439 mode = opts.mode
437 mode = opts.mode
440 runners[mode]().main(args)
438 runners[mode]().main(args)
441
439
442 if __name__ == '__main__':
440 if __name__ == '__main__':
443 main()
441 main()
@@ -1,734 +1,736 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 pretty
3 Python advanced pretty printer. This pretty printer is intended to
4 ~~
4 replace the old `pprint` python module which does not allow developers
5 to provide their own pretty print callbacks.
5
6
6 Python advanced pretty printer. This pretty printer is intended to
7 This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`.
7 replace the old `pprint` python module which does not allow developers
8 to provide their own pretty print callbacks.
9
8
10 This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`.
11
9
10 Example Usage
11 -------------
12
12
13 Example Usage
13 To directly print the representation of an object use `pprint`::
14 =============
15
14
16 To directly print the representation of an object use `pprint`::
15 from pretty import pprint
16 pprint(complex_object)
17
17
18 from pretty import pprint
18 To get a string of the output use `pretty`::
19 pprint(complex_object)
20
19
21 To get a string of the output use `pretty`::
20 from pretty import pretty
21 string = pretty(complex_object)
22
22
23 from pretty import pretty
24 string = pretty(complex_object)
25
23
24 Extending
25 ---------
26
26
27 Extending
27 The pretty library allows developers to add pretty printing rules for their
28 =========
28 own objects. This process is straightforward. All you have to do is to
29 add a `_repr_pretty_` method to your object and call the methods on the
30 pretty printer passed::
29
31
30 The pretty library allows developers to add pretty printing rules for their
32 class MyObject(object):
31 own objects. This process is straightforward. All you have to do is to
32 add a `_repr_pretty_` method to your object and call the methods on the
33 pretty printer passed::
34
33
35 class MyObject(object):
34 def _repr_pretty_(self, p, cycle):
36
35 ...
37 def _repr_pretty_(self, p, cycle):
38 ...
39
36
40 Depending on the python version you want to support you have two
37 Depending on the python version you want to support you have two
41 possibilities. The following list shows the python 2.5 version and the
38 possibilities. The following list shows the python 2.5 version and the
42 compatibility one.
39 compatibility one.
43
40
44
41
45 Here the example implementation of a `_repr_pretty_` method for a list
42 Here the example implementation of a `_repr_pretty_` method for a list
46 subclass for python 2.5 and higher (python 2.5 requires the with statement
43 subclass for python 2.5 and higher (python 2.5 requires the with statement
47 __future__ import)::
44 __future__ import)::
48
45
49 class MyList(list):
46 class MyList(list):
50
47
51 def _repr_pretty_(self, p, cycle):
48 def _repr_pretty_(self, p, cycle):
52 if cycle:
49 if cycle:
53 p.text('MyList(...)')
50 p.text('MyList(...)')
54 else:
51 else:
55 with p.group(8, 'MyList([', '])'):
52 with p.group(8, 'MyList([', '])'):
56 for idx, item in enumerate(self):
57 if idx:
58 p.text(',')
59 p.breakable()
60 p.pretty(item)
61
62 The `cycle` parameter is `True` if pretty detected a cycle. You *have* to
63 react to that or the result is an infinite loop. `p.text()` just adds
64 non breaking text to the output, `p.breakable()` either adds a whitespace
65 or breaks here. If you pass it an argument it's used instead of the
66 default space. `p.pretty` prettyprints another object using the pretty print
67 method.
68
69 The first parameter to the `group` function specifies the extra indentation
70 of the next line. In this example the next item will either be not
71 breaked (if the items are short enough) or aligned with the right edge of
72 the opening bracked of `MyList`.
73
74 If you want to support python 2.4 and lower you can use this code::
75
76 class MyList(list):
77
78 def _repr_pretty_(self, p, cycle):
79 if cycle:
80 p.text('MyList(...)')
81 else:
82 p.begin_group(8, 'MyList([')
83 for idx, item in enumerate(self):
53 for idx, item in enumerate(self):
84 if idx:
54 if idx:
85 p.text(',')
55 p.text(',')
86 p.breakable()
56 p.breakable()
87 p.pretty(item)
57 p.pretty(item)
88 p.end_group(8, '])')
89
58
90 If you just want to indent something you can use the group function
59 The `cycle` parameter is `True` if pretty detected a cycle. You *have* to
91 without open / close parameters. Under python 2.5 you can also use this
60 react to that or the result is an infinite loop. `p.text()` just adds
92 code::
61 non breaking text to the output, `p.breakable()` either adds a whitespace
62 or breaks here. If you pass it an argument it's used instead of the
63 default space. `p.pretty` prettyprints another object using the pretty print
64 method.
93
65
94 with p.indent(2):
66 The first parameter to the `group` function specifies the extra indentation
95 ...
67 of the next line. In this example the next item will either be not
68 breaked (if the items are short enough) or aligned with the right edge of
69 the opening bracked of `MyList`.
70
71 If you want to support python 2.4 and lower you can use this code::
72
73 class MyList(list):
74
75 def _repr_pretty_(self, p, cycle):
76 if cycle:
77 p.text('MyList(...)')
78 else:
79 p.begin_group(8, 'MyList([')
80 for idx, item in enumerate(self):
81 if idx:
82 p.text(',')
83 p.breakable()
84 p.pretty(item)
85 p.end_group(8, '])')
86
87 If you just want to indent something you can use the group function
88 without open / close parameters. Under python 2.5 you can also use this
89 code::
90
91 with p.indent(2):
92 ...
93
94 Or under python2.4 you might want to modify ``p.indentation`` by hand but
95 this is rather ugly.
96
97 Inheritance diagram:
96
98
97 Or under python2.4 you might want to modify ``p.indentation`` by hand but
99 .. inheritance-diagram:: IPython.lib.pretty
98 this is rather ugly.
100 :parts: 3
99
101
100 :copyright: 2007 by Armin Ronacher.
102 :copyright: 2007 by Armin Ronacher.
101 Portions (c) 2009 by Robert Kern.
103 Portions (c) 2009 by Robert Kern.
102 :license: BSD License.
104 :license: BSD License.
103 """
105 """
104 from __future__ import with_statement
106 from __future__ import with_statement
105 from contextlib import contextmanager
107 from contextlib import contextmanager
106 import sys
108 import sys
107 import types
109 import types
108 import re
110 import re
109 import datetime
111 import datetime
110 from StringIO import StringIO
112 from StringIO import StringIO
111 from collections import deque
113 from collections import deque
112
114
113
115
114 __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
116 __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
115 'for_type', 'for_type_by_name']
117 'for_type', 'for_type_by_name']
116
118
117
119
118 _re_pattern_type = type(re.compile(''))
120 _re_pattern_type = type(re.compile(''))
119
121
120
122
121 def pretty(obj, verbose=False, max_width=79, newline='\n'):
123 def pretty(obj, verbose=False, max_width=79, newline='\n'):
122 """
124 """
123 Pretty print the object's representation.
125 Pretty print the object's representation.
124 """
126 """
125 stream = StringIO()
127 stream = StringIO()
126 printer = RepresentationPrinter(stream, verbose, max_width, newline)
128 printer = RepresentationPrinter(stream, verbose, max_width, newline)
127 printer.pretty(obj)
129 printer.pretty(obj)
128 printer.flush()
130 printer.flush()
129 return stream.getvalue()
131 return stream.getvalue()
130
132
131
133
132 def pprint(obj, verbose=False, max_width=79, newline='\n'):
134 def pprint(obj, verbose=False, max_width=79, newline='\n'):
133 """
135 """
134 Like `pretty` but print to stdout.
136 Like `pretty` but print to stdout.
135 """
137 """
136 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline)
138 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline)
137 printer.pretty(obj)
139 printer.pretty(obj)
138 printer.flush()
140 printer.flush()
139 sys.stdout.write(newline)
141 sys.stdout.write(newline)
140 sys.stdout.flush()
142 sys.stdout.flush()
141
143
142 class _PrettyPrinterBase(object):
144 class _PrettyPrinterBase(object):
143
145
144 @contextmanager
146 @contextmanager
145 def indent(self, indent):
147 def indent(self, indent):
146 """with statement support for indenting/dedenting."""
148 """with statement support for indenting/dedenting."""
147 self.indentation += indent
149 self.indentation += indent
148 try:
150 try:
149 yield
151 yield
150 finally:
152 finally:
151 self.indentation -= indent
153 self.indentation -= indent
152
154
153 @contextmanager
155 @contextmanager
154 def group(self, indent=0, open='', close=''):
156 def group(self, indent=0, open='', close=''):
155 """like begin_group / end_group but for the with statement."""
157 """like begin_group / end_group but for the with statement."""
156 self.begin_group(indent, open)
158 self.begin_group(indent, open)
157 try:
159 try:
158 yield
160 yield
159 finally:
161 finally:
160 self.end_group(indent, close)
162 self.end_group(indent, close)
161
163
162 class PrettyPrinter(_PrettyPrinterBase):
164 class PrettyPrinter(_PrettyPrinterBase):
163 """
165 """
164 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
166 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
165 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
167 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
166 this printer knows nothing about the default pprinters or the `_repr_pretty_`
168 this printer knows nothing about the default pprinters or the `_repr_pretty_`
167 callback method.
169 callback method.
168 """
170 """
169
171
170 def __init__(self, output, max_width=79, newline='\n'):
172 def __init__(self, output, max_width=79, newline='\n'):
171 self.output = output
173 self.output = output
172 self.max_width = max_width
174 self.max_width = max_width
173 self.newline = newline
175 self.newline = newline
174 self.output_width = 0
176 self.output_width = 0
175 self.buffer_width = 0
177 self.buffer_width = 0
176 self.buffer = deque()
178 self.buffer = deque()
177
179
178 root_group = Group(0)
180 root_group = Group(0)
179 self.group_stack = [root_group]
181 self.group_stack = [root_group]
180 self.group_queue = GroupQueue(root_group)
182 self.group_queue = GroupQueue(root_group)
181 self.indentation = 0
183 self.indentation = 0
182
184
183 def _break_outer_groups(self):
185 def _break_outer_groups(self):
184 while self.max_width < self.output_width + self.buffer_width:
186 while self.max_width < self.output_width + self.buffer_width:
185 group = self.group_queue.deq()
187 group = self.group_queue.deq()
186 if not group:
188 if not group:
187 return
189 return
188 while group.breakables:
190 while group.breakables:
189 x = self.buffer.popleft()
191 x = self.buffer.popleft()
190 self.output_width = x.output(self.output, self.output_width)
192 self.output_width = x.output(self.output, self.output_width)
191 self.buffer_width -= x.width
193 self.buffer_width -= x.width
192 while self.buffer and isinstance(self.buffer[0], Text):
194 while self.buffer and isinstance(self.buffer[0], Text):
193 x = self.buffer.popleft()
195 x = self.buffer.popleft()
194 self.output_width = x.output(self.output, self.output_width)
196 self.output_width = x.output(self.output, self.output_width)
195 self.buffer_width -= x.width
197 self.buffer_width -= x.width
196
198
197 def text(self, obj):
199 def text(self, obj):
198 """Add literal text to the output."""
200 """Add literal text to the output."""
199 width = len(obj)
201 width = len(obj)
200 if self.buffer:
202 if self.buffer:
201 text = self.buffer[-1]
203 text = self.buffer[-1]
202 if not isinstance(text, Text):
204 if not isinstance(text, Text):
203 text = Text()
205 text = Text()
204 self.buffer.append(text)
206 self.buffer.append(text)
205 text.add(obj, width)
207 text.add(obj, width)
206 self.buffer_width += width
208 self.buffer_width += width
207 self._break_outer_groups()
209 self._break_outer_groups()
208 else:
210 else:
209 self.output.write(obj)
211 self.output.write(obj)
210 self.output_width += width
212 self.output_width += width
211
213
212 def breakable(self, sep=' '):
214 def breakable(self, sep=' '):
213 """
215 """
214 Add a breakable separator to the output. This does not mean that it
216 Add a breakable separator to the output. This does not mean that it
215 will automatically break here. If no breaking on this position takes
217 will automatically break here. If no breaking on this position takes
216 place the `sep` is inserted which default to one space.
218 place the `sep` is inserted which default to one space.
217 """
219 """
218 width = len(sep)
220 width = len(sep)
219 group = self.group_stack[-1]
221 group = self.group_stack[-1]
220 if group.want_break:
222 if group.want_break:
221 self.flush()
223 self.flush()
222 self.output.write(self.newline)
224 self.output.write(self.newline)
223 self.output.write(' ' * self.indentation)
225 self.output.write(' ' * self.indentation)
224 self.output_width = self.indentation
226 self.output_width = self.indentation
225 self.buffer_width = 0
227 self.buffer_width = 0
226 else:
228 else:
227 self.buffer.append(Breakable(sep, width, self))
229 self.buffer.append(Breakable(sep, width, self))
228 self.buffer_width += width
230 self.buffer_width += width
229 self._break_outer_groups()
231 self._break_outer_groups()
230
232
231
233
232 def begin_group(self, indent=0, open=''):
234 def begin_group(self, indent=0, open=''):
233 """
235 """
234 Begin a group. If you want support for python < 2.5 which doesn't has
236 Begin a group. If you want support for python < 2.5 which doesn't has
235 the with statement this is the preferred way:
237 the with statement this is the preferred way:
236
238
237 p.begin_group(1, '{')
239 p.begin_group(1, '{')
238 ...
240 ...
239 p.end_group(1, '}')
241 p.end_group(1, '}')
240
242
241 The python 2.5 expression would be this:
243 The python 2.5 expression would be this:
242
244
243 with p.group(1, '{', '}'):
245 with p.group(1, '{', '}'):
244 ...
246 ...
245
247
246 The first parameter specifies the indentation for the next line (usually
248 The first parameter specifies the indentation for the next line (usually
247 the width of the opening text), the second the opening text. All
249 the width of the opening text), the second the opening text. All
248 parameters are optional.
250 parameters are optional.
249 """
251 """
250 if open:
252 if open:
251 self.text(open)
253 self.text(open)
252 group = Group(self.group_stack[-1].depth + 1)
254 group = Group(self.group_stack[-1].depth + 1)
253 self.group_stack.append(group)
255 self.group_stack.append(group)
254 self.group_queue.enq(group)
256 self.group_queue.enq(group)
255 self.indentation += indent
257 self.indentation += indent
256
258
257 def end_group(self, dedent=0, close=''):
259 def end_group(self, dedent=0, close=''):
258 """End a group. See `begin_group` for more details."""
260 """End a group. See `begin_group` for more details."""
259 self.indentation -= dedent
261 self.indentation -= dedent
260 group = self.group_stack.pop()
262 group = self.group_stack.pop()
261 if not group.breakables:
263 if not group.breakables:
262 self.group_queue.remove(group)
264 self.group_queue.remove(group)
263 if close:
265 if close:
264 self.text(close)
266 self.text(close)
265
267
266 def flush(self):
268 def flush(self):
267 """Flush data that is left in the buffer."""
269 """Flush data that is left in the buffer."""
268 for data in self.buffer:
270 for data in self.buffer:
269 self.output_width += data.output(self.output, self.output_width)
271 self.output_width += data.output(self.output, self.output_width)
270 self.buffer.clear()
272 self.buffer.clear()
271 self.buffer_width = 0
273 self.buffer_width = 0
272
274
273
275
274 def _get_mro(obj_class):
276 def _get_mro(obj_class):
275 """ Get a reasonable method resolution order of a class and its superclasses
277 """ Get a reasonable method resolution order of a class and its superclasses
276 for both old-style and new-style classes.
278 for both old-style and new-style classes.
277 """
279 """
278 if not hasattr(obj_class, '__mro__'):
280 if not hasattr(obj_class, '__mro__'):
279 # Old-style class. Mix in object to make a fake new-style class.
281 # Old-style class. Mix in object to make a fake new-style class.
280 try:
282 try:
281 obj_class = type(obj_class.__name__, (obj_class, object), {})
283 obj_class = type(obj_class.__name__, (obj_class, object), {})
282 except TypeError:
284 except TypeError:
283 # Old-style extension type that does not descend from object.
285 # Old-style extension type that does not descend from object.
284 # FIXME: try to construct a more thorough MRO.
286 # FIXME: try to construct a more thorough MRO.
285 mro = [obj_class]
287 mro = [obj_class]
286 else:
288 else:
287 mro = obj_class.__mro__[1:-1]
289 mro = obj_class.__mro__[1:-1]
288 else:
290 else:
289 mro = obj_class.__mro__
291 mro = obj_class.__mro__
290 return mro
292 return mro
291
293
292
294
293 class RepresentationPrinter(PrettyPrinter):
295 class RepresentationPrinter(PrettyPrinter):
294 """
296 """
295 Special pretty printer that has a `pretty` method that calls the pretty
297 Special pretty printer that has a `pretty` method that calls the pretty
296 printer for a python object.
298 printer for a python object.
297
299
298 This class stores processing data on `self` so you must *never* use
300 This class stores processing data on `self` so you must *never* use
299 this class in a threaded environment. Always lock it or reinstanciate
301 this class in a threaded environment. Always lock it or reinstanciate
300 it.
302 it.
301
303
302 Instances also have a verbose flag callbacks can access to control their
304 Instances also have a verbose flag callbacks can access to control their
303 output. For example the default instance repr prints all attributes and
305 output. For example the default instance repr prints all attributes and
304 methods that are not prefixed by an underscore if the printer is in
306 methods that are not prefixed by an underscore if the printer is in
305 verbose mode.
307 verbose mode.
306 """
308 """
307
309
308 def __init__(self, output, verbose=False, max_width=79, newline='\n',
310 def __init__(self, output, verbose=False, max_width=79, newline='\n',
309 singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None):
311 singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None):
310
312
311 PrettyPrinter.__init__(self, output, max_width, newline)
313 PrettyPrinter.__init__(self, output, max_width, newline)
312 self.verbose = verbose
314 self.verbose = verbose
313 self.stack = []
315 self.stack = []
314 if singleton_pprinters is None:
316 if singleton_pprinters is None:
315 singleton_pprinters = _singleton_pprinters.copy()
317 singleton_pprinters = _singleton_pprinters.copy()
316 self.singleton_pprinters = singleton_pprinters
318 self.singleton_pprinters = singleton_pprinters
317 if type_pprinters is None:
319 if type_pprinters is None:
318 type_pprinters = _type_pprinters.copy()
320 type_pprinters = _type_pprinters.copy()
319 self.type_pprinters = type_pprinters
321 self.type_pprinters = type_pprinters
320 if deferred_pprinters is None:
322 if deferred_pprinters is None:
321 deferred_pprinters = _deferred_type_pprinters.copy()
323 deferred_pprinters = _deferred_type_pprinters.copy()
322 self.deferred_pprinters = deferred_pprinters
324 self.deferred_pprinters = deferred_pprinters
323
325
324 def pretty(self, obj):
326 def pretty(self, obj):
325 """Pretty print the given object."""
327 """Pretty print the given object."""
326 obj_id = id(obj)
328 obj_id = id(obj)
327 cycle = obj_id in self.stack
329 cycle = obj_id in self.stack
328 self.stack.append(obj_id)
330 self.stack.append(obj_id)
329 self.begin_group()
331 self.begin_group()
330 try:
332 try:
331 obj_class = getattr(obj, '__class__', None) or type(obj)
333 obj_class = getattr(obj, '__class__', None) or type(obj)
332 # First try to find registered singleton printers for the type.
334 # First try to find registered singleton printers for the type.
333 try:
335 try:
334 printer = self.singleton_pprinters[obj_id]
336 printer = self.singleton_pprinters[obj_id]
335 except (TypeError, KeyError):
337 except (TypeError, KeyError):
336 pass
338 pass
337 else:
339 else:
338 return printer(obj, self, cycle)
340 return printer(obj, self, cycle)
339 # Next walk the mro and check for either:
341 # Next walk the mro and check for either:
340 # 1) a registered printer
342 # 1) a registered printer
341 # 2) a _repr_pretty_ method
343 # 2) a _repr_pretty_ method
342 for cls in _get_mro(obj_class):
344 for cls in _get_mro(obj_class):
343 if cls in self.type_pprinters:
345 if cls in self.type_pprinters:
344 # printer registered in self.type_pprinters
346 # printer registered in self.type_pprinters
345 return self.type_pprinters[cls](obj, self, cycle)
347 return self.type_pprinters[cls](obj, self, cycle)
346 else:
348 else:
347 # deferred printer
349 # deferred printer
348 printer = self._in_deferred_types(cls)
350 printer = self._in_deferred_types(cls)
349 if printer is not None:
351 if printer is not None:
350 return printer(obj, self, cycle)
352 return printer(obj, self, cycle)
351 else:
353 else:
352 # Finally look for special method names.
354 # Finally look for special method names.
353 # Some objects automatically create any requested
355 # Some objects automatically create any requested
354 # attribute. Try to ignore most of them by checking for
356 # attribute. Try to ignore most of them by checking for
355 # callability.
357 # callability.
356 if '_repr_pretty_' in cls.__dict__:
358 if '_repr_pretty_' in cls.__dict__:
357 meth = cls._repr_pretty_
359 meth = cls._repr_pretty_
358 if callable(meth):
360 if callable(meth):
359 return meth(obj, self, cycle)
361 return meth(obj, self, cycle)
360 return _default_pprint(obj, self, cycle)
362 return _default_pprint(obj, self, cycle)
361 finally:
363 finally:
362 self.end_group()
364 self.end_group()
363 self.stack.pop()
365 self.stack.pop()
364
366
365 def _in_deferred_types(self, cls):
367 def _in_deferred_types(self, cls):
366 """
368 """
367 Check if the given class is specified in the deferred type registry.
369 Check if the given class is specified in the deferred type registry.
368
370
369 Returns the printer from the registry if it exists, and None if the
371 Returns the printer from the registry if it exists, and None if the
370 class is not in the registry. Successful matches will be moved to the
372 class is not in the registry. Successful matches will be moved to the
371 regular type registry for future use.
373 regular type registry for future use.
372 """
374 """
373 mod = getattr(cls, '__module__', None)
375 mod = getattr(cls, '__module__', None)
374 name = getattr(cls, '__name__', None)
376 name = getattr(cls, '__name__', None)
375 key = (mod, name)
377 key = (mod, name)
376 printer = None
378 printer = None
377 if key in self.deferred_pprinters:
379 if key in self.deferred_pprinters:
378 # Move the printer over to the regular registry.
380 # Move the printer over to the regular registry.
379 printer = self.deferred_pprinters.pop(key)
381 printer = self.deferred_pprinters.pop(key)
380 self.type_pprinters[cls] = printer
382 self.type_pprinters[cls] = printer
381 return printer
383 return printer
382
384
383
385
384 class Printable(object):
386 class Printable(object):
385
387
386 def output(self, stream, output_width):
388 def output(self, stream, output_width):
387 return output_width
389 return output_width
388
390
389
391
390 class Text(Printable):
392 class Text(Printable):
391
393
392 def __init__(self):
394 def __init__(self):
393 self.objs = []
395 self.objs = []
394 self.width = 0
396 self.width = 0
395
397
396 def output(self, stream, output_width):
398 def output(self, stream, output_width):
397 for obj in self.objs:
399 for obj in self.objs:
398 stream.write(obj)
400 stream.write(obj)
399 return output_width + self.width
401 return output_width + self.width
400
402
401 def add(self, obj, width):
403 def add(self, obj, width):
402 self.objs.append(obj)
404 self.objs.append(obj)
403 self.width += width
405 self.width += width
404
406
405
407
406 class Breakable(Printable):
408 class Breakable(Printable):
407
409
408 def __init__(self, seq, width, pretty):
410 def __init__(self, seq, width, pretty):
409 self.obj = seq
411 self.obj = seq
410 self.width = width
412 self.width = width
411 self.pretty = pretty
413 self.pretty = pretty
412 self.indentation = pretty.indentation
414 self.indentation = pretty.indentation
413 self.group = pretty.group_stack[-1]
415 self.group = pretty.group_stack[-1]
414 self.group.breakables.append(self)
416 self.group.breakables.append(self)
415
417
416 def output(self, stream, output_width):
418 def output(self, stream, output_width):
417 self.group.breakables.popleft()
419 self.group.breakables.popleft()
418 if self.group.want_break:
420 if self.group.want_break:
419 stream.write(self.pretty.newline)
421 stream.write(self.pretty.newline)
420 stream.write(' ' * self.indentation)
422 stream.write(' ' * self.indentation)
421 return self.indentation
423 return self.indentation
422 if not self.group.breakables:
424 if not self.group.breakables:
423 self.pretty.group_queue.remove(self.group)
425 self.pretty.group_queue.remove(self.group)
424 stream.write(self.obj)
426 stream.write(self.obj)
425 return output_width + self.width
427 return output_width + self.width
426
428
427
429
428 class Group(Printable):
430 class Group(Printable):
429
431
430 def __init__(self, depth):
432 def __init__(self, depth):
431 self.depth = depth
433 self.depth = depth
432 self.breakables = deque()
434 self.breakables = deque()
433 self.want_break = False
435 self.want_break = False
434
436
435
437
436 class GroupQueue(object):
438 class GroupQueue(object):
437
439
438 def __init__(self, *groups):
440 def __init__(self, *groups):
439 self.queue = []
441 self.queue = []
440 for group in groups:
442 for group in groups:
441 self.enq(group)
443 self.enq(group)
442
444
443 def enq(self, group):
445 def enq(self, group):
444 depth = group.depth
446 depth = group.depth
445 while depth > len(self.queue) - 1:
447 while depth > len(self.queue) - 1:
446 self.queue.append([])
448 self.queue.append([])
447 self.queue[depth].append(group)
449 self.queue[depth].append(group)
448
450
449 def deq(self):
451 def deq(self):
450 for stack in self.queue:
452 for stack in self.queue:
451 for idx, group in enumerate(reversed(stack)):
453 for idx, group in enumerate(reversed(stack)):
452 if group.breakables:
454 if group.breakables:
453 del stack[idx]
455 del stack[idx]
454 group.want_break = True
456 group.want_break = True
455 return group
457 return group
456 for group in stack:
458 for group in stack:
457 group.want_break = True
459 group.want_break = True
458 del stack[:]
460 del stack[:]
459
461
460 def remove(self, group):
462 def remove(self, group):
461 try:
463 try:
462 self.queue[group.depth].remove(group)
464 self.queue[group.depth].remove(group)
463 except ValueError:
465 except ValueError:
464 pass
466 pass
465
467
466 try:
468 try:
467 _baseclass_reprs = (object.__repr__, types.InstanceType.__repr__)
469 _baseclass_reprs = (object.__repr__, types.InstanceType.__repr__)
468 except AttributeError: # Python 3
470 except AttributeError: # Python 3
469 _baseclass_reprs = (object.__repr__,)
471 _baseclass_reprs = (object.__repr__,)
470
472
471
473
472 def _default_pprint(obj, p, cycle):
474 def _default_pprint(obj, p, cycle):
473 """
475 """
474 The default print function. Used if an object does not provide one and
476 The default print function. Used if an object does not provide one and
475 it's none of the builtin objects.
477 it's none of the builtin objects.
476 """
478 """
477 klass = getattr(obj, '__class__', None) or type(obj)
479 klass = getattr(obj, '__class__', None) or type(obj)
478 if getattr(klass, '__repr__', None) not in _baseclass_reprs:
480 if getattr(klass, '__repr__', None) not in _baseclass_reprs:
479 # A user-provided repr.
481 # A user-provided repr.
480 p.text(repr(obj))
482 p.text(repr(obj))
481 return
483 return
482 p.begin_group(1, '<')
484 p.begin_group(1, '<')
483 p.pretty(klass)
485 p.pretty(klass)
484 p.text(' at 0x%x' % id(obj))
486 p.text(' at 0x%x' % id(obj))
485 if cycle:
487 if cycle:
486 p.text(' ...')
488 p.text(' ...')
487 elif p.verbose:
489 elif p.verbose:
488 first = True
490 first = True
489 for key in dir(obj):
491 for key in dir(obj):
490 if not key.startswith('_'):
492 if not key.startswith('_'):
491 try:
493 try:
492 value = getattr(obj, key)
494 value = getattr(obj, key)
493 except AttributeError:
495 except AttributeError:
494 continue
496 continue
495 if isinstance(value, types.MethodType):
497 if isinstance(value, types.MethodType):
496 continue
498 continue
497 if not first:
499 if not first:
498 p.text(',')
500 p.text(',')
499 p.breakable()
501 p.breakable()
500 p.text(key)
502 p.text(key)
501 p.text('=')
503 p.text('=')
502 step = len(key) + 1
504 step = len(key) + 1
503 p.indentation += step
505 p.indentation += step
504 p.pretty(value)
506 p.pretty(value)
505 p.indentation -= step
507 p.indentation -= step
506 first = False
508 first = False
507 p.end_group(1, '>')
509 p.end_group(1, '>')
508
510
509
511
510 def _seq_pprinter_factory(start, end, basetype):
512 def _seq_pprinter_factory(start, end, basetype):
511 """
513 """
512 Factory that returns a pprint function useful for sequences. Used by
514 Factory that returns a pprint function useful for sequences. Used by
513 the default pprint for tuples, dicts, lists, sets and frozensets.
515 the default pprint for tuples, dicts, lists, sets and frozensets.
514 """
516 """
515 def inner(obj, p, cycle):
517 def inner(obj, p, cycle):
516 typ = type(obj)
518 typ = type(obj)
517 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
519 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
518 # If the subclass provides its own repr, use it instead.
520 # If the subclass provides its own repr, use it instead.
519 return p.text(typ.__repr__(obj))
521 return p.text(typ.__repr__(obj))
520
522
521 if cycle:
523 if cycle:
522 return p.text(start + '...' + end)
524 return p.text(start + '...' + end)
523 step = len(start)
525 step = len(start)
524 p.begin_group(step, start)
526 p.begin_group(step, start)
525 for idx, x in enumerate(obj):
527 for idx, x in enumerate(obj):
526 if idx:
528 if idx:
527 p.text(',')
529 p.text(',')
528 p.breakable()
530 p.breakable()
529 p.pretty(x)
531 p.pretty(x)
530 if len(obj) == 1 and type(obj) is tuple:
532 if len(obj) == 1 and type(obj) is tuple:
531 # Special case for 1-item tuples.
533 # Special case for 1-item tuples.
532 p.text(',')
534 p.text(',')
533 p.end_group(step, end)
535 p.end_group(step, end)
534 return inner
536 return inner
535
537
536
538
537 def _dict_pprinter_factory(start, end, basetype=None):
539 def _dict_pprinter_factory(start, end, basetype=None):
538 """
540 """
539 Factory that returns a pprint function used by the default pprint of
541 Factory that returns a pprint function used by the default pprint of
540 dicts and dict proxies.
542 dicts and dict proxies.
541 """
543 """
542 def inner(obj, p, cycle):
544 def inner(obj, p, cycle):
543 typ = type(obj)
545 typ = type(obj)
544 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
546 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
545 # If the subclass provides its own repr, use it instead.
547 # If the subclass provides its own repr, use it instead.
546 return p.text(typ.__repr__(obj))
548 return p.text(typ.__repr__(obj))
547
549
548 if cycle:
550 if cycle:
549 return p.text('{...}')
551 return p.text('{...}')
550 p.begin_group(1, start)
552 p.begin_group(1, start)
551 keys = obj.keys()
553 keys = obj.keys()
552 try:
554 try:
553 keys.sort()
555 keys.sort()
554 except Exception as e:
556 except Exception as e:
555 # Sometimes the keys don't sort.
557 # Sometimes the keys don't sort.
556 pass
558 pass
557 for idx, key in enumerate(keys):
559 for idx, key in enumerate(keys):
558 if idx:
560 if idx:
559 p.text(',')
561 p.text(',')
560 p.breakable()
562 p.breakable()
561 p.pretty(key)
563 p.pretty(key)
562 p.text(': ')
564 p.text(': ')
563 p.pretty(obj[key])
565 p.pretty(obj[key])
564 p.end_group(1, end)
566 p.end_group(1, end)
565 return inner
567 return inner
566
568
567
569
568 def _super_pprint(obj, p, cycle):
570 def _super_pprint(obj, p, cycle):
569 """The pprint for the super type."""
571 """The pprint for the super type."""
570 p.begin_group(8, '<super: ')
572 p.begin_group(8, '<super: ')
571 p.pretty(obj.__self_class__)
573 p.pretty(obj.__self_class__)
572 p.text(',')
574 p.text(',')
573 p.breakable()
575 p.breakable()
574 p.pretty(obj.__self__)
576 p.pretty(obj.__self__)
575 p.end_group(8, '>')
577 p.end_group(8, '>')
576
578
577
579
578 def _re_pattern_pprint(obj, p, cycle):
580 def _re_pattern_pprint(obj, p, cycle):
579 """The pprint function for regular expression patterns."""
581 """The pprint function for regular expression patterns."""
580 p.text('re.compile(')
582 p.text('re.compile(')
581 pattern = repr(obj.pattern)
583 pattern = repr(obj.pattern)
582 if pattern[:1] in 'uU':
584 if pattern[:1] in 'uU':
583 pattern = pattern[1:]
585 pattern = pattern[1:]
584 prefix = 'ur'
586 prefix = 'ur'
585 else:
587 else:
586 prefix = 'r'
588 prefix = 'r'
587 pattern = prefix + pattern.replace('\\\\', '\\')
589 pattern = prefix + pattern.replace('\\\\', '\\')
588 p.text(pattern)
590 p.text(pattern)
589 if obj.flags:
591 if obj.flags:
590 p.text(',')
592 p.text(',')
591 p.breakable()
593 p.breakable()
592 done_one = False
594 done_one = False
593 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
595 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
594 'UNICODE', 'VERBOSE', 'DEBUG'):
596 'UNICODE', 'VERBOSE', 'DEBUG'):
595 if obj.flags & getattr(re, flag):
597 if obj.flags & getattr(re, flag):
596 if done_one:
598 if done_one:
597 p.text('|')
599 p.text('|')
598 p.text('re.' + flag)
600 p.text('re.' + flag)
599 done_one = True
601 done_one = True
600 p.text(')')
602 p.text(')')
601
603
602
604
603 def _type_pprint(obj, p, cycle):
605 def _type_pprint(obj, p, cycle):
604 """The pprint for classes and types."""
606 """The pprint for classes and types."""
605 if obj.__module__ in ('__builtin__', 'exceptions'):
607 if obj.__module__ in ('__builtin__', 'exceptions'):
606 name = obj.__name__
608 name = obj.__name__
607 else:
609 else:
608 name = obj.__module__ + '.' + obj.__name__
610 name = obj.__module__ + '.' + obj.__name__
609 p.text(name)
611 p.text(name)
610
612
611
613
612 def _repr_pprint(obj, p, cycle):
614 def _repr_pprint(obj, p, cycle):
613 """A pprint that just redirects to the normal repr function."""
615 """A pprint that just redirects to the normal repr function."""
614 p.text(repr(obj))
616 p.text(repr(obj))
615
617
616
618
617 def _function_pprint(obj, p, cycle):
619 def _function_pprint(obj, p, cycle):
618 """Base pprint for all functions and builtin functions."""
620 """Base pprint for all functions and builtin functions."""
619 if obj.__module__ in ('__builtin__', 'exceptions') or not obj.__module__:
621 if obj.__module__ in ('__builtin__', 'exceptions') or not obj.__module__:
620 name = obj.__name__
622 name = obj.__name__
621 else:
623 else:
622 name = obj.__module__ + '.' + obj.__name__
624 name = obj.__module__ + '.' + obj.__name__
623 p.text('<function %s>' % name)
625 p.text('<function %s>' % name)
624
626
625
627
626 def _exception_pprint(obj, p, cycle):
628 def _exception_pprint(obj, p, cycle):
627 """Base pprint for all exceptions."""
629 """Base pprint for all exceptions."""
628 if obj.__class__.__module__ in ('exceptions', 'builtins'):
630 if obj.__class__.__module__ in ('exceptions', 'builtins'):
629 name = obj.__class__.__name__
631 name = obj.__class__.__name__
630 else:
632 else:
631 name = '%s.%s' % (
633 name = '%s.%s' % (
632 obj.__class__.__module__,
634 obj.__class__.__module__,
633 obj.__class__.__name__
635 obj.__class__.__name__
634 )
636 )
635 step = len(name) + 1
637 step = len(name) + 1
636 p.begin_group(step, name + '(')
638 p.begin_group(step, name + '(')
637 for idx, arg in enumerate(getattr(obj, 'args', ())):
639 for idx, arg in enumerate(getattr(obj, 'args', ())):
638 if idx:
640 if idx:
639 p.text(',')
641 p.text(',')
640 p.breakable()
642 p.breakable()
641 p.pretty(arg)
643 p.pretty(arg)
642 p.end_group(step, ')')
644 p.end_group(step, ')')
643
645
644
646
645 #: the exception base
647 #: the exception base
646 try:
648 try:
647 _exception_base = BaseException
649 _exception_base = BaseException
648 except NameError:
650 except NameError:
649 _exception_base = Exception
651 _exception_base = Exception
650
652
651
653
652 #: printers for builtin types
654 #: printers for builtin types
653 _type_pprinters = {
655 _type_pprinters = {
654 int: _repr_pprint,
656 int: _repr_pprint,
655 long: _repr_pprint,
657 long: _repr_pprint,
656 float: _repr_pprint,
658 float: _repr_pprint,
657 str: _repr_pprint,
659 str: _repr_pprint,
658 unicode: _repr_pprint,
660 unicode: _repr_pprint,
659 tuple: _seq_pprinter_factory('(', ')', tuple),
661 tuple: _seq_pprinter_factory('(', ')', tuple),
660 list: _seq_pprinter_factory('[', ']', list),
662 list: _seq_pprinter_factory('[', ']', list),
661 dict: _dict_pprinter_factory('{', '}', dict),
663 dict: _dict_pprinter_factory('{', '}', dict),
662
664
663 set: _seq_pprinter_factory('set([', '])', set),
665 set: _seq_pprinter_factory('set([', '])', set),
664 frozenset: _seq_pprinter_factory('frozenset([', '])', frozenset),
666 frozenset: _seq_pprinter_factory('frozenset([', '])', frozenset),
665 super: _super_pprint,
667 super: _super_pprint,
666 _re_pattern_type: _re_pattern_pprint,
668 _re_pattern_type: _re_pattern_pprint,
667 type: _type_pprint,
669 type: _type_pprint,
668 types.FunctionType: _function_pprint,
670 types.FunctionType: _function_pprint,
669 types.BuiltinFunctionType: _function_pprint,
671 types.BuiltinFunctionType: _function_pprint,
670 types.SliceType: _repr_pprint,
672 types.SliceType: _repr_pprint,
671 types.MethodType: _repr_pprint,
673 types.MethodType: _repr_pprint,
672
674
673 datetime.datetime: _repr_pprint,
675 datetime.datetime: _repr_pprint,
674 datetime.timedelta: _repr_pprint,
676 datetime.timedelta: _repr_pprint,
675 _exception_base: _exception_pprint
677 _exception_base: _exception_pprint
676 }
678 }
677
679
678 try:
680 try:
679 _type_pprinters[types.DictProxyType] = _dict_pprinter_factory('<dictproxy {', '}>')
681 _type_pprinters[types.DictProxyType] = _dict_pprinter_factory('<dictproxy {', '}>')
680 _type_pprinters[types.ClassType] = _type_pprint
682 _type_pprinters[types.ClassType] = _type_pprint
681 except AttributeError: # Python 3
683 except AttributeError: # Python 3
682 pass
684 pass
683
685
684 try:
686 try:
685 _type_pprinters[xrange] = _repr_pprint
687 _type_pprinters[xrange] = _repr_pprint
686 except NameError:
688 except NameError:
687 _type_pprinters[range] = _repr_pprint
689 _type_pprinters[range] = _repr_pprint
688
690
689 #: printers for types specified by name
691 #: printers for types specified by name
690 _deferred_type_pprinters = {
692 _deferred_type_pprinters = {
691 }
693 }
692
694
693 def for_type(typ, func):
695 def for_type(typ, func):
694 """
696 """
695 Add a pretty printer for a given type.
697 Add a pretty printer for a given type.
696 """
698 """
697 oldfunc = _type_pprinters.get(typ, None)
699 oldfunc = _type_pprinters.get(typ, None)
698 if func is not None:
700 if func is not None:
699 # To support easy restoration of old pprinters, we need to ignore Nones.
701 # To support easy restoration of old pprinters, we need to ignore Nones.
700 _type_pprinters[typ] = func
702 _type_pprinters[typ] = func
701 return oldfunc
703 return oldfunc
702
704
703 def for_type_by_name(type_module, type_name, func):
705 def for_type_by_name(type_module, type_name, func):
704 """
706 """
705 Add a pretty printer for a type specified by the module and name of a type
707 Add a pretty printer for a type specified by the module and name of a type
706 rather than the type object itself.
708 rather than the type object itself.
707 """
709 """
708 key = (type_module, type_name)
710 key = (type_module, type_name)
709 oldfunc = _deferred_type_pprinters.get(key, None)
711 oldfunc = _deferred_type_pprinters.get(key, None)
710 if func is not None:
712 if func is not None:
711 # To support easy restoration of old pprinters, we need to ignore Nones.
713 # To support easy restoration of old pprinters, we need to ignore Nones.
712 _deferred_type_pprinters[key] = func
714 _deferred_type_pprinters[key] = func
713 return oldfunc
715 return oldfunc
714
716
715
717
716 #: printers for the default singletons
718 #: printers for the default singletons
717 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
719 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
718 NotImplemented]), _repr_pprint)
720 NotImplemented]), _repr_pprint)
719
721
720
722
721 if __name__ == '__main__':
723 if __name__ == '__main__':
722 from random import randrange
724 from random import randrange
723 class Foo(object):
725 class Foo(object):
724 def __init__(self):
726 def __init__(self):
725 self.foo = 1
727 self.foo = 1
726 self.bar = re.compile(r'\s+')
728 self.bar = re.compile(r'\s+')
727 self.blub = dict.fromkeys(range(30), randrange(1, 40))
729 self.blub = dict.fromkeys(range(30), randrange(1, 40))
728 self.hehe = 23424.234234
730 self.hehe = 23424.234234
729 self.list = ["blub", "blah", self]
731 self.list = ["blub", "blah", self]
730
732
731 def get_foo(self):
733 def get_foo(self):
732 print "foo"
734 print "foo"
733
735
734 pprint(Foo(), verbose=True)
736 pprint(Foo(), verbose=True)
@@ -1,341 +1,346 b''
1 # encoding: utf-8
1 # encoding: utf-8
2
2
3 """Classes and functions for kernel related errors and exceptions.
3 """Classes and functions for kernel related errors and exceptions.
4
4
5 Inheritance diagram:
6
7 .. inheritance-diagram:: IPython.parallel.error
8 :parts: 3
9
5 Authors:
10 Authors:
6
11
7 * Brian Granger
12 * Brian Granger
8 * Min RK
13 * Min RK
9 """
14 """
10 from __future__ import print_function
15 from __future__ import print_function
11
16
12 import sys
17 import sys
13 import traceback
18 import traceback
14
19
15 __docformat__ = "restructuredtext en"
20 __docformat__ = "restructuredtext en"
16
21
17 # Tell nose to skip this module
22 # Tell nose to skip this module
18 __test__ = {}
23 __test__ = {}
19
24
20 #-------------------------------------------------------------------------------
25 #-------------------------------------------------------------------------------
21 # Copyright (C) 2008-2011 The IPython Development Team
26 # Copyright (C) 2008-2011 The IPython Development Team
22 #
27 #
23 # Distributed under the terms of the BSD License. The full license is in
28 # Distributed under the terms of the BSD License. The full license is in
24 # the file COPYING, distributed as part of this software.
29 # the file COPYING, distributed as part of this software.
25 #-------------------------------------------------------------------------------
30 #-------------------------------------------------------------------------------
26
31
27 #-------------------------------------------------------------------------------
32 #-------------------------------------------------------------------------------
28 # Error classes
33 # Error classes
29 #-------------------------------------------------------------------------------
34 #-------------------------------------------------------------------------------
30 class IPythonError(Exception):
35 class IPythonError(Exception):
31 """Base exception that all of our exceptions inherit from.
36 """Base exception that all of our exceptions inherit from.
32
37
33 This can be raised by code that doesn't have any more specific
38 This can be raised by code that doesn't have any more specific
34 information."""
39 information."""
35
40
36 pass
41 pass
37
42
38 # Exceptions associated with the controller objects
43 # Exceptions associated with the controller objects
39 class ControllerError(IPythonError): pass
44 class ControllerError(IPythonError): pass
40
45
41 class ControllerCreationError(ControllerError): pass
46 class ControllerCreationError(ControllerError): pass
42
47
43
48
44 # Exceptions associated with the Engines
49 # Exceptions associated with the Engines
45 class EngineError(IPythonError): pass
50 class EngineError(IPythonError): pass
46
51
47 class EngineCreationError(EngineError): pass
52 class EngineCreationError(EngineError): pass
48
53
49 class KernelError(IPythonError):
54 class KernelError(IPythonError):
50 pass
55 pass
51
56
52 class NotDefined(KernelError):
57 class NotDefined(KernelError):
53 def __init__(self, name):
58 def __init__(self, name):
54 self.name = name
59 self.name = name
55 self.args = (name,)
60 self.args = (name,)
56
61
57 def __repr__(self):
62 def __repr__(self):
58 return '<NotDefined: %s>' % self.name
63 return '<NotDefined: %s>' % self.name
59
64
60 __str__ = __repr__
65 __str__ = __repr__
61
66
62
67
63 class QueueCleared(KernelError):
68 class QueueCleared(KernelError):
64 pass
69 pass
65
70
66
71
67 class IdInUse(KernelError):
72 class IdInUse(KernelError):
68 pass
73 pass
69
74
70
75
71 class ProtocolError(KernelError):
76 class ProtocolError(KernelError):
72 pass
77 pass
73
78
74
79
75 class ConnectionError(KernelError):
80 class ConnectionError(KernelError):
76 pass
81 pass
77
82
78
83
79 class InvalidEngineID(KernelError):
84 class InvalidEngineID(KernelError):
80 pass
85 pass
81
86
82
87
83 class NoEnginesRegistered(KernelError):
88 class NoEnginesRegistered(KernelError):
84 pass
89 pass
85
90
86
91
87 class InvalidClientID(KernelError):
92 class InvalidClientID(KernelError):
88 pass
93 pass
89
94
90
95
91 class InvalidDeferredID(KernelError):
96 class InvalidDeferredID(KernelError):
92 pass
97 pass
93
98
94
99
95 class SerializationError(KernelError):
100 class SerializationError(KernelError):
96 pass
101 pass
97
102
98
103
99 class MessageSizeError(KernelError):
104 class MessageSizeError(KernelError):
100 pass
105 pass
101
106
102
107
103 class PBMessageSizeError(MessageSizeError):
108 class PBMessageSizeError(MessageSizeError):
104 pass
109 pass
105
110
106
111
107 class ResultNotCompleted(KernelError):
112 class ResultNotCompleted(KernelError):
108 pass
113 pass
109
114
110
115
111 class ResultAlreadyRetrieved(KernelError):
116 class ResultAlreadyRetrieved(KernelError):
112 pass
117 pass
113
118
114 class ClientError(KernelError):
119 class ClientError(KernelError):
115 pass
120 pass
116
121
117
122
118 class TaskAborted(KernelError):
123 class TaskAborted(KernelError):
119 pass
124 pass
120
125
121
126
122 class TaskTimeout(KernelError):
127 class TaskTimeout(KernelError):
123 pass
128 pass
124
129
125
130
126 class NotAPendingResult(KernelError):
131 class NotAPendingResult(KernelError):
127 pass
132 pass
128
133
129
134
130 class UnpickleableException(KernelError):
135 class UnpickleableException(KernelError):
131 pass
136 pass
132
137
133
138
134 class AbortedPendingDeferredError(KernelError):
139 class AbortedPendingDeferredError(KernelError):
135 pass
140 pass
136
141
137
142
138 class InvalidProperty(KernelError):
143 class InvalidProperty(KernelError):
139 pass
144 pass
140
145
141
146
142 class MissingBlockArgument(KernelError):
147 class MissingBlockArgument(KernelError):
143 pass
148 pass
144
149
145
150
146 class StopLocalExecution(KernelError):
151 class StopLocalExecution(KernelError):
147 pass
152 pass
148
153
149
154
150 class SecurityError(KernelError):
155 class SecurityError(KernelError):
151 pass
156 pass
152
157
153
158
154 class FileTimeoutError(KernelError):
159 class FileTimeoutError(KernelError):
155 pass
160 pass
156
161
157 class TimeoutError(KernelError):
162 class TimeoutError(KernelError):
158 pass
163 pass
159
164
160 class UnmetDependency(KernelError):
165 class UnmetDependency(KernelError):
161 pass
166 pass
162
167
163 class ImpossibleDependency(UnmetDependency):
168 class ImpossibleDependency(UnmetDependency):
164 pass
169 pass
165
170
166 class DependencyTimeout(ImpossibleDependency):
171 class DependencyTimeout(ImpossibleDependency):
167 pass
172 pass
168
173
169 class InvalidDependency(ImpossibleDependency):
174 class InvalidDependency(ImpossibleDependency):
170 pass
175 pass
171
176
172 class RemoteError(KernelError):
177 class RemoteError(KernelError):
173 """Error raised elsewhere"""
178 """Error raised elsewhere"""
174 ename=None
179 ename=None
175 evalue=None
180 evalue=None
176 traceback=None
181 traceback=None
177 engine_info=None
182 engine_info=None
178
183
179 def __init__(self, ename, evalue, traceback, engine_info=None):
184 def __init__(self, ename, evalue, traceback, engine_info=None):
180 self.ename=ename
185 self.ename=ename
181 self.evalue=evalue
186 self.evalue=evalue
182 self.traceback=traceback
187 self.traceback=traceback
183 self.engine_info=engine_info or {}
188 self.engine_info=engine_info or {}
184 self.args=(ename, evalue)
189 self.args=(ename, evalue)
185
190
186 def __repr__(self):
191 def __repr__(self):
187 engineid = self.engine_info.get('engine_id', ' ')
192 engineid = self.engine_info.get('engine_id', ' ')
188 return "<Remote[%s]:%s(%s)>"%(engineid, self.ename, self.evalue)
193 return "<Remote[%s]:%s(%s)>"%(engineid, self.ename, self.evalue)
189
194
190 def __str__(self):
195 def __str__(self):
191 return "%s(%s)" % (self.ename, self.evalue)
196 return "%s(%s)" % (self.ename, self.evalue)
192
197
193 def render_traceback(self):
198 def render_traceback(self):
194 """render traceback to a list of lines"""
199 """render traceback to a list of lines"""
195 return (self.traceback or "No traceback available").splitlines()
200 return (self.traceback or "No traceback available").splitlines()
196
201
197 def _render_traceback_(self):
202 def _render_traceback_(self):
198 """Special method for custom tracebacks within IPython.
203 """Special method for custom tracebacks within IPython.
199
204
200 This will be called by IPython instead of displaying the local traceback.
205 This will be called by IPython instead of displaying the local traceback.
201
206
202 It should return a traceback rendered as a list of lines.
207 It should return a traceback rendered as a list of lines.
203 """
208 """
204 return self.render_traceback()
209 return self.render_traceback()
205
210
206 def print_traceback(self, excid=None):
211 def print_traceback(self, excid=None):
207 """print my traceback"""
212 """print my traceback"""
208 print('\n'.join(self.render_traceback()))
213 print('\n'.join(self.render_traceback()))
209
214
210
215
211
216
212
217
213 class TaskRejectError(KernelError):
218 class TaskRejectError(KernelError):
214 """Exception to raise when a task should be rejected by an engine.
219 """Exception to raise when a task should be rejected by an engine.
215
220
216 This exception can be used to allow a task running on an engine to test
221 This exception can be used to allow a task running on an engine to test
217 if the engine (or the user's namespace on the engine) has the needed
222 if the engine (or the user's namespace on the engine) has the needed
218 task dependencies. If not, the task should raise this exception. For
223 task dependencies. If not, the task should raise this exception. For
219 the task to be retried on another engine, the task should be created
224 the task to be retried on another engine, the task should be created
220 with the `retries` argument > 1.
225 with the `retries` argument > 1.
221
226
222 The advantage of this approach over our older properties system is that
227 The advantage of this approach over our older properties system is that
223 tasks have full access to the user's namespace on the engines and the
228 tasks have full access to the user's namespace on the engines and the
224 properties don't have to be managed or tested by the controller.
229 properties don't have to be managed or tested by the controller.
225 """
230 """
226
231
227
232
228 class CompositeError(RemoteError):
233 class CompositeError(RemoteError):
229 """Error for representing possibly multiple errors on engines"""
234 """Error for representing possibly multiple errors on engines"""
230 def __init__(self, message, elist):
235 def __init__(self, message, elist):
231 Exception.__init__(self, *(message, elist))
236 Exception.__init__(self, *(message, elist))
232 # Don't use pack_exception because it will conflict with the .message
237 # Don't use pack_exception because it will conflict with the .message
233 # attribute that is being deprecated in 2.6 and beyond.
238 # attribute that is being deprecated in 2.6 and beyond.
234 self.msg = message
239 self.msg = message
235 self.elist = elist
240 self.elist = elist
236 self.args = [ e[0] for e in elist ]
241 self.args = [ e[0] for e in elist ]
237
242
238 def _get_engine_str(self, ei):
243 def _get_engine_str(self, ei):
239 if not ei:
244 if not ei:
240 return '[Engine Exception]'
245 return '[Engine Exception]'
241 else:
246 else:
242 return '[%s:%s]: ' % (ei['engine_id'], ei['method'])
247 return '[%s:%s]: ' % (ei['engine_id'], ei['method'])
243
248
244 def _get_traceback(self, ev):
249 def _get_traceback(self, ev):
245 try:
250 try:
246 tb = ev._ipython_traceback_text
251 tb = ev._ipython_traceback_text
247 except AttributeError:
252 except AttributeError:
248 return 'No traceback available'
253 return 'No traceback available'
249 else:
254 else:
250 return tb
255 return tb
251
256
252 def __str__(self):
257 def __str__(self):
253 s = str(self.msg)
258 s = str(self.msg)
254 for en, ev, etb, ei in self.elist:
259 for en, ev, etb, ei in self.elist:
255 engine_str = self._get_engine_str(ei)
260 engine_str = self._get_engine_str(ei)
256 s = s + '\n' + engine_str + en + ': ' + str(ev)
261 s = s + '\n' + engine_str + en + ': ' + str(ev)
257 return s
262 return s
258
263
259 def __repr__(self):
264 def __repr__(self):
260 return "CompositeError(%i)"%len(self.elist)
265 return "CompositeError(%i)"%len(self.elist)
261
266
262 def render_traceback(self, excid=None):
267 def render_traceback(self, excid=None):
263 """render one or all of my tracebacks to a list of lines"""
268 """render one or all of my tracebacks to a list of lines"""
264 lines = []
269 lines = []
265 if excid is None:
270 if excid is None:
266 for (en,ev,etb,ei) in self.elist:
271 for (en,ev,etb,ei) in self.elist:
267 lines.append(self._get_engine_str(ei))
272 lines.append(self._get_engine_str(ei))
268 lines.extend((etb or 'No traceback available').splitlines())
273 lines.extend((etb or 'No traceback available').splitlines())
269 lines.append('')
274 lines.append('')
270 else:
275 else:
271 try:
276 try:
272 en,ev,etb,ei = self.elist[excid]
277 en,ev,etb,ei = self.elist[excid]
273 except:
278 except:
274 raise IndexError("an exception with index %i does not exist"%excid)
279 raise IndexError("an exception with index %i does not exist"%excid)
275 else:
280 else:
276 lines.append(self._get_engine_str(ei))
281 lines.append(self._get_engine_str(ei))
277 lines.extend((etb or 'No traceback available').splitlines())
282 lines.extend((etb or 'No traceback available').splitlines())
278
283
279 return lines
284 return lines
280
285
281 def print_traceback(self, excid=None):
286 def print_traceback(self, excid=None):
282 print('\n'.join(self.render_traceback(excid)))
287 print('\n'.join(self.render_traceback(excid)))
283
288
284 def raise_exception(self, excid=0):
289 def raise_exception(self, excid=0):
285 try:
290 try:
286 en,ev,etb,ei = self.elist[excid]
291 en,ev,etb,ei = self.elist[excid]
287 except:
292 except:
288 raise IndexError("an exception with index %i does not exist"%excid)
293 raise IndexError("an exception with index %i does not exist"%excid)
289 else:
294 else:
290 raise RemoteError(en, ev, etb, ei)
295 raise RemoteError(en, ev, etb, ei)
291
296
292
297
293 def collect_exceptions(rdict_or_list, method='unspecified'):
298 def collect_exceptions(rdict_or_list, method='unspecified'):
294 """check a result dict for errors, and raise CompositeError if any exist.
299 """check a result dict for errors, and raise CompositeError if any exist.
295 Passthrough otherwise."""
300 Passthrough otherwise."""
296 elist = []
301 elist = []
297 if isinstance(rdict_or_list, dict):
302 if isinstance(rdict_or_list, dict):
298 rlist = rdict_or_list.values()
303 rlist = rdict_or_list.values()
299 else:
304 else:
300 rlist = rdict_or_list
305 rlist = rdict_or_list
301 for r in rlist:
306 for r in rlist:
302 if isinstance(r, RemoteError):
307 if isinstance(r, RemoteError):
303 en, ev, etb, ei = r.ename, r.evalue, r.traceback, r.engine_info
308 en, ev, etb, ei = r.ename, r.evalue, r.traceback, r.engine_info
304 # Sometimes we could have CompositeError in our list. Just take
309 # Sometimes we could have CompositeError in our list. Just take
305 # the errors out of them and put them in our new list. This
310 # the errors out of them and put them in our new list. This
306 # has the effect of flattening lists of CompositeErrors into one
311 # has the effect of flattening lists of CompositeErrors into one
307 # CompositeError
312 # CompositeError
308 if en=='CompositeError':
313 if en=='CompositeError':
309 for e in ev.elist:
314 for e in ev.elist:
310 elist.append(e)
315 elist.append(e)
311 else:
316 else:
312 elist.append((en, ev, etb, ei))
317 elist.append((en, ev, etb, ei))
313 if len(elist)==0:
318 if len(elist)==0:
314 return rdict_or_list
319 return rdict_or_list
315 else:
320 else:
316 msg = "one or more exceptions from call to method: %s" % (method)
321 msg = "one or more exceptions from call to method: %s" % (method)
317 # This silliness is needed so the debugger has access to the exception
322 # This silliness is needed so the debugger has access to the exception
318 # instance (e in this case)
323 # instance (e in this case)
319 try:
324 try:
320 raise CompositeError(msg, elist)
325 raise CompositeError(msg, elist)
321 except CompositeError as e:
326 except CompositeError as e:
322 raise e
327 raise e
323
328
324 def wrap_exception(engine_info={}):
329 def wrap_exception(engine_info={}):
325 etype, evalue, tb = sys.exc_info()
330 etype, evalue, tb = sys.exc_info()
326 stb = traceback.format_exception(etype, evalue, tb)
331 stb = traceback.format_exception(etype, evalue, tb)
327 exc_content = {
332 exc_content = {
328 'status' : 'error',
333 'status' : 'error',
329 'traceback' : stb,
334 'traceback' : stb,
330 'ename' : unicode(etype.__name__),
335 'ename' : unicode(etype.__name__),
331 'evalue' : unicode(evalue),
336 'evalue' : unicode(evalue),
332 'engine_info' : engine_info
337 'engine_info' : engine_info
333 }
338 }
334 return exc_content
339 return exc_content
335
340
336 def unwrap_exception(content):
341 def unwrap_exception(content):
337 err = RemoteError(content['ename'], content['evalue'],
342 err = RemoteError(content['ename'], content['evalue'],
338 ''.join(content['traceback']),
343 ''.join(content['traceback']),
339 content.get('engine_info', {}))
344 content.get('engine_info', {}))
340 return err
345 return err
341
346
@@ -1,845 +1,850 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for working with strings and text.
3 Utilities for working with strings and text.
4
5 Inheritance diagram:
6
7 .. inheritance-diagram:: IPython.utils.text
8 :parts: 3
4 """
9 """
5
10
6 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
8 #
13 #
9 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
12
17
13 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
14 # Imports
19 # Imports
15 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
16
21
17 import __main__
22 import __main__
18
23
19 import os
24 import os
20 import re
25 import re
21 import shutil
26 import shutil
22 import sys
27 import sys
23 import textwrap
28 import textwrap
24 from string import Formatter
29 from string import Formatter
25
30
26 from IPython.external.path import path
31 from IPython.external.path import path
27 from IPython.testing.skipdoctest import skip_doctest_py3, skip_doctest
32 from IPython.testing.skipdoctest import skip_doctest_py3, skip_doctest
28 from IPython.utils import py3compat
33 from IPython.utils import py3compat
29 from IPython.utils.io import nlprint
34 from IPython.utils.io import nlprint
30 from IPython.utils.data import flatten
35 from IPython.utils.data import flatten
31
36
32 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
33 # Code
38 # Code
34 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
35
40
36 def unquote_ends(istr):
41 def unquote_ends(istr):
37 """Remove a single pair of quotes from the endpoints of a string."""
42 """Remove a single pair of quotes from the endpoints of a string."""
38
43
39 if not istr:
44 if not istr:
40 return istr
45 return istr
41 if (istr[0]=="'" and istr[-1]=="'") or \
46 if (istr[0]=="'" and istr[-1]=="'") or \
42 (istr[0]=='"' and istr[-1]=='"'):
47 (istr[0]=='"' and istr[-1]=='"'):
43 return istr[1:-1]
48 return istr[1:-1]
44 else:
49 else:
45 return istr
50 return istr
46
51
47
52
48 class LSString(str):
53 class LSString(str):
49 """String derivative with a special access attributes.
54 """String derivative with a special access attributes.
50
55
51 These are normal strings, but with the special attributes:
56 These are normal strings, but with the special attributes:
52
57
53 .l (or .list) : value as list (split on newlines).
58 .l (or .list) : value as list (split on newlines).
54 .n (or .nlstr): original value (the string itself).
59 .n (or .nlstr): original value (the string itself).
55 .s (or .spstr): value as whitespace-separated string.
60 .s (or .spstr): value as whitespace-separated string.
56 .p (or .paths): list of path objects
61 .p (or .paths): list of path objects
57
62
58 Any values which require transformations are computed only once and
63 Any values which require transformations are computed only once and
59 cached.
64 cached.
60
65
61 Such strings are very useful to efficiently interact with the shell, which
66 Such strings are very useful to efficiently interact with the shell, which
62 typically only understands whitespace-separated options for commands."""
67 typically only understands whitespace-separated options for commands."""
63
68
64 def get_list(self):
69 def get_list(self):
65 try:
70 try:
66 return self.__list
71 return self.__list
67 except AttributeError:
72 except AttributeError:
68 self.__list = self.split('\n')
73 self.__list = self.split('\n')
69 return self.__list
74 return self.__list
70
75
71 l = list = property(get_list)
76 l = list = property(get_list)
72
77
73 def get_spstr(self):
78 def get_spstr(self):
74 try:
79 try:
75 return self.__spstr
80 return self.__spstr
76 except AttributeError:
81 except AttributeError:
77 self.__spstr = self.replace('\n',' ')
82 self.__spstr = self.replace('\n',' ')
78 return self.__spstr
83 return self.__spstr
79
84
80 s = spstr = property(get_spstr)
85 s = spstr = property(get_spstr)
81
86
82 def get_nlstr(self):
87 def get_nlstr(self):
83 return self
88 return self
84
89
85 n = nlstr = property(get_nlstr)
90 n = nlstr = property(get_nlstr)
86
91
87 def get_paths(self):
92 def get_paths(self):
88 try:
93 try:
89 return self.__paths
94 return self.__paths
90 except AttributeError:
95 except AttributeError:
91 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
96 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
92 return self.__paths
97 return self.__paths
93
98
94 p = paths = property(get_paths)
99 p = paths = property(get_paths)
95
100
96 # FIXME: We need to reimplement type specific displayhook and then add this
101 # FIXME: We need to reimplement type specific displayhook and then add this
97 # back as a custom printer. This should also be moved outside utils into the
102 # back as a custom printer. This should also be moved outside utils into the
98 # core.
103 # core.
99
104
100 # def print_lsstring(arg):
105 # def print_lsstring(arg):
101 # """ Prettier (non-repr-like) and more informative printer for LSString """
106 # """ Prettier (non-repr-like) and more informative printer for LSString """
102 # print "LSString (.p, .n, .l, .s available). Value:"
107 # print "LSString (.p, .n, .l, .s available). Value:"
103 # print arg
108 # print arg
104 #
109 #
105 #
110 #
106 # print_lsstring = result_display.when_type(LSString)(print_lsstring)
111 # print_lsstring = result_display.when_type(LSString)(print_lsstring)
107
112
108
113
109 class SList(list):
114 class SList(list):
110 """List derivative with a special access attributes.
115 """List derivative with a special access attributes.
111
116
112 These are normal lists, but with the special attributes:
117 These are normal lists, but with the special attributes:
113
118
114 .l (or .list) : value as list (the list itself).
119 .l (or .list) : value as list (the list itself).
115 .n (or .nlstr): value as a string, joined on newlines.
120 .n (or .nlstr): value as a string, joined on newlines.
116 .s (or .spstr): value as a string, joined on spaces.
121 .s (or .spstr): value as a string, joined on spaces.
117 .p (or .paths): list of path objects
122 .p (or .paths): list of path objects
118
123
119 Any values which require transformations are computed only once and
124 Any values which require transformations are computed only once and
120 cached."""
125 cached."""
121
126
122 def get_list(self):
127 def get_list(self):
123 return self
128 return self
124
129
125 l = list = property(get_list)
130 l = list = property(get_list)
126
131
127 def get_spstr(self):
132 def get_spstr(self):
128 try:
133 try:
129 return self.__spstr
134 return self.__spstr
130 except AttributeError:
135 except AttributeError:
131 self.__spstr = ' '.join(self)
136 self.__spstr = ' '.join(self)
132 return self.__spstr
137 return self.__spstr
133
138
134 s = spstr = property(get_spstr)
139 s = spstr = property(get_spstr)
135
140
136 def get_nlstr(self):
141 def get_nlstr(self):
137 try:
142 try:
138 return self.__nlstr
143 return self.__nlstr
139 except AttributeError:
144 except AttributeError:
140 self.__nlstr = '\n'.join(self)
145 self.__nlstr = '\n'.join(self)
141 return self.__nlstr
146 return self.__nlstr
142
147
143 n = nlstr = property(get_nlstr)
148 n = nlstr = property(get_nlstr)
144
149
145 def get_paths(self):
150 def get_paths(self):
146 try:
151 try:
147 return self.__paths
152 return self.__paths
148 except AttributeError:
153 except AttributeError:
149 self.__paths = [path(p) for p in self if os.path.exists(p)]
154 self.__paths = [path(p) for p in self if os.path.exists(p)]
150 return self.__paths
155 return self.__paths
151
156
152 p = paths = property(get_paths)
157 p = paths = property(get_paths)
153
158
154 def grep(self, pattern, prune = False, field = None):
159 def grep(self, pattern, prune = False, field = None):
155 """ Return all strings matching 'pattern' (a regex or callable)
160 """ Return all strings matching 'pattern' (a regex or callable)
156
161
157 This is case-insensitive. If prune is true, return all items
162 This is case-insensitive. If prune is true, return all items
158 NOT matching the pattern.
163 NOT matching the pattern.
159
164
160 If field is specified, the match must occur in the specified
165 If field is specified, the match must occur in the specified
161 whitespace-separated field.
166 whitespace-separated field.
162
167
163 Examples::
168 Examples::
164
169
165 a.grep( lambda x: x.startswith('C') )
170 a.grep( lambda x: x.startswith('C') )
166 a.grep('Cha.*log', prune=1)
171 a.grep('Cha.*log', prune=1)
167 a.grep('chm', field=-1)
172 a.grep('chm', field=-1)
168 """
173 """
169
174
170 def match_target(s):
175 def match_target(s):
171 if field is None:
176 if field is None:
172 return s
177 return s
173 parts = s.split()
178 parts = s.split()
174 try:
179 try:
175 tgt = parts[field]
180 tgt = parts[field]
176 return tgt
181 return tgt
177 except IndexError:
182 except IndexError:
178 return ""
183 return ""
179
184
180 if isinstance(pattern, basestring):
185 if isinstance(pattern, basestring):
181 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
186 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
182 else:
187 else:
183 pred = pattern
188 pred = pattern
184 if not prune:
189 if not prune:
185 return SList([el for el in self if pred(match_target(el))])
190 return SList([el for el in self if pred(match_target(el))])
186 else:
191 else:
187 return SList([el for el in self if not pred(match_target(el))])
192 return SList([el for el in self if not pred(match_target(el))])
188
193
189 def fields(self, *fields):
194 def fields(self, *fields):
190 """ Collect whitespace-separated fields from string list
195 """ Collect whitespace-separated fields from string list
191
196
192 Allows quick awk-like usage of string lists.
197 Allows quick awk-like usage of string lists.
193
198
194 Example data (in var a, created by 'a = !ls -l')::
199 Example data (in var a, created by 'a = !ls -l')::
195 -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
200 -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
196 drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
201 drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
197
202
198 a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
203 a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
199 a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
204 a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
200 (note the joining by space).
205 (note the joining by space).
201 a.fields(-1) is ['ChangeLog', 'IPython']
206 a.fields(-1) is ['ChangeLog', 'IPython']
202
207
203 IndexErrors are ignored.
208 IndexErrors are ignored.
204
209
205 Without args, fields() just split()'s the strings.
210 Without args, fields() just split()'s the strings.
206 """
211 """
207 if len(fields) == 0:
212 if len(fields) == 0:
208 return [el.split() for el in self]
213 return [el.split() for el in self]
209
214
210 res = SList()
215 res = SList()
211 for el in [f.split() for f in self]:
216 for el in [f.split() for f in self]:
212 lineparts = []
217 lineparts = []
213
218
214 for fd in fields:
219 for fd in fields:
215 try:
220 try:
216 lineparts.append(el[fd])
221 lineparts.append(el[fd])
217 except IndexError:
222 except IndexError:
218 pass
223 pass
219 if lineparts:
224 if lineparts:
220 res.append(" ".join(lineparts))
225 res.append(" ".join(lineparts))
221
226
222 return res
227 return res
223
228
224 def sort(self,field= None, nums = False):
229 def sort(self,field= None, nums = False):
225 """ sort by specified fields (see fields())
230 """ sort by specified fields (see fields())
226
231
227 Example::
232 Example::
228 a.sort(1, nums = True)
233 a.sort(1, nums = True)
229
234
230 Sorts a by second field, in numerical order (so that 21 > 3)
235 Sorts a by second field, in numerical order (so that 21 > 3)
231
236
232 """
237 """
233
238
234 #decorate, sort, undecorate
239 #decorate, sort, undecorate
235 if field is not None:
240 if field is not None:
236 dsu = [[SList([line]).fields(field), line] for line in self]
241 dsu = [[SList([line]).fields(field), line] for line in self]
237 else:
242 else:
238 dsu = [[line, line] for line in self]
243 dsu = [[line, line] for line in self]
239 if nums:
244 if nums:
240 for i in range(len(dsu)):
245 for i in range(len(dsu)):
241 numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
246 numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
242 try:
247 try:
243 n = int(numstr)
248 n = int(numstr)
244 except ValueError:
249 except ValueError:
245 n = 0;
250 n = 0;
246 dsu[i][0] = n
251 dsu[i][0] = n
247
252
248
253
249 dsu.sort()
254 dsu.sort()
250 return SList([t[1] for t in dsu])
255 return SList([t[1] for t in dsu])
251
256
252
257
253 # FIXME: We need to reimplement type specific displayhook and then add this
258 # FIXME: We need to reimplement type specific displayhook and then add this
254 # back as a custom printer. This should also be moved outside utils into the
259 # back as a custom printer. This should also be moved outside utils into the
255 # core.
260 # core.
256
261
257 # def print_slist(arg):
262 # def print_slist(arg):
258 # """ Prettier (non-repr-like) and more informative printer for SList """
263 # """ Prettier (non-repr-like) and more informative printer for SList """
259 # print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
264 # print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
260 # if hasattr(arg, 'hideonce') and arg.hideonce:
265 # if hasattr(arg, 'hideonce') and arg.hideonce:
261 # arg.hideonce = False
266 # arg.hideonce = False
262 # return
267 # return
263 #
268 #
264 # nlprint(arg)
269 # nlprint(arg)
265 #
270 #
266 # print_slist = result_display.when_type(SList)(print_slist)
271 # print_slist = result_display.when_type(SList)(print_slist)
267
272
268
273
269 def esc_quotes(strng):
274 def esc_quotes(strng):
270 """Return the input string with single and double quotes escaped out"""
275 """Return the input string with single and double quotes escaped out"""
271
276
272 return strng.replace('"','\\"').replace("'","\\'")
277 return strng.replace('"','\\"').replace("'","\\'")
273
278
274
279
275 def qw(words,flat=0,sep=None,maxsplit=-1):
280 def qw(words,flat=0,sep=None,maxsplit=-1):
276 """Similar to Perl's qw() operator, but with some more options.
281 """Similar to Perl's qw() operator, but with some more options.
277
282
278 qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
283 qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
279
284
280 words can also be a list itself, and with flat=1, the output will be
285 words can also be a list itself, and with flat=1, the output will be
281 recursively flattened.
286 recursively flattened.
282
287
283 Examples:
288 Examples:
284
289
285 >>> qw('1 2')
290 >>> qw('1 2')
286 ['1', '2']
291 ['1', '2']
287
292
288 >>> qw(['a b','1 2',['m n','p q']])
293 >>> qw(['a b','1 2',['m n','p q']])
289 [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
294 [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
290
295
291 >>> qw(['a b','1 2',['m n','p q']],flat=1)
296 >>> qw(['a b','1 2',['m n','p q']],flat=1)
292 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
297 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
293 """
298 """
294
299
295 if isinstance(words, basestring):
300 if isinstance(words, basestring):
296 return [word.strip() for word in words.split(sep,maxsplit)
301 return [word.strip() for word in words.split(sep,maxsplit)
297 if word and not word.isspace() ]
302 if word and not word.isspace() ]
298 if flat:
303 if flat:
299 return flatten(map(qw,words,[1]*len(words)))
304 return flatten(map(qw,words,[1]*len(words)))
300 return map(qw,words)
305 return map(qw,words)
301
306
302
307
303 def qwflat(words,sep=None,maxsplit=-1):
308 def qwflat(words,sep=None,maxsplit=-1):
304 """Calls qw(words) in flat mode. It's just a convenient shorthand."""
309 """Calls qw(words) in flat mode. It's just a convenient shorthand."""
305 return qw(words,1,sep,maxsplit)
310 return qw(words,1,sep,maxsplit)
306
311
307
312
308 def qw_lol(indata):
313 def qw_lol(indata):
309 """qw_lol('a b') -> [['a','b']],
314 """qw_lol('a b') -> [['a','b']],
310 otherwise it's just a call to qw().
315 otherwise it's just a call to qw().
311
316
312 We need this to make sure the modules_some keys *always* end up as a
317 We need this to make sure the modules_some keys *always* end up as a
313 list of lists."""
318 list of lists."""
314
319
315 if isinstance(indata, basestring):
320 if isinstance(indata, basestring):
316 return [qw(indata)]
321 return [qw(indata)]
317 else:
322 else:
318 return qw(indata)
323 return qw(indata)
319
324
320
325
321 def grep(pat,list,case=1):
326 def grep(pat,list,case=1):
322 """Simple minded grep-like function.
327 """Simple minded grep-like function.
323 grep(pat,list) returns occurrences of pat in list, None on failure.
328 grep(pat,list) returns occurrences of pat in list, None on failure.
324
329
325 It only does simple string matching, with no support for regexps. Use the
330 It only does simple string matching, with no support for regexps. Use the
326 option case=0 for case-insensitive matching."""
331 option case=0 for case-insensitive matching."""
327
332
328 # This is pretty crude. At least it should implement copying only references
333 # This is pretty crude. At least it should implement copying only references
329 # to the original data in case it's big. Now it copies the data for output.
334 # to the original data in case it's big. Now it copies the data for output.
330 out=[]
335 out=[]
331 if case:
336 if case:
332 for term in list:
337 for term in list:
333 if term.find(pat)>-1: out.append(term)
338 if term.find(pat)>-1: out.append(term)
334 else:
339 else:
335 lpat=pat.lower()
340 lpat=pat.lower()
336 for term in list:
341 for term in list:
337 if term.lower().find(lpat)>-1: out.append(term)
342 if term.lower().find(lpat)>-1: out.append(term)
338
343
339 if len(out): return out
344 if len(out): return out
340 else: return None
345 else: return None
341
346
342
347
343 def dgrep(pat,*opts):
348 def dgrep(pat,*opts):
344 """Return grep() on dir()+dir(__builtins__).
349 """Return grep() on dir()+dir(__builtins__).
345
350
346 A very common use of grep() when working interactively."""
351 A very common use of grep() when working interactively."""
347
352
348 return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
353 return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
349
354
350
355
351 def idgrep(pat):
356 def idgrep(pat):
352 """Case-insensitive dgrep()"""
357 """Case-insensitive dgrep()"""
353
358
354 return dgrep(pat,0)
359 return dgrep(pat,0)
355
360
356
361
357 def igrep(pat,list):
362 def igrep(pat,list):
358 """Synonym for case-insensitive grep."""
363 """Synonym for case-insensitive grep."""
359
364
360 return grep(pat,list,case=0)
365 return grep(pat,list,case=0)
361
366
362
367
363 def indent(instr,nspaces=4, ntabs=0, flatten=False):
368 def indent(instr,nspaces=4, ntabs=0, flatten=False):
364 """Indent a string a given number of spaces or tabstops.
369 """Indent a string a given number of spaces or tabstops.
365
370
366 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
371 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
367
372
368 Parameters
373 Parameters
369 ----------
374 ----------
370
375
371 instr : basestring
376 instr : basestring
372 The string to be indented.
377 The string to be indented.
373 nspaces : int (default: 4)
378 nspaces : int (default: 4)
374 The number of spaces to be indented.
379 The number of spaces to be indented.
375 ntabs : int (default: 0)
380 ntabs : int (default: 0)
376 The number of tabs to be indented.
381 The number of tabs to be indented.
377 flatten : bool (default: False)
382 flatten : bool (default: False)
378 Whether to scrub existing indentation. If True, all lines will be
383 Whether to scrub existing indentation. If True, all lines will be
379 aligned to the same indentation. If False, existing indentation will
384 aligned to the same indentation. If False, existing indentation will
380 be strictly increased.
385 be strictly increased.
381
386
382 Returns
387 Returns
383 -------
388 -------
384
389
385 str|unicode : string indented by ntabs and nspaces.
390 str|unicode : string indented by ntabs and nspaces.
386
391
387 """
392 """
388 if instr is None:
393 if instr is None:
389 return
394 return
390 ind = '\t'*ntabs+' '*nspaces
395 ind = '\t'*ntabs+' '*nspaces
391 if flatten:
396 if flatten:
392 pat = re.compile(r'^\s*', re.MULTILINE)
397 pat = re.compile(r'^\s*', re.MULTILINE)
393 else:
398 else:
394 pat = re.compile(r'^', re.MULTILINE)
399 pat = re.compile(r'^', re.MULTILINE)
395 outstr = re.sub(pat, ind, instr)
400 outstr = re.sub(pat, ind, instr)
396 if outstr.endswith(os.linesep+ind):
401 if outstr.endswith(os.linesep+ind):
397 return outstr[:-len(ind)]
402 return outstr[:-len(ind)]
398 else:
403 else:
399 return outstr
404 return outstr
400
405
401 def native_line_ends(filename,backup=1):
406 def native_line_ends(filename,backup=1):
402 """Convert (in-place) a file to line-ends native to the current OS.
407 """Convert (in-place) a file to line-ends native to the current OS.
403
408
404 If the optional backup argument is given as false, no backup of the
409 If the optional backup argument is given as false, no backup of the
405 original file is left. """
410 original file is left. """
406
411
407 backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
412 backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
408
413
409 bak_filename = filename + backup_suffixes[os.name]
414 bak_filename = filename + backup_suffixes[os.name]
410
415
411 original = open(filename).read()
416 original = open(filename).read()
412 shutil.copy2(filename,bak_filename)
417 shutil.copy2(filename,bak_filename)
413 try:
418 try:
414 new = open(filename,'wb')
419 new = open(filename,'wb')
415 new.write(os.linesep.join(original.splitlines()))
420 new.write(os.linesep.join(original.splitlines()))
416 new.write(os.linesep) # ALWAYS put an eol at the end of the file
421 new.write(os.linesep) # ALWAYS put an eol at the end of the file
417 new.close()
422 new.close()
418 except:
423 except:
419 os.rename(bak_filename,filename)
424 os.rename(bak_filename,filename)
420 if not backup:
425 if not backup:
421 try:
426 try:
422 os.remove(bak_filename)
427 os.remove(bak_filename)
423 except:
428 except:
424 pass
429 pass
425
430
426
431
427 def list_strings(arg):
432 def list_strings(arg):
428 """Always return a list of strings, given a string or list of strings
433 """Always return a list of strings, given a string or list of strings
429 as input.
434 as input.
430
435
431 :Examples:
436 :Examples:
432
437
433 In [7]: list_strings('A single string')
438 In [7]: list_strings('A single string')
434 Out[7]: ['A single string']
439 Out[7]: ['A single string']
435
440
436 In [8]: list_strings(['A single string in a list'])
441 In [8]: list_strings(['A single string in a list'])
437 Out[8]: ['A single string in a list']
442 Out[8]: ['A single string in a list']
438
443
439 In [9]: list_strings(['A','list','of','strings'])
444 In [9]: list_strings(['A','list','of','strings'])
440 Out[9]: ['A', 'list', 'of', 'strings']
445 Out[9]: ['A', 'list', 'of', 'strings']
441 """
446 """
442
447
443 if isinstance(arg,basestring): return [arg]
448 if isinstance(arg,basestring): return [arg]
444 else: return arg
449 else: return arg
445
450
446
451
447 def marquee(txt='',width=78,mark='*'):
452 def marquee(txt='',width=78,mark='*'):
448 """Return the input string centered in a 'marquee'.
453 """Return the input string centered in a 'marquee'.
449
454
450 :Examples:
455 :Examples:
451
456
452 In [16]: marquee('A test',40)
457 In [16]: marquee('A test',40)
453 Out[16]: '**************** A test ****************'
458 Out[16]: '**************** A test ****************'
454
459
455 In [17]: marquee('A test',40,'-')
460 In [17]: marquee('A test',40,'-')
456 Out[17]: '---------------- A test ----------------'
461 Out[17]: '---------------- A test ----------------'
457
462
458 In [18]: marquee('A test',40,' ')
463 In [18]: marquee('A test',40,' ')
459 Out[18]: ' A test '
464 Out[18]: ' A test '
460
465
461 """
466 """
462 if not txt:
467 if not txt:
463 return (mark*width)[:width]
468 return (mark*width)[:width]
464 nmark = (width-len(txt)-2)//len(mark)//2
469 nmark = (width-len(txt)-2)//len(mark)//2
465 if nmark < 0: nmark =0
470 if nmark < 0: nmark =0
466 marks = mark*nmark
471 marks = mark*nmark
467 return '%s %s %s' % (marks,txt,marks)
472 return '%s %s %s' % (marks,txt,marks)
468
473
469
474
470 ini_spaces_re = re.compile(r'^(\s+)')
475 ini_spaces_re = re.compile(r'^(\s+)')
471
476
472 def num_ini_spaces(strng):
477 def num_ini_spaces(strng):
473 """Return the number of initial spaces in a string"""
478 """Return the number of initial spaces in a string"""
474
479
475 ini_spaces = ini_spaces_re.match(strng)
480 ini_spaces = ini_spaces_re.match(strng)
476 if ini_spaces:
481 if ini_spaces:
477 return ini_spaces.end()
482 return ini_spaces.end()
478 else:
483 else:
479 return 0
484 return 0
480
485
481
486
482 def format_screen(strng):
487 def format_screen(strng):
483 """Format a string for screen printing.
488 """Format a string for screen printing.
484
489
485 This removes some latex-type format codes."""
490 This removes some latex-type format codes."""
486 # Paragraph continue
491 # Paragraph continue
487 par_re = re.compile(r'\\$',re.MULTILINE)
492 par_re = re.compile(r'\\$',re.MULTILINE)
488 strng = par_re.sub('',strng)
493 strng = par_re.sub('',strng)
489 return strng
494 return strng
490
495
491
496
492 def dedent(text):
497 def dedent(text):
493 """Equivalent of textwrap.dedent that ignores unindented first line.
498 """Equivalent of textwrap.dedent that ignores unindented first line.
494
499
495 This means it will still dedent strings like:
500 This means it will still dedent strings like:
496 '''foo
501 '''foo
497 is a bar
502 is a bar
498 '''
503 '''
499
504
500 For use in wrap_paragraphs.
505 For use in wrap_paragraphs.
501 """
506 """
502
507
503 if text.startswith('\n'):
508 if text.startswith('\n'):
504 # text starts with blank line, don't ignore the first line
509 # text starts with blank line, don't ignore the first line
505 return textwrap.dedent(text)
510 return textwrap.dedent(text)
506
511
507 # split first line
512 # split first line
508 splits = text.split('\n',1)
513 splits = text.split('\n',1)
509 if len(splits) == 1:
514 if len(splits) == 1:
510 # only one line
515 # only one line
511 return textwrap.dedent(text)
516 return textwrap.dedent(text)
512
517
513 first, rest = splits
518 first, rest = splits
514 # dedent everything but the first line
519 # dedent everything but the first line
515 rest = textwrap.dedent(rest)
520 rest = textwrap.dedent(rest)
516 return '\n'.join([first, rest])
521 return '\n'.join([first, rest])
517
522
518
523
519 def wrap_paragraphs(text, ncols=80):
524 def wrap_paragraphs(text, ncols=80):
520 """Wrap multiple paragraphs to fit a specified width.
525 """Wrap multiple paragraphs to fit a specified width.
521
526
522 This is equivalent to textwrap.wrap, but with support for multiple
527 This is equivalent to textwrap.wrap, but with support for multiple
523 paragraphs, as separated by empty lines.
528 paragraphs, as separated by empty lines.
524
529
525 Returns
530 Returns
526 -------
531 -------
527
532
528 list of complete paragraphs, wrapped to fill `ncols` columns.
533 list of complete paragraphs, wrapped to fill `ncols` columns.
529 """
534 """
530 paragraph_re = re.compile(r'\n(\s*\n)+', re.MULTILINE)
535 paragraph_re = re.compile(r'\n(\s*\n)+', re.MULTILINE)
531 text = dedent(text).strip()
536 text = dedent(text).strip()
532 paragraphs = paragraph_re.split(text)[::2] # every other entry is space
537 paragraphs = paragraph_re.split(text)[::2] # every other entry is space
533 out_ps = []
538 out_ps = []
534 indent_re = re.compile(r'\n\s+', re.MULTILINE)
539 indent_re = re.compile(r'\n\s+', re.MULTILINE)
535 for p in paragraphs:
540 for p in paragraphs:
536 # presume indentation that survives dedent is meaningful formatting,
541 # presume indentation that survives dedent is meaningful formatting,
537 # so don't fill unless text is flush.
542 # so don't fill unless text is flush.
538 if indent_re.search(p) is None:
543 if indent_re.search(p) is None:
539 # wrap paragraph
544 # wrap paragraph
540 p = textwrap.fill(p, ncols)
545 p = textwrap.fill(p, ncols)
541 out_ps.append(p)
546 out_ps.append(p)
542 return out_ps
547 return out_ps
543
548
544
549
545 def long_substr(data):
550 def long_substr(data):
546 """Return the longest common substring in a list of strings.
551 """Return the longest common substring in a list of strings.
547
552
548 Credit: http://stackoverflow.com/questions/2892931/longest-common-substring-from-more-than-two-strings-python
553 Credit: http://stackoverflow.com/questions/2892931/longest-common-substring-from-more-than-two-strings-python
549 """
554 """
550 substr = ''
555 substr = ''
551 if len(data) > 1 and len(data[0]) > 0:
556 if len(data) > 1 and len(data[0]) > 0:
552 for i in range(len(data[0])):
557 for i in range(len(data[0])):
553 for j in range(len(data[0])-i+1):
558 for j in range(len(data[0])-i+1):
554 if j > len(substr) and all(data[0][i:i+j] in x for x in data):
559 if j > len(substr) and all(data[0][i:i+j] in x for x in data):
555 substr = data[0][i:i+j]
560 substr = data[0][i:i+j]
556 elif len(data) == 1:
561 elif len(data) == 1:
557 substr = data[0]
562 substr = data[0]
558 return substr
563 return substr
559
564
560
565
561 def strip_email_quotes(text):
566 def strip_email_quotes(text):
562 """Strip leading email quotation characters ('>').
567 """Strip leading email quotation characters ('>').
563
568
564 Removes any combination of leading '>' interspersed with whitespace that
569 Removes any combination of leading '>' interspersed with whitespace that
565 appears *identically* in all lines of the input text.
570 appears *identically* in all lines of the input text.
566
571
567 Parameters
572 Parameters
568 ----------
573 ----------
569 text : str
574 text : str
570
575
571 Examples
576 Examples
572 --------
577 --------
573
578
574 Simple uses::
579 Simple uses::
575
580
576 In [2]: strip_email_quotes('> > text')
581 In [2]: strip_email_quotes('> > text')
577 Out[2]: 'text'
582 Out[2]: 'text'
578
583
579 In [3]: strip_email_quotes('> > text\\n> > more')
584 In [3]: strip_email_quotes('> > text\\n> > more')
580 Out[3]: 'text\\nmore'
585 Out[3]: 'text\\nmore'
581
586
582 Note how only the common prefix that appears in all lines is stripped::
587 Note how only the common prefix that appears in all lines is stripped::
583
588
584 In [4]: strip_email_quotes('> > text\\n> > more\\n> more...')
589 In [4]: strip_email_quotes('> > text\\n> > more\\n> more...')
585 Out[4]: '> text\\n> more\\nmore...'
590 Out[4]: '> text\\n> more\\nmore...'
586
591
587 So if any line has no quote marks ('>') , then none are stripped from any
592 So if any line has no quote marks ('>') , then none are stripped from any
588 of them ::
593 of them ::
589
594
590 In [5]: strip_email_quotes('> > text\\n> > more\\nlast different')
595 In [5]: strip_email_quotes('> > text\\n> > more\\nlast different')
591 Out[5]: '> > text\\n> > more\\nlast different'
596 Out[5]: '> > text\\n> > more\\nlast different'
592 """
597 """
593 lines = text.splitlines()
598 lines = text.splitlines()
594 matches = set()
599 matches = set()
595 for line in lines:
600 for line in lines:
596 prefix = re.match(r'^(\s*>[ >]*)', line)
601 prefix = re.match(r'^(\s*>[ >]*)', line)
597 if prefix:
602 if prefix:
598 matches.add(prefix.group(1))
603 matches.add(prefix.group(1))
599 else:
604 else:
600 break
605 break
601 else:
606 else:
602 prefix = long_substr(list(matches))
607 prefix = long_substr(list(matches))
603 if prefix:
608 if prefix:
604 strip = len(prefix)
609 strip = len(prefix)
605 text = '\n'.join([ ln[strip:] for ln in lines])
610 text = '\n'.join([ ln[strip:] for ln in lines])
606 return text
611 return text
607
612
608
613
609 class EvalFormatter(Formatter):
614 class EvalFormatter(Formatter):
610 """A String Formatter that allows evaluation of simple expressions.
615 """A String Formatter that allows evaluation of simple expressions.
611
616
612 Note that this version interprets a : as specifying a format string (as per
617 Note that this version interprets a : as specifying a format string (as per
613 standard string formatting), so if slicing is required, you must explicitly
618 standard string formatting), so if slicing is required, you must explicitly
614 create a slice.
619 create a slice.
615
620
616 This is to be used in templating cases, such as the parallel batch
621 This is to be used in templating cases, such as the parallel batch
617 script templates, where simple arithmetic on arguments is useful.
622 script templates, where simple arithmetic on arguments is useful.
618
623
619 Examples
624 Examples
620 --------
625 --------
621
626
622 In [1]: f = EvalFormatter()
627 In [1]: f = EvalFormatter()
623 In [2]: f.format('{n//4}', n=8)
628 In [2]: f.format('{n//4}', n=8)
624 Out [2]: '2'
629 Out [2]: '2'
625
630
626 In [3]: f.format("{greeting[slice(2,4)]}", greeting="Hello")
631 In [3]: f.format("{greeting[slice(2,4)]}", greeting="Hello")
627 Out [3]: 'll'
632 Out [3]: 'll'
628 """
633 """
629 def get_field(self, name, args, kwargs):
634 def get_field(self, name, args, kwargs):
630 v = eval(name, kwargs)
635 v = eval(name, kwargs)
631 return v, name
636 return v, name
632
637
633
638
634 @skip_doctest_py3
639 @skip_doctest_py3
635 class FullEvalFormatter(Formatter):
640 class FullEvalFormatter(Formatter):
636 """A String Formatter that allows evaluation of simple expressions.
641 """A String Formatter that allows evaluation of simple expressions.
637
642
638 Any time a format key is not found in the kwargs,
643 Any time a format key is not found in the kwargs,
639 it will be tried as an expression in the kwargs namespace.
644 it will be tried as an expression in the kwargs namespace.
640
645
641 Note that this version allows slicing using [1:2], so you cannot specify
646 Note that this version allows slicing using [1:2], so you cannot specify
642 a format string. Use :class:`EvalFormatter` to permit format strings.
647 a format string. Use :class:`EvalFormatter` to permit format strings.
643
648
644 Examples
649 Examples
645 --------
650 --------
646
651
647 In [1]: f = FullEvalFormatter()
652 In [1]: f = FullEvalFormatter()
648 In [2]: f.format('{n//4}', n=8)
653 In [2]: f.format('{n//4}', n=8)
649 Out[2]: u'2'
654 Out[2]: u'2'
650
655
651 In [3]: f.format('{list(range(5))[2:4]}')
656 In [3]: f.format('{list(range(5))[2:4]}')
652 Out[3]: u'[2, 3]'
657 Out[3]: u'[2, 3]'
653
658
654 In [4]: f.format('{3*2}')
659 In [4]: f.format('{3*2}')
655 Out[4]: u'6'
660 Out[4]: u'6'
656 """
661 """
657 # copied from Formatter._vformat with minor changes to allow eval
662 # copied from Formatter._vformat with minor changes to allow eval
658 # and replace the format_spec code with slicing
663 # and replace the format_spec code with slicing
659 def _vformat(self, format_string, args, kwargs, used_args, recursion_depth):
664 def _vformat(self, format_string, args, kwargs, used_args, recursion_depth):
660 if recursion_depth < 0:
665 if recursion_depth < 0:
661 raise ValueError('Max string recursion exceeded')
666 raise ValueError('Max string recursion exceeded')
662 result = []
667 result = []
663 for literal_text, field_name, format_spec, conversion in \
668 for literal_text, field_name, format_spec, conversion in \
664 self.parse(format_string):
669 self.parse(format_string):
665
670
666 # output the literal text
671 # output the literal text
667 if literal_text:
672 if literal_text:
668 result.append(literal_text)
673 result.append(literal_text)
669
674
670 # if there's a field, output it
675 # if there's a field, output it
671 if field_name is not None:
676 if field_name is not None:
672 # this is some markup, find the object and do
677 # this is some markup, find the object and do
673 # the formatting
678 # the formatting
674
679
675 if format_spec:
680 if format_spec:
676 # override format spec, to allow slicing:
681 # override format spec, to allow slicing:
677 field_name = ':'.join([field_name, format_spec])
682 field_name = ':'.join([field_name, format_spec])
678
683
679 # eval the contents of the field for the object
684 # eval the contents of the field for the object
680 # to be formatted
685 # to be formatted
681 obj = eval(field_name, kwargs)
686 obj = eval(field_name, kwargs)
682
687
683 # do any conversion on the resulting object
688 # do any conversion on the resulting object
684 obj = self.convert_field(obj, conversion)
689 obj = self.convert_field(obj, conversion)
685
690
686 # format the object and append to the result
691 # format the object and append to the result
687 result.append(self.format_field(obj, ''))
692 result.append(self.format_field(obj, ''))
688
693
689 return u''.join(py3compat.cast_unicode(s) for s in result)
694 return u''.join(py3compat.cast_unicode(s) for s in result)
690
695
691
696
692 @skip_doctest_py3
697 @skip_doctest_py3
693 class DollarFormatter(FullEvalFormatter):
698 class DollarFormatter(FullEvalFormatter):
694 """Formatter allowing Itpl style $foo replacement, for names and attribute
699 """Formatter allowing Itpl style $foo replacement, for names and attribute
695 access only. Standard {foo} replacement also works, and allows full
700 access only. Standard {foo} replacement also works, and allows full
696 evaluation of its arguments.
701 evaluation of its arguments.
697
702
698 Examples
703 Examples
699 --------
704 --------
700 In [1]: f = DollarFormatter()
705 In [1]: f = DollarFormatter()
701 In [2]: f.format('{n//4}', n=8)
706 In [2]: f.format('{n//4}', n=8)
702 Out[2]: u'2'
707 Out[2]: u'2'
703
708
704 In [3]: f.format('23 * 76 is $result', result=23*76)
709 In [3]: f.format('23 * 76 is $result', result=23*76)
705 Out[3]: u'23 * 76 is 1748'
710 Out[3]: u'23 * 76 is 1748'
706
711
707 In [4]: f.format('$a or {b}', a=1, b=2)
712 In [4]: f.format('$a or {b}', a=1, b=2)
708 Out[4]: u'1 or 2'
713 Out[4]: u'1 or 2'
709 """
714 """
710 _dollar_pattern = re.compile("(.*?)\$(\$?[\w\.]+)")
715 _dollar_pattern = re.compile("(.*?)\$(\$?[\w\.]+)")
711 def parse(self, fmt_string):
716 def parse(self, fmt_string):
712 for literal_txt, field_name, format_spec, conversion \
717 for literal_txt, field_name, format_spec, conversion \
713 in Formatter.parse(self, fmt_string):
718 in Formatter.parse(self, fmt_string):
714
719
715 # Find $foo patterns in the literal text.
720 # Find $foo patterns in the literal text.
716 continue_from = 0
721 continue_from = 0
717 txt = ""
722 txt = ""
718 for m in self._dollar_pattern.finditer(literal_txt):
723 for m in self._dollar_pattern.finditer(literal_txt):
719 new_txt, new_field = m.group(1,2)
724 new_txt, new_field = m.group(1,2)
720 # $$foo --> $foo
725 # $$foo --> $foo
721 if new_field.startswith("$"):
726 if new_field.startswith("$"):
722 txt += new_txt + new_field
727 txt += new_txt + new_field
723 else:
728 else:
724 yield (txt + new_txt, new_field, "", None)
729 yield (txt + new_txt, new_field, "", None)
725 txt = ""
730 txt = ""
726 continue_from = m.end()
731 continue_from = m.end()
727
732
728 # Re-yield the {foo} style pattern
733 # Re-yield the {foo} style pattern
729 yield (txt + literal_txt[continue_from:], field_name, format_spec, conversion)
734 yield (txt + literal_txt[continue_from:], field_name, format_spec, conversion)
730
735
731 #-----------------------------------------------------------------------------
736 #-----------------------------------------------------------------------------
732 # Utils to columnize a list of string
737 # Utils to columnize a list of string
733 #-----------------------------------------------------------------------------
738 #-----------------------------------------------------------------------------
734
739
735 def _chunks(l, n):
740 def _chunks(l, n):
736 """Yield successive n-sized chunks from l."""
741 """Yield successive n-sized chunks from l."""
737 for i in xrange(0, len(l), n):
742 for i in xrange(0, len(l), n):
738 yield l[i:i+n]
743 yield l[i:i+n]
739
744
740
745
741 def _find_optimal(rlist , separator_size=2 , displaywidth=80):
746 def _find_optimal(rlist , separator_size=2 , displaywidth=80):
742 """Calculate optimal info to columnize a list of string"""
747 """Calculate optimal info to columnize a list of string"""
743 for nrow in range(1, len(rlist)+1) :
748 for nrow in range(1, len(rlist)+1) :
744 chk = map(max,_chunks(rlist, nrow))
749 chk = map(max,_chunks(rlist, nrow))
745 sumlength = sum(chk)
750 sumlength = sum(chk)
746 ncols = len(chk)
751 ncols = len(chk)
747 if sumlength+separator_size*(ncols-1) <= displaywidth :
752 if sumlength+separator_size*(ncols-1) <= displaywidth :
748 break;
753 break;
749 return {'columns_numbers' : ncols,
754 return {'columns_numbers' : ncols,
750 'optimal_separator_width':(displaywidth - sumlength)/(ncols-1) if (ncols -1) else 0,
755 'optimal_separator_width':(displaywidth - sumlength)/(ncols-1) if (ncols -1) else 0,
751 'rows_numbers' : nrow,
756 'rows_numbers' : nrow,
752 'columns_width' : chk
757 'columns_width' : chk
753 }
758 }
754
759
755
760
756 def _get_or_default(mylist, i, default=None):
761 def _get_or_default(mylist, i, default=None):
757 """return list item number, or default if don't exist"""
762 """return list item number, or default if don't exist"""
758 if i >= len(mylist):
763 if i >= len(mylist):
759 return default
764 return default
760 else :
765 else :
761 return mylist[i]
766 return mylist[i]
762
767
763
768
764 @skip_doctest
769 @skip_doctest
765 def compute_item_matrix(items, empty=None, *args, **kwargs) :
770 def compute_item_matrix(items, empty=None, *args, **kwargs) :
766 """Returns a nested list, and info to columnize items
771 """Returns a nested list, and info to columnize items
767
772
768 Parameters :
773 Parameters :
769 ------------
774 ------------
770
775
771 items :
776 items :
772 list of strings to columize
777 list of strings to columize
773 empty : (default None)
778 empty : (default None)
774 default value to fill list if needed
779 default value to fill list if needed
775 separator_size : int (default=2)
780 separator_size : int (default=2)
776 How much caracters will be used as a separation between each columns.
781 How much caracters will be used as a separation between each columns.
777 displaywidth : int (default=80)
782 displaywidth : int (default=80)
778 The width of the area onto wich the columns should enter
783 The width of the area onto wich the columns should enter
779
784
780 Returns :
785 Returns :
781 ---------
786 ---------
782
787
783 Returns a tuple of (strings_matrix, dict_info)
788 Returns a tuple of (strings_matrix, dict_info)
784
789
785 strings_matrix :
790 strings_matrix :
786
791
787 nested list of string, the outer most list contains as many list as
792 nested list of string, the outer most list contains as many list as
788 rows, the innermost lists have each as many element as colums. If the
793 rows, the innermost lists have each as many element as colums. If the
789 total number of elements in `items` does not equal the product of
794 total number of elements in `items` does not equal the product of
790 rows*columns, the last element of some lists are filled with `None`.
795 rows*columns, the last element of some lists are filled with `None`.
791
796
792 dict_info :
797 dict_info :
793 some info to make columnize easier:
798 some info to make columnize easier:
794
799
795 columns_numbers : number of columns
800 columns_numbers : number of columns
796 rows_numbers : number of rows
801 rows_numbers : number of rows
797 columns_width : list of with of each columns
802 columns_width : list of with of each columns
798 optimal_separator_width : best separator width between columns
803 optimal_separator_width : best separator width between columns
799
804
800 Exemple :
805 Exemple :
801 ---------
806 ---------
802
807
803 In [1]: l = ['aaa','b','cc','d','eeeee','f','g','h','i','j','k','l']
808 In [1]: l = ['aaa','b','cc','d','eeeee','f','g','h','i','j','k','l']
804 ...: compute_item_matrix(l,displaywidth=12)
809 ...: compute_item_matrix(l,displaywidth=12)
805 Out[1]:
810 Out[1]:
806 ([['aaa', 'f', 'k'],
811 ([['aaa', 'f', 'k'],
807 ['b', 'g', 'l'],
812 ['b', 'g', 'l'],
808 ['cc', 'h', None],
813 ['cc', 'h', None],
809 ['d', 'i', None],
814 ['d', 'i', None],
810 ['eeeee', 'j', None]],
815 ['eeeee', 'j', None]],
811 {'columns_numbers': 3,
816 {'columns_numbers': 3,
812 'columns_width': [5, 1, 1],
817 'columns_width': [5, 1, 1],
813 'optimal_separator_width': 2,
818 'optimal_separator_width': 2,
814 'rows_numbers': 5})
819 'rows_numbers': 5})
815
820
816 """
821 """
817 info = _find_optimal(map(len, items), *args, **kwargs)
822 info = _find_optimal(map(len, items), *args, **kwargs)
818 nrow, ncol = info['rows_numbers'], info['columns_numbers']
823 nrow, ncol = info['rows_numbers'], info['columns_numbers']
819 return ([[ _get_or_default(items, c*nrow+i, default=empty) for c in range(ncol) ] for i in range(nrow) ], info)
824 return ([[ _get_or_default(items, c*nrow+i, default=empty) for c in range(ncol) ] for i in range(nrow) ], info)
820
825
821
826
822 def columnize(items, separator=' ', displaywidth=80):
827 def columnize(items, separator=' ', displaywidth=80):
823 """ Transform a list of strings into a single string with columns.
828 """ Transform a list of strings into a single string with columns.
824
829
825 Parameters
830 Parameters
826 ----------
831 ----------
827 items : sequence of strings
832 items : sequence of strings
828 The strings to process.
833 The strings to process.
829
834
830 separator : str, optional [default is two spaces]
835 separator : str, optional [default is two spaces]
831 The string that separates columns.
836 The string that separates columns.
832
837
833 displaywidth : int, optional [default is 80]
838 displaywidth : int, optional [default is 80]
834 Width of the display in number of characters.
839 Width of the display in number of characters.
835
840
836 Returns
841 Returns
837 -------
842 -------
838 The formatted string.
843 The formatted string.
839 """
844 """
840 if not items :
845 if not items :
841 return '\n'
846 return '\n'
842 matrix, info = compute_item_matrix(items, separator_size=len(separator), displaywidth=displaywidth)
847 matrix, info = compute_item_matrix(items, separator_size=len(separator), displaywidth=displaywidth)
843 fmatrix = [filter(None, x) for x in matrix]
848 fmatrix = [filter(None, x) for x in matrix]
844 sjoin = lambda x : separator.join([ y.ljust(w, ' ') for y, w in zip(x, info['columns_width'])])
849 sjoin = lambda x : separator.join([ y.ljust(w, ' ') for y, w in zip(x, info['columns_width'])])
845 return '\n'.join(map(sjoin, fmatrix))+'\n'
850 return '\n'.join(map(sjoin, fmatrix))+'\n'
@@ -1,1434 +1,1439 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A lightweight Traits like module.
3 A lightweight Traits like module.
4
4
5 This is designed to provide a lightweight, simple, pure Python version of
5 This is designed to provide a lightweight, simple, pure Python version of
6 many of the capabilities of enthought.traits. This includes:
6 many of the capabilities of enthought.traits. This includes:
7
7
8 * Validation
8 * Validation
9 * Type specification with defaults
9 * Type specification with defaults
10 * Static and dynamic notification
10 * Static and dynamic notification
11 * Basic predefined types
11 * Basic predefined types
12 * An API that is similar to enthought.traits
12 * An API that is similar to enthought.traits
13
13
14 We don't support:
14 We don't support:
15
15
16 * Delegation
16 * Delegation
17 * Automatic GUI generation
17 * Automatic GUI generation
18 * A full set of trait types. Most importantly, we don't provide container
18 * A full set of trait types. Most importantly, we don't provide container
19 traits (list, dict, tuple) that can trigger notifications if their
19 traits (list, dict, tuple) that can trigger notifications if their
20 contents change.
20 contents change.
21 * API compatibility with enthought.traits
21 * API compatibility with enthought.traits
22
22
23 There are also some important difference in our design:
23 There are also some important difference in our design:
24
24
25 * enthought.traits does not validate default values. We do.
25 * enthought.traits does not validate default values. We do.
26
26
27 We choose to create this module because we need these capabilities, but
27 We choose to create this module because we need these capabilities, but
28 we need them to be pure Python so they work in all Python implementations,
28 we need them to be pure Python so they work in all Python implementations,
29 including Jython and IronPython.
29 including Jython and IronPython.
30
30
31 Inheritance diagram:
32
33 .. inheritance-diagram:: IPython.utils.traitlets
34 :parts: 3
35
31 Authors:
36 Authors:
32
37
33 * Brian Granger
38 * Brian Granger
34 * Enthought, Inc. Some of the code in this file comes from enthought.traits
39 * Enthought, Inc. Some of the code in this file comes from enthought.traits
35 and is licensed under the BSD license. Also, many of the ideas also come
40 and is licensed under the BSD license. Also, many of the ideas also come
36 from enthought.traits even though our implementation is very different.
41 from enthought.traits even though our implementation is very different.
37 """
42 """
38
43
39 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
40 # Copyright (C) 2008-2011 The IPython Development Team
45 # Copyright (C) 2008-2011 The IPython Development Team
41 #
46 #
42 # Distributed under the terms of the BSD License. The full license is in
47 # Distributed under the terms of the BSD License. The full license is in
43 # the file COPYING, distributed as part of this software.
48 # the file COPYING, distributed as part of this software.
44 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
45
50
46 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
47 # Imports
52 # Imports
48 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
49
54
50
55
51 import inspect
56 import inspect
52 import re
57 import re
53 import sys
58 import sys
54 import types
59 import types
55 from types import FunctionType
60 from types import FunctionType
56 try:
61 try:
57 from types import ClassType, InstanceType
62 from types import ClassType, InstanceType
58 ClassTypes = (ClassType, type)
63 ClassTypes = (ClassType, type)
59 except:
64 except:
60 ClassTypes = (type,)
65 ClassTypes = (type,)
61
66
62 from .importstring import import_item
67 from .importstring import import_item
63 from IPython.utils import py3compat
68 from IPython.utils import py3compat
64
69
65 SequenceTypes = (list, tuple, set, frozenset)
70 SequenceTypes = (list, tuple, set, frozenset)
66
71
67 #-----------------------------------------------------------------------------
72 #-----------------------------------------------------------------------------
68 # Basic classes
73 # Basic classes
69 #-----------------------------------------------------------------------------
74 #-----------------------------------------------------------------------------
70
75
71
76
72 class NoDefaultSpecified ( object ): pass
77 class NoDefaultSpecified ( object ): pass
73 NoDefaultSpecified = NoDefaultSpecified()
78 NoDefaultSpecified = NoDefaultSpecified()
74
79
75
80
76 class Undefined ( object ): pass
81 class Undefined ( object ): pass
77 Undefined = Undefined()
82 Undefined = Undefined()
78
83
79 class TraitError(Exception):
84 class TraitError(Exception):
80 pass
85 pass
81
86
82 #-----------------------------------------------------------------------------
87 #-----------------------------------------------------------------------------
83 # Utilities
88 # Utilities
84 #-----------------------------------------------------------------------------
89 #-----------------------------------------------------------------------------
85
90
86
91
87 def class_of ( object ):
92 def class_of ( object ):
88 """ Returns a string containing the class name of an object with the
93 """ Returns a string containing the class name of an object with the
89 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
94 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
90 'a PlotValue').
95 'a PlotValue').
91 """
96 """
92 if isinstance( object, basestring ):
97 if isinstance( object, basestring ):
93 return add_article( object )
98 return add_article( object )
94
99
95 return add_article( object.__class__.__name__ )
100 return add_article( object.__class__.__name__ )
96
101
97
102
98 def add_article ( name ):
103 def add_article ( name ):
99 """ Returns a string containing the correct indefinite article ('a' or 'an')
104 """ Returns a string containing the correct indefinite article ('a' or 'an')
100 prefixed to the specified string.
105 prefixed to the specified string.
101 """
106 """
102 if name[:1].lower() in 'aeiou':
107 if name[:1].lower() in 'aeiou':
103 return 'an ' + name
108 return 'an ' + name
104
109
105 return 'a ' + name
110 return 'a ' + name
106
111
107
112
108 def repr_type(obj):
113 def repr_type(obj):
109 """ Return a string representation of a value and its type for readable
114 """ Return a string representation of a value and its type for readable
110 error messages.
115 error messages.
111 """
116 """
112 the_type = type(obj)
117 the_type = type(obj)
113 if (not py3compat.PY3) and the_type is InstanceType:
118 if (not py3compat.PY3) and the_type is InstanceType:
114 # Old-style class.
119 # Old-style class.
115 the_type = obj.__class__
120 the_type = obj.__class__
116 msg = '%r %r' % (obj, the_type)
121 msg = '%r %r' % (obj, the_type)
117 return msg
122 return msg
118
123
119
124
120 def is_trait(t):
125 def is_trait(t):
121 """ Returns whether the given value is an instance or subclass of TraitType.
126 """ Returns whether the given value is an instance or subclass of TraitType.
122 """
127 """
123 return (isinstance(t, TraitType) or
128 return (isinstance(t, TraitType) or
124 (isinstance(t, type) and issubclass(t, TraitType)))
129 (isinstance(t, type) and issubclass(t, TraitType)))
125
130
126
131
127 def parse_notifier_name(name):
132 def parse_notifier_name(name):
128 """Convert the name argument to a list of names.
133 """Convert the name argument to a list of names.
129
134
130 Examples
135 Examples
131 --------
136 --------
132
137
133 >>> parse_notifier_name('a')
138 >>> parse_notifier_name('a')
134 ['a']
139 ['a']
135 >>> parse_notifier_name(['a','b'])
140 >>> parse_notifier_name(['a','b'])
136 ['a', 'b']
141 ['a', 'b']
137 >>> parse_notifier_name(None)
142 >>> parse_notifier_name(None)
138 ['anytrait']
143 ['anytrait']
139 """
144 """
140 if isinstance(name, str):
145 if isinstance(name, str):
141 return [name]
146 return [name]
142 elif name is None:
147 elif name is None:
143 return ['anytrait']
148 return ['anytrait']
144 elif isinstance(name, (list, tuple)):
149 elif isinstance(name, (list, tuple)):
145 for n in name:
150 for n in name:
146 assert isinstance(n, str), "names must be strings"
151 assert isinstance(n, str), "names must be strings"
147 return name
152 return name
148
153
149
154
150 class _SimpleTest:
155 class _SimpleTest:
151 def __init__ ( self, value ): self.value = value
156 def __init__ ( self, value ): self.value = value
152 def __call__ ( self, test ):
157 def __call__ ( self, test ):
153 return test == self.value
158 return test == self.value
154 def __repr__(self):
159 def __repr__(self):
155 return "<SimpleTest(%r)" % self.value
160 return "<SimpleTest(%r)" % self.value
156 def __str__(self):
161 def __str__(self):
157 return self.__repr__()
162 return self.__repr__()
158
163
159
164
160 def getmembers(object, predicate=None):
165 def getmembers(object, predicate=None):
161 """A safe version of inspect.getmembers that handles missing attributes.
166 """A safe version of inspect.getmembers that handles missing attributes.
162
167
163 This is useful when there are descriptor based attributes that for
168 This is useful when there are descriptor based attributes that for
164 some reason raise AttributeError even though they exist. This happens
169 some reason raise AttributeError even though they exist. This happens
165 in zope.inteface with the __provides__ attribute.
170 in zope.inteface with the __provides__ attribute.
166 """
171 """
167 results = []
172 results = []
168 for key in dir(object):
173 for key in dir(object):
169 try:
174 try:
170 value = getattr(object, key)
175 value = getattr(object, key)
171 except AttributeError:
176 except AttributeError:
172 pass
177 pass
173 else:
178 else:
174 if not predicate or predicate(value):
179 if not predicate or predicate(value):
175 results.append((key, value))
180 results.append((key, value))
176 results.sort()
181 results.sort()
177 return results
182 return results
178
183
179
184
180 #-----------------------------------------------------------------------------
185 #-----------------------------------------------------------------------------
181 # Base TraitType for all traits
186 # Base TraitType for all traits
182 #-----------------------------------------------------------------------------
187 #-----------------------------------------------------------------------------
183
188
184
189
185 class TraitType(object):
190 class TraitType(object):
186 """A base class for all trait descriptors.
191 """A base class for all trait descriptors.
187
192
188 Notes
193 Notes
189 -----
194 -----
190 Our implementation of traits is based on Python's descriptor
195 Our implementation of traits is based on Python's descriptor
191 prototol. This class is the base class for all such descriptors. The
196 prototol. This class is the base class for all such descriptors. The
192 only magic we use is a custom metaclass for the main :class:`HasTraits`
197 only magic we use is a custom metaclass for the main :class:`HasTraits`
193 class that does the following:
198 class that does the following:
194
199
195 1. Sets the :attr:`name` attribute of every :class:`TraitType`
200 1. Sets the :attr:`name` attribute of every :class:`TraitType`
196 instance in the class dict to the name of the attribute.
201 instance in the class dict to the name of the attribute.
197 2. Sets the :attr:`this_class` attribute of every :class:`TraitType`
202 2. Sets the :attr:`this_class` attribute of every :class:`TraitType`
198 instance in the class dict to the *class* that declared the trait.
203 instance in the class dict to the *class* that declared the trait.
199 This is used by the :class:`This` trait to allow subclasses to
204 This is used by the :class:`This` trait to allow subclasses to
200 accept superclasses for :class:`This` values.
205 accept superclasses for :class:`This` values.
201 """
206 """
202
207
203
208
204 metadata = {}
209 metadata = {}
205 default_value = Undefined
210 default_value = Undefined
206 info_text = 'any value'
211 info_text = 'any value'
207
212
208 def __init__(self, default_value=NoDefaultSpecified, **metadata):
213 def __init__(self, default_value=NoDefaultSpecified, **metadata):
209 """Create a TraitType.
214 """Create a TraitType.
210 """
215 """
211 if default_value is not NoDefaultSpecified:
216 if default_value is not NoDefaultSpecified:
212 self.default_value = default_value
217 self.default_value = default_value
213
218
214 if len(metadata) > 0:
219 if len(metadata) > 0:
215 if len(self.metadata) > 0:
220 if len(self.metadata) > 0:
216 self._metadata = self.metadata.copy()
221 self._metadata = self.metadata.copy()
217 self._metadata.update(metadata)
222 self._metadata.update(metadata)
218 else:
223 else:
219 self._metadata = metadata
224 self._metadata = metadata
220 else:
225 else:
221 self._metadata = self.metadata
226 self._metadata = self.metadata
222
227
223 self.init()
228 self.init()
224
229
225 def init(self):
230 def init(self):
226 pass
231 pass
227
232
228 def get_default_value(self):
233 def get_default_value(self):
229 """Create a new instance of the default value."""
234 """Create a new instance of the default value."""
230 return self.default_value
235 return self.default_value
231
236
232 def instance_init(self, obj):
237 def instance_init(self, obj):
233 """This is called by :meth:`HasTraits.__new__` to finish init'ing.
238 """This is called by :meth:`HasTraits.__new__` to finish init'ing.
234
239
235 Some stages of initialization must be delayed until the parent
240 Some stages of initialization must be delayed until the parent
236 :class:`HasTraits` instance has been created. This method is
241 :class:`HasTraits` instance has been created. This method is
237 called in :meth:`HasTraits.__new__` after the instance has been
242 called in :meth:`HasTraits.__new__` after the instance has been
238 created.
243 created.
239
244
240 This method trigger the creation and validation of default values
245 This method trigger the creation and validation of default values
241 and also things like the resolution of str given class names in
246 and also things like the resolution of str given class names in
242 :class:`Type` and :class`Instance`.
247 :class:`Type` and :class`Instance`.
243
248
244 Parameters
249 Parameters
245 ----------
250 ----------
246 obj : :class:`HasTraits` instance
251 obj : :class:`HasTraits` instance
247 The parent :class:`HasTraits` instance that has just been
252 The parent :class:`HasTraits` instance that has just been
248 created.
253 created.
249 """
254 """
250 self.set_default_value(obj)
255 self.set_default_value(obj)
251
256
252 def set_default_value(self, obj):
257 def set_default_value(self, obj):
253 """Set the default value on a per instance basis.
258 """Set the default value on a per instance basis.
254
259
255 This method is called by :meth:`instance_init` to create and
260 This method is called by :meth:`instance_init` to create and
256 validate the default value. The creation and validation of
261 validate the default value. The creation and validation of
257 default values must be delayed until the parent :class:`HasTraits`
262 default values must be delayed until the parent :class:`HasTraits`
258 class has been instantiated.
263 class has been instantiated.
259 """
264 """
260 # Check for a deferred initializer defined in the same class as the
265 # Check for a deferred initializer defined in the same class as the
261 # trait declaration or above.
266 # trait declaration or above.
262 mro = type(obj).mro()
267 mro = type(obj).mro()
263 meth_name = '_%s_default' % self.name
268 meth_name = '_%s_default' % self.name
264 for cls in mro[:mro.index(self.this_class)+1]:
269 for cls in mro[:mro.index(self.this_class)+1]:
265 if meth_name in cls.__dict__:
270 if meth_name in cls.__dict__:
266 break
271 break
267 else:
272 else:
268 # We didn't find one. Do static initialization.
273 # We didn't find one. Do static initialization.
269 dv = self.get_default_value()
274 dv = self.get_default_value()
270 newdv = self._validate(obj, dv)
275 newdv = self._validate(obj, dv)
271 obj._trait_values[self.name] = newdv
276 obj._trait_values[self.name] = newdv
272 return
277 return
273 # Complete the dynamic initialization.
278 # Complete the dynamic initialization.
274 obj._trait_dyn_inits[self.name] = cls.__dict__[meth_name]
279 obj._trait_dyn_inits[self.name] = cls.__dict__[meth_name]
275
280
276 def __get__(self, obj, cls=None):
281 def __get__(self, obj, cls=None):
277 """Get the value of the trait by self.name for the instance.
282 """Get the value of the trait by self.name for the instance.
278
283
279 Default values are instantiated when :meth:`HasTraits.__new__`
284 Default values are instantiated when :meth:`HasTraits.__new__`
280 is called. Thus by the time this method gets called either the
285 is called. Thus by the time this method gets called either the
281 default value or a user defined value (they called :meth:`__set__`)
286 default value or a user defined value (they called :meth:`__set__`)
282 is in the :class:`HasTraits` instance.
287 is in the :class:`HasTraits` instance.
283 """
288 """
284 if obj is None:
289 if obj is None:
285 return self
290 return self
286 else:
291 else:
287 try:
292 try:
288 value = obj._trait_values[self.name]
293 value = obj._trait_values[self.name]
289 except KeyError:
294 except KeyError:
290 # Check for a dynamic initializer.
295 # Check for a dynamic initializer.
291 if self.name in obj._trait_dyn_inits:
296 if self.name in obj._trait_dyn_inits:
292 value = obj._trait_dyn_inits[self.name](obj)
297 value = obj._trait_dyn_inits[self.name](obj)
293 # FIXME: Do we really validate here?
298 # FIXME: Do we really validate here?
294 value = self._validate(obj, value)
299 value = self._validate(obj, value)
295 obj._trait_values[self.name] = value
300 obj._trait_values[self.name] = value
296 return value
301 return value
297 else:
302 else:
298 raise TraitError('Unexpected error in TraitType: '
303 raise TraitError('Unexpected error in TraitType: '
299 'both default value and dynamic initializer are '
304 'both default value and dynamic initializer are '
300 'absent.')
305 'absent.')
301 except Exception:
306 except Exception:
302 # HasTraits should call set_default_value to populate
307 # HasTraits should call set_default_value to populate
303 # this. So this should never be reached.
308 # this. So this should never be reached.
304 raise TraitError('Unexpected error in TraitType: '
309 raise TraitError('Unexpected error in TraitType: '
305 'default value not set properly')
310 'default value not set properly')
306 else:
311 else:
307 return value
312 return value
308
313
309 def __set__(self, obj, value):
314 def __set__(self, obj, value):
310 new_value = self._validate(obj, value)
315 new_value = self._validate(obj, value)
311 old_value = self.__get__(obj)
316 old_value = self.__get__(obj)
312 obj._trait_values[self.name] = new_value
317 obj._trait_values[self.name] = new_value
313 if old_value != new_value:
318 if old_value != new_value:
314 obj._notify_trait(self.name, old_value, new_value)
319 obj._notify_trait(self.name, old_value, new_value)
315
320
316 def _validate(self, obj, value):
321 def _validate(self, obj, value):
317 if hasattr(self, 'validate'):
322 if hasattr(self, 'validate'):
318 return self.validate(obj, value)
323 return self.validate(obj, value)
319 elif hasattr(self, 'is_valid_for'):
324 elif hasattr(self, 'is_valid_for'):
320 valid = self.is_valid_for(value)
325 valid = self.is_valid_for(value)
321 if valid:
326 if valid:
322 return value
327 return value
323 else:
328 else:
324 raise TraitError('invalid value for type: %r' % value)
329 raise TraitError('invalid value for type: %r' % value)
325 elif hasattr(self, 'value_for'):
330 elif hasattr(self, 'value_for'):
326 return self.value_for(value)
331 return self.value_for(value)
327 else:
332 else:
328 return value
333 return value
329
334
330 def info(self):
335 def info(self):
331 return self.info_text
336 return self.info_text
332
337
333 def error(self, obj, value):
338 def error(self, obj, value):
334 if obj is not None:
339 if obj is not None:
335 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
340 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
336 % (self.name, class_of(obj),
341 % (self.name, class_of(obj),
337 self.info(), repr_type(value))
342 self.info(), repr_type(value))
338 else:
343 else:
339 e = "The '%s' trait must be %s, but a value of %r was specified." \
344 e = "The '%s' trait must be %s, but a value of %r was specified." \
340 % (self.name, self.info(), repr_type(value))
345 % (self.name, self.info(), repr_type(value))
341 raise TraitError(e)
346 raise TraitError(e)
342
347
343 def get_metadata(self, key):
348 def get_metadata(self, key):
344 return getattr(self, '_metadata', {}).get(key, None)
349 return getattr(self, '_metadata', {}).get(key, None)
345
350
346 def set_metadata(self, key, value):
351 def set_metadata(self, key, value):
347 getattr(self, '_metadata', {})[key] = value
352 getattr(self, '_metadata', {})[key] = value
348
353
349
354
350 #-----------------------------------------------------------------------------
355 #-----------------------------------------------------------------------------
351 # The HasTraits implementation
356 # The HasTraits implementation
352 #-----------------------------------------------------------------------------
357 #-----------------------------------------------------------------------------
353
358
354
359
355 class MetaHasTraits(type):
360 class MetaHasTraits(type):
356 """A metaclass for HasTraits.
361 """A metaclass for HasTraits.
357
362
358 This metaclass makes sure that any TraitType class attributes are
363 This metaclass makes sure that any TraitType class attributes are
359 instantiated and sets their name attribute.
364 instantiated and sets their name attribute.
360 """
365 """
361
366
362 def __new__(mcls, name, bases, classdict):
367 def __new__(mcls, name, bases, classdict):
363 """Create the HasTraits class.
368 """Create the HasTraits class.
364
369
365 This instantiates all TraitTypes in the class dict and sets their
370 This instantiates all TraitTypes in the class dict and sets their
366 :attr:`name` attribute.
371 :attr:`name` attribute.
367 """
372 """
368 # print "MetaHasTraitlets (mcls, name): ", mcls, name
373 # print "MetaHasTraitlets (mcls, name): ", mcls, name
369 # print "MetaHasTraitlets (bases): ", bases
374 # print "MetaHasTraitlets (bases): ", bases
370 # print "MetaHasTraitlets (classdict): ", classdict
375 # print "MetaHasTraitlets (classdict): ", classdict
371 for k,v in classdict.iteritems():
376 for k,v in classdict.iteritems():
372 if isinstance(v, TraitType):
377 if isinstance(v, TraitType):
373 v.name = k
378 v.name = k
374 elif inspect.isclass(v):
379 elif inspect.isclass(v):
375 if issubclass(v, TraitType):
380 if issubclass(v, TraitType):
376 vinst = v()
381 vinst = v()
377 vinst.name = k
382 vinst.name = k
378 classdict[k] = vinst
383 classdict[k] = vinst
379 return super(MetaHasTraits, mcls).__new__(mcls, name, bases, classdict)
384 return super(MetaHasTraits, mcls).__new__(mcls, name, bases, classdict)
380
385
381 def __init__(cls, name, bases, classdict):
386 def __init__(cls, name, bases, classdict):
382 """Finish initializing the HasTraits class.
387 """Finish initializing the HasTraits class.
383
388
384 This sets the :attr:`this_class` attribute of each TraitType in the
389 This sets the :attr:`this_class` attribute of each TraitType in the
385 class dict to the newly created class ``cls``.
390 class dict to the newly created class ``cls``.
386 """
391 """
387 for k, v in classdict.iteritems():
392 for k, v in classdict.iteritems():
388 if isinstance(v, TraitType):
393 if isinstance(v, TraitType):
389 v.this_class = cls
394 v.this_class = cls
390 super(MetaHasTraits, cls).__init__(name, bases, classdict)
395 super(MetaHasTraits, cls).__init__(name, bases, classdict)
391
396
392 class HasTraits(object):
397 class HasTraits(object):
393
398
394 __metaclass__ = MetaHasTraits
399 __metaclass__ = MetaHasTraits
395
400
396 def __new__(cls, **kw):
401 def __new__(cls, **kw):
397 # This is needed because in Python 2.6 object.__new__ only accepts
402 # This is needed because in Python 2.6 object.__new__ only accepts
398 # the cls argument.
403 # the cls argument.
399 new_meth = super(HasTraits, cls).__new__
404 new_meth = super(HasTraits, cls).__new__
400 if new_meth is object.__new__:
405 if new_meth is object.__new__:
401 inst = new_meth(cls)
406 inst = new_meth(cls)
402 else:
407 else:
403 inst = new_meth(cls, **kw)
408 inst = new_meth(cls, **kw)
404 inst._trait_values = {}
409 inst._trait_values = {}
405 inst._trait_notifiers = {}
410 inst._trait_notifiers = {}
406 inst._trait_dyn_inits = {}
411 inst._trait_dyn_inits = {}
407 # Here we tell all the TraitType instances to set their default
412 # Here we tell all the TraitType instances to set their default
408 # values on the instance.
413 # values on the instance.
409 for key in dir(cls):
414 for key in dir(cls):
410 # Some descriptors raise AttributeError like zope.interface's
415 # Some descriptors raise AttributeError like zope.interface's
411 # __provides__ attributes even though they exist. This causes
416 # __provides__ attributes even though they exist. This causes
412 # AttributeErrors even though they are listed in dir(cls).
417 # AttributeErrors even though they are listed in dir(cls).
413 try:
418 try:
414 value = getattr(cls, key)
419 value = getattr(cls, key)
415 except AttributeError:
420 except AttributeError:
416 pass
421 pass
417 else:
422 else:
418 if isinstance(value, TraitType):
423 if isinstance(value, TraitType):
419 value.instance_init(inst)
424 value.instance_init(inst)
420
425
421 return inst
426 return inst
422
427
423 def __init__(self, **kw):
428 def __init__(self, **kw):
424 # Allow trait values to be set using keyword arguments.
429 # Allow trait values to be set using keyword arguments.
425 # We need to use setattr for this to trigger validation and
430 # We need to use setattr for this to trigger validation and
426 # notifications.
431 # notifications.
427 for key, value in kw.iteritems():
432 for key, value in kw.iteritems():
428 setattr(self, key, value)
433 setattr(self, key, value)
429
434
430 def _notify_trait(self, name, old_value, new_value):
435 def _notify_trait(self, name, old_value, new_value):
431
436
432 # First dynamic ones
437 # First dynamic ones
433 callables = self._trait_notifiers.get(name,[])
438 callables = self._trait_notifiers.get(name,[])
434 more_callables = self._trait_notifiers.get('anytrait',[])
439 more_callables = self._trait_notifiers.get('anytrait',[])
435 callables.extend(more_callables)
440 callables.extend(more_callables)
436
441
437 # Now static ones
442 # Now static ones
438 try:
443 try:
439 cb = getattr(self, '_%s_changed' % name)
444 cb = getattr(self, '_%s_changed' % name)
440 except:
445 except:
441 pass
446 pass
442 else:
447 else:
443 callables.append(cb)
448 callables.append(cb)
444
449
445 # Call them all now
450 # Call them all now
446 for c in callables:
451 for c in callables:
447 # Traits catches and logs errors here. I allow them to raise
452 # Traits catches and logs errors here. I allow them to raise
448 if callable(c):
453 if callable(c):
449 argspec = inspect.getargspec(c)
454 argspec = inspect.getargspec(c)
450 nargs = len(argspec[0])
455 nargs = len(argspec[0])
451 # Bound methods have an additional 'self' argument
456 # Bound methods have an additional 'self' argument
452 # I don't know how to treat unbound methods, but they
457 # I don't know how to treat unbound methods, but they
453 # can't really be used for callbacks.
458 # can't really be used for callbacks.
454 if isinstance(c, types.MethodType):
459 if isinstance(c, types.MethodType):
455 offset = -1
460 offset = -1
456 else:
461 else:
457 offset = 0
462 offset = 0
458 if nargs + offset == 0:
463 if nargs + offset == 0:
459 c()
464 c()
460 elif nargs + offset == 1:
465 elif nargs + offset == 1:
461 c(name)
466 c(name)
462 elif nargs + offset == 2:
467 elif nargs + offset == 2:
463 c(name, new_value)
468 c(name, new_value)
464 elif nargs + offset == 3:
469 elif nargs + offset == 3:
465 c(name, old_value, new_value)
470 c(name, old_value, new_value)
466 else:
471 else:
467 raise TraitError('a trait changed callback '
472 raise TraitError('a trait changed callback '
468 'must have 0-3 arguments.')
473 'must have 0-3 arguments.')
469 else:
474 else:
470 raise TraitError('a trait changed callback '
475 raise TraitError('a trait changed callback '
471 'must be callable.')
476 'must be callable.')
472
477
473
478
474 def _add_notifiers(self, handler, name):
479 def _add_notifiers(self, handler, name):
475 if name not in self._trait_notifiers:
480 if name not in self._trait_notifiers:
476 nlist = []
481 nlist = []
477 self._trait_notifiers[name] = nlist
482 self._trait_notifiers[name] = nlist
478 else:
483 else:
479 nlist = self._trait_notifiers[name]
484 nlist = self._trait_notifiers[name]
480 if handler not in nlist:
485 if handler not in nlist:
481 nlist.append(handler)
486 nlist.append(handler)
482
487
483 def _remove_notifiers(self, handler, name):
488 def _remove_notifiers(self, handler, name):
484 if name in self._trait_notifiers:
489 if name in self._trait_notifiers:
485 nlist = self._trait_notifiers[name]
490 nlist = self._trait_notifiers[name]
486 try:
491 try:
487 index = nlist.index(handler)
492 index = nlist.index(handler)
488 except ValueError:
493 except ValueError:
489 pass
494 pass
490 else:
495 else:
491 del nlist[index]
496 del nlist[index]
492
497
493 def on_trait_change(self, handler, name=None, remove=False):
498 def on_trait_change(self, handler, name=None, remove=False):
494 """Setup a handler to be called when a trait changes.
499 """Setup a handler to be called when a trait changes.
495
500
496 This is used to setup dynamic notifications of trait changes.
501 This is used to setup dynamic notifications of trait changes.
497
502
498 Static handlers can be created by creating methods on a HasTraits
503 Static handlers can be created by creating methods on a HasTraits
499 subclass with the naming convention '_[traitname]_changed'. Thus,
504 subclass with the naming convention '_[traitname]_changed'. Thus,
500 to create static handler for the trait 'a', create the method
505 to create static handler for the trait 'a', create the method
501 _a_changed(self, name, old, new) (fewer arguments can be used, see
506 _a_changed(self, name, old, new) (fewer arguments can be used, see
502 below).
507 below).
503
508
504 Parameters
509 Parameters
505 ----------
510 ----------
506 handler : callable
511 handler : callable
507 A callable that is called when a trait changes. Its
512 A callable that is called when a trait changes. Its
508 signature can be handler(), handler(name), handler(name, new)
513 signature can be handler(), handler(name), handler(name, new)
509 or handler(name, old, new).
514 or handler(name, old, new).
510 name : list, str, None
515 name : list, str, None
511 If None, the handler will apply to all traits. If a list
516 If None, the handler will apply to all traits. If a list
512 of str, handler will apply to all names in the list. If a
517 of str, handler will apply to all names in the list. If a
513 str, the handler will apply just to that name.
518 str, the handler will apply just to that name.
514 remove : bool
519 remove : bool
515 If False (the default), then install the handler. If True
520 If False (the default), then install the handler. If True
516 then unintall it.
521 then unintall it.
517 """
522 """
518 if remove:
523 if remove:
519 names = parse_notifier_name(name)
524 names = parse_notifier_name(name)
520 for n in names:
525 for n in names:
521 self._remove_notifiers(handler, n)
526 self._remove_notifiers(handler, n)
522 else:
527 else:
523 names = parse_notifier_name(name)
528 names = parse_notifier_name(name)
524 for n in names:
529 for n in names:
525 self._add_notifiers(handler, n)
530 self._add_notifiers(handler, n)
526
531
527 @classmethod
532 @classmethod
528 def class_trait_names(cls, **metadata):
533 def class_trait_names(cls, **metadata):
529 """Get a list of all the names of this classes traits.
534 """Get a list of all the names of this classes traits.
530
535
531 This method is just like the :meth:`trait_names` method, but is unbound.
536 This method is just like the :meth:`trait_names` method, but is unbound.
532 """
537 """
533 return cls.class_traits(**metadata).keys()
538 return cls.class_traits(**metadata).keys()
534
539
535 @classmethod
540 @classmethod
536 def class_traits(cls, **metadata):
541 def class_traits(cls, **metadata):
537 """Get a list of all the traits of this class.
542 """Get a list of all the traits of this class.
538
543
539 This method is just like the :meth:`traits` method, but is unbound.
544 This method is just like the :meth:`traits` method, but is unbound.
540
545
541 The TraitTypes returned don't know anything about the values
546 The TraitTypes returned don't know anything about the values
542 that the various HasTrait's instances are holding.
547 that the various HasTrait's instances are holding.
543
548
544 This follows the same algorithm as traits does and does not allow
549 This follows the same algorithm as traits does and does not allow
545 for any simple way of specifying merely that a metadata name
550 for any simple way of specifying merely that a metadata name
546 exists, but has any value. This is because get_metadata returns
551 exists, but has any value. This is because get_metadata returns
547 None if a metadata key doesn't exist.
552 None if a metadata key doesn't exist.
548 """
553 """
549 traits = dict([memb for memb in getmembers(cls) if \
554 traits = dict([memb for memb in getmembers(cls) if \
550 isinstance(memb[1], TraitType)])
555 isinstance(memb[1], TraitType)])
551
556
552 if len(metadata) == 0:
557 if len(metadata) == 0:
553 return traits
558 return traits
554
559
555 for meta_name, meta_eval in metadata.items():
560 for meta_name, meta_eval in metadata.items():
556 if type(meta_eval) is not FunctionType:
561 if type(meta_eval) is not FunctionType:
557 metadata[meta_name] = _SimpleTest(meta_eval)
562 metadata[meta_name] = _SimpleTest(meta_eval)
558
563
559 result = {}
564 result = {}
560 for name, trait in traits.items():
565 for name, trait in traits.items():
561 for meta_name, meta_eval in metadata.items():
566 for meta_name, meta_eval in metadata.items():
562 if not meta_eval(trait.get_metadata(meta_name)):
567 if not meta_eval(trait.get_metadata(meta_name)):
563 break
568 break
564 else:
569 else:
565 result[name] = trait
570 result[name] = trait
566
571
567 return result
572 return result
568
573
569 def trait_names(self, **metadata):
574 def trait_names(self, **metadata):
570 """Get a list of all the names of this classes traits."""
575 """Get a list of all the names of this classes traits."""
571 return self.traits(**metadata).keys()
576 return self.traits(**metadata).keys()
572
577
573 def traits(self, **metadata):
578 def traits(self, **metadata):
574 """Get a list of all the traits of this class.
579 """Get a list of all the traits of this class.
575
580
576 The TraitTypes returned don't know anything about the values
581 The TraitTypes returned don't know anything about the values
577 that the various HasTrait's instances are holding.
582 that the various HasTrait's instances are holding.
578
583
579 This follows the same algorithm as traits does and does not allow
584 This follows the same algorithm as traits does and does not allow
580 for any simple way of specifying merely that a metadata name
585 for any simple way of specifying merely that a metadata name
581 exists, but has any value. This is because get_metadata returns
586 exists, but has any value. This is because get_metadata returns
582 None if a metadata key doesn't exist.
587 None if a metadata key doesn't exist.
583 """
588 """
584 traits = dict([memb for memb in getmembers(self.__class__) if \
589 traits = dict([memb for memb in getmembers(self.__class__) if \
585 isinstance(memb[1], TraitType)])
590 isinstance(memb[1], TraitType)])
586
591
587 if len(metadata) == 0:
592 if len(metadata) == 0:
588 return traits
593 return traits
589
594
590 for meta_name, meta_eval in metadata.items():
595 for meta_name, meta_eval in metadata.items():
591 if type(meta_eval) is not FunctionType:
596 if type(meta_eval) is not FunctionType:
592 metadata[meta_name] = _SimpleTest(meta_eval)
597 metadata[meta_name] = _SimpleTest(meta_eval)
593
598
594 result = {}
599 result = {}
595 for name, trait in traits.items():
600 for name, trait in traits.items():
596 for meta_name, meta_eval in metadata.items():
601 for meta_name, meta_eval in metadata.items():
597 if not meta_eval(trait.get_metadata(meta_name)):
602 if not meta_eval(trait.get_metadata(meta_name)):
598 break
603 break
599 else:
604 else:
600 result[name] = trait
605 result[name] = trait
601
606
602 return result
607 return result
603
608
604 def trait_metadata(self, traitname, key):
609 def trait_metadata(self, traitname, key):
605 """Get metadata values for trait by key."""
610 """Get metadata values for trait by key."""
606 try:
611 try:
607 trait = getattr(self.__class__, traitname)
612 trait = getattr(self.__class__, traitname)
608 except AttributeError:
613 except AttributeError:
609 raise TraitError("Class %s does not have a trait named %s" %
614 raise TraitError("Class %s does not have a trait named %s" %
610 (self.__class__.__name__, traitname))
615 (self.__class__.__name__, traitname))
611 else:
616 else:
612 return trait.get_metadata(key)
617 return trait.get_metadata(key)
613
618
614 #-----------------------------------------------------------------------------
619 #-----------------------------------------------------------------------------
615 # Actual TraitTypes implementations/subclasses
620 # Actual TraitTypes implementations/subclasses
616 #-----------------------------------------------------------------------------
621 #-----------------------------------------------------------------------------
617
622
618 #-----------------------------------------------------------------------------
623 #-----------------------------------------------------------------------------
619 # TraitTypes subclasses for handling classes and instances of classes
624 # TraitTypes subclasses for handling classes and instances of classes
620 #-----------------------------------------------------------------------------
625 #-----------------------------------------------------------------------------
621
626
622
627
623 class ClassBasedTraitType(TraitType):
628 class ClassBasedTraitType(TraitType):
624 """A trait with error reporting for Type, Instance and This."""
629 """A trait with error reporting for Type, Instance and This."""
625
630
626 def error(self, obj, value):
631 def error(self, obj, value):
627 kind = type(value)
632 kind = type(value)
628 if (not py3compat.PY3) and kind is InstanceType:
633 if (not py3compat.PY3) and kind is InstanceType:
629 msg = 'class %s' % value.__class__.__name__
634 msg = 'class %s' % value.__class__.__name__
630 else:
635 else:
631 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
636 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
632
637
633 if obj is not None:
638 if obj is not None:
634 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
639 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
635 % (self.name, class_of(obj),
640 % (self.name, class_of(obj),
636 self.info(), msg)
641 self.info(), msg)
637 else:
642 else:
638 e = "The '%s' trait must be %s, but a value of %r was specified." \
643 e = "The '%s' trait must be %s, but a value of %r was specified." \
639 % (self.name, self.info(), msg)
644 % (self.name, self.info(), msg)
640
645
641 raise TraitError(e)
646 raise TraitError(e)
642
647
643
648
644 class Type(ClassBasedTraitType):
649 class Type(ClassBasedTraitType):
645 """A trait whose value must be a subclass of a specified class."""
650 """A trait whose value must be a subclass of a specified class."""
646
651
647 def __init__ (self, default_value=None, klass=None, allow_none=True, **metadata ):
652 def __init__ (self, default_value=None, klass=None, allow_none=True, **metadata ):
648 """Construct a Type trait
653 """Construct a Type trait
649
654
650 A Type trait specifies that its values must be subclasses of
655 A Type trait specifies that its values must be subclasses of
651 a particular class.
656 a particular class.
652
657
653 If only ``default_value`` is given, it is used for the ``klass`` as
658 If only ``default_value`` is given, it is used for the ``klass`` as
654 well.
659 well.
655
660
656 Parameters
661 Parameters
657 ----------
662 ----------
658 default_value : class, str or None
663 default_value : class, str or None
659 The default value must be a subclass of klass. If an str,
664 The default value must be a subclass of klass. If an str,
660 the str must be a fully specified class name, like 'foo.bar.Bah'.
665 the str must be a fully specified class name, like 'foo.bar.Bah'.
661 The string is resolved into real class, when the parent
666 The string is resolved into real class, when the parent
662 :class:`HasTraits` class is instantiated.
667 :class:`HasTraits` class is instantiated.
663 klass : class, str, None
668 klass : class, str, None
664 Values of this trait must be a subclass of klass. The klass
669 Values of this trait must be a subclass of klass. The klass
665 may be specified in a string like: 'foo.bar.MyClass'.
670 may be specified in a string like: 'foo.bar.MyClass'.
666 The string is resolved into real class, when the parent
671 The string is resolved into real class, when the parent
667 :class:`HasTraits` class is instantiated.
672 :class:`HasTraits` class is instantiated.
668 allow_none : boolean
673 allow_none : boolean
669 Indicates whether None is allowed as an assignable value. Even if
674 Indicates whether None is allowed as an assignable value. Even if
670 ``False``, the default value may be ``None``.
675 ``False``, the default value may be ``None``.
671 """
676 """
672 if default_value is None:
677 if default_value is None:
673 if klass is None:
678 if klass is None:
674 klass = object
679 klass = object
675 elif klass is None:
680 elif klass is None:
676 klass = default_value
681 klass = default_value
677
682
678 if not (inspect.isclass(klass) or isinstance(klass, basestring)):
683 if not (inspect.isclass(klass) or isinstance(klass, basestring)):
679 raise TraitError("A Type trait must specify a class.")
684 raise TraitError("A Type trait must specify a class.")
680
685
681 self.klass = klass
686 self.klass = klass
682 self._allow_none = allow_none
687 self._allow_none = allow_none
683
688
684 super(Type, self).__init__(default_value, **metadata)
689 super(Type, self).__init__(default_value, **metadata)
685
690
686 def validate(self, obj, value):
691 def validate(self, obj, value):
687 """Validates that the value is a valid object instance."""
692 """Validates that the value is a valid object instance."""
688 try:
693 try:
689 if issubclass(value, self.klass):
694 if issubclass(value, self.klass):
690 return value
695 return value
691 except:
696 except:
692 if (value is None) and (self._allow_none):
697 if (value is None) and (self._allow_none):
693 return value
698 return value
694
699
695 self.error(obj, value)
700 self.error(obj, value)
696
701
697 def info(self):
702 def info(self):
698 """ Returns a description of the trait."""
703 """ Returns a description of the trait."""
699 if isinstance(self.klass, basestring):
704 if isinstance(self.klass, basestring):
700 klass = self.klass
705 klass = self.klass
701 else:
706 else:
702 klass = self.klass.__name__
707 klass = self.klass.__name__
703 result = 'a subclass of ' + klass
708 result = 'a subclass of ' + klass
704 if self._allow_none:
709 if self._allow_none:
705 return result + ' or None'
710 return result + ' or None'
706 return result
711 return result
707
712
708 def instance_init(self, obj):
713 def instance_init(self, obj):
709 self._resolve_classes()
714 self._resolve_classes()
710 super(Type, self).instance_init(obj)
715 super(Type, self).instance_init(obj)
711
716
712 def _resolve_classes(self):
717 def _resolve_classes(self):
713 if isinstance(self.klass, basestring):
718 if isinstance(self.klass, basestring):
714 self.klass = import_item(self.klass)
719 self.klass = import_item(self.klass)
715 if isinstance(self.default_value, basestring):
720 if isinstance(self.default_value, basestring):
716 self.default_value = import_item(self.default_value)
721 self.default_value = import_item(self.default_value)
717
722
718 def get_default_value(self):
723 def get_default_value(self):
719 return self.default_value
724 return self.default_value
720
725
721
726
722 class DefaultValueGenerator(object):
727 class DefaultValueGenerator(object):
723 """A class for generating new default value instances."""
728 """A class for generating new default value instances."""
724
729
725 def __init__(self, *args, **kw):
730 def __init__(self, *args, **kw):
726 self.args = args
731 self.args = args
727 self.kw = kw
732 self.kw = kw
728
733
729 def generate(self, klass):
734 def generate(self, klass):
730 return klass(*self.args, **self.kw)
735 return klass(*self.args, **self.kw)
731
736
732
737
733 class Instance(ClassBasedTraitType):
738 class Instance(ClassBasedTraitType):
734 """A trait whose value must be an instance of a specified class.
739 """A trait whose value must be an instance of a specified class.
735
740
736 The value can also be an instance of a subclass of the specified class.
741 The value can also be an instance of a subclass of the specified class.
737 """
742 """
738
743
739 def __init__(self, klass=None, args=None, kw=None,
744 def __init__(self, klass=None, args=None, kw=None,
740 allow_none=True, **metadata ):
745 allow_none=True, **metadata ):
741 """Construct an Instance trait.
746 """Construct an Instance trait.
742
747
743 This trait allows values that are instances of a particular
748 This trait allows values that are instances of a particular
744 class or its sublclasses. Our implementation is quite different
749 class or its sublclasses. Our implementation is quite different
745 from that of enthough.traits as we don't allow instances to be used
750 from that of enthough.traits as we don't allow instances to be used
746 for klass and we handle the ``args`` and ``kw`` arguments differently.
751 for klass and we handle the ``args`` and ``kw`` arguments differently.
747
752
748 Parameters
753 Parameters
749 ----------
754 ----------
750 klass : class, str
755 klass : class, str
751 The class that forms the basis for the trait. Class names
756 The class that forms the basis for the trait. Class names
752 can also be specified as strings, like 'foo.bar.Bar'.
757 can also be specified as strings, like 'foo.bar.Bar'.
753 args : tuple
758 args : tuple
754 Positional arguments for generating the default value.
759 Positional arguments for generating the default value.
755 kw : dict
760 kw : dict
756 Keyword arguments for generating the default value.
761 Keyword arguments for generating the default value.
757 allow_none : bool
762 allow_none : bool
758 Indicates whether None is allowed as a value.
763 Indicates whether None is allowed as a value.
759
764
760 Default Value
765 Default Value
761 -------------
766 -------------
762 If both ``args`` and ``kw`` are None, then the default value is None.
767 If both ``args`` and ``kw`` are None, then the default value is None.
763 If ``args`` is a tuple and ``kw`` is a dict, then the default is
768 If ``args`` is a tuple and ``kw`` is a dict, then the default is
764 created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
769 created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
765 not (but not both), None is replace by ``()`` or ``{}``.
770 not (but not both), None is replace by ``()`` or ``{}``.
766 """
771 """
767
772
768 self._allow_none = allow_none
773 self._allow_none = allow_none
769
774
770 if (klass is None) or (not (inspect.isclass(klass) or isinstance(klass, basestring))):
775 if (klass is None) or (not (inspect.isclass(klass) or isinstance(klass, basestring))):
771 raise TraitError('The klass argument must be a class'
776 raise TraitError('The klass argument must be a class'
772 ' you gave: %r' % klass)
777 ' you gave: %r' % klass)
773 self.klass = klass
778 self.klass = klass
774
779
775 # self.klass is a class, so handle default_value
780 # self.klass is a class, so handle default_value
776 if args is None and kw is None:
781 if args is None and kw is None:
777 default_value = None
782 default_value = None
778 else:
783 else:
779 if args is None:
784 if args is None:
780 # kw is not None
785 # kw is not None
781 args = ()
786 args = ()
782 elif kw is None:
787 elif kw is None:
783 # args is not None
788 # args is not None
784 kw = {}
789 kw = {}
785
790
786 if not isinstance(kw, dict):
791 if not isinstance(kw, dict):
787 raise TraitError("The 'kw' argument must be a dict or None.")
792 raise TraitError("The 'kw' argument must be a dict or None.")
788 if not isinstance(args, tuple):
793 if not isinstance(args, tuple):
789 raise TraitError("The 'args' argument must be a tuple or None.")
794 raise TraitError("The 'args' argument must be a tuple or None.")
790
795
791 default_value = DefaultValueGenerator(*args, **kw)
796 default_value = DefaultValueGenerator(*args, **kw)
792
797
793 super(Instance, self).__init__(default_value, **metadata)
798 super(Instance, self).__init__(default_value, **metadata)
794
799
795 def validate(self, obj, value):
800 def validate(self, obj, value):
796 if value is None:
801 if value is None:
797 if self._allow_none:
802 if self._allow_none:
798 return value
803 return value
799 self.error(obj, value)
804 self.error(obj, value)
800
805
801 if isinstance(value, self.klass):
806 if isinstance(value, self.klass):
802 return value
807 return value
803 else:
808 else:
804 self.error(obj, value)
809 self.error(obj, value)
805
810
806 def info(self):
811 def info(self):
807 if isinstance(self.klass, basestring):
812 if isinstance(self.klass, basestring):
808 klass = self.klass
813 klass = self.klass
809 else:
814 else:
810 klass = self.klass.__name__
815 klass = self.klass.__name__
811 result = class_of(klass)
816 result = class_of(klass)
812 if self._allow_none:
817 if self._allow_none:
813 return result + ' or None'
818 return result + ' or None'
814
819
815 return result
820 return result
816
821
817 def instance_init(self, obj):
822 def instance_init(self, obj):
818 self._resolve_classes()
823 self._resolve_classes()
819 super(Instance, self).instance_init(obj)
824 super(Instance, self).instance_init(obj)
820
825
821 def _resolve_classes(self):
826 def _resolve_classes(self):
822 if isinstance(self.klass, basestring):
827 if isinstance(self.klass, basestring):
823 self.klass = import_item(self.klass)
828 self.klass = import_item(self.klass)
824
829
825 def get_default_value(self):
830 def get_default_value(self):
826 """Instantiate a default value instance.
831 """Instantiate a default value instance.
827
832
828 This is called when the containing HasTraits classes'
833 This is called when the containing HasTraits classes'
829 :meth:`__new__` method is called to ensure that a unique instance
834 :meth:`__new__` method is called to ensure that a unique instance
830 is created for each HasTraits instance.
835 is created for each HasTraits instance.
831 """
836 """
832 dv = self.default_value
837 dv = self.default_value
833 if isinstance(dv, DefaultValueGenerator):
838 if isinstance(dv, DefaultValueGenerator):
834 return dv.generate(self.klass)
839 return dv.generate(self.klass)
835 else:
840 else:
836 return dv
841 return dv
837
842
838
843
839 class This(ClassBasedTraitType):
844 class This(ClassBasedTraitType):
840 """A trait for instances of the class containing this trait.
845 """A trait for instances of the class containing this trait.
841
846
842 Because how how and when class bodies are executed, the ``This``
847 Because how how and when class bodies are executed, the ``This``
843 trait can only have a default value of None. This, and because we
848 trait can only have a default value of None. This, and because we
844 always validate default values, ``allow_none`` is *always* true.
849 always validate default values, ``allow_none`` is *always* true.
845 """
850 """
846
851
847 info_text = 'an instance of the same type as the receiver or None'
852 info_text = 'an instance of the same type as the receiver or None'
848
853
849 def __init__(self, **metadata):
854 def __init__(self, **metadata):
850 super(This, self).__init__(None, **metadata)
855 super(This, self).__init__(None, **metadata)
851
856
852 def validate(self, obj, value):
857 def validate(self, obj, value):
853 # What if value is a superclass of obj.__class__? This is
858 # What if value is a superclass of obj.__class__? This is
854 # complicated if it was the superclass that defined the This
859 # complicated if it was the superclass that defined the This
855 # trait.
860 # trait.
856 if isinstance(value, self.this_class) or (value is None):
861 if isinstance(value, self.this_class) or (value is None):
857 return value
862 return value
858 else:
863 else:
859 self.error(obj, value)
864 self.error(obj, value)
860
865
861
866
862 #-----------------------------------------------------------------------------
867 #-----------------------------------------------------------------------------
863 # Basic TraitTypes implementations/subclasses
868 # Basic TraitTypes implementations/subclasses
864 #-----------------------------------------------------------------------------
869 #-----------------------------------------------------------------------------
865
870
866
871
867 class Any(TraitType):
872 class Any(TraitType):
868 default_value = None
873 default_value = None
869 info_text = 'any value'
874 info_text = 'any value'
870
875
871
876
872 class Int(TraitType):
877 class Int(TraitType):
873 """An int trait."""
878 """An int trait."""
874
879
875 default_value = 0
880 default_value = 0
876 info_text = 'an int'
881 info_text = 'an int'
877
882
878 def validate(self, obj, value):
883 def validate(self, obj, value):
879 if isinstance(value, int):
884 if isinstance(value, int):
880 return value
885 return value
881 self.error(obj, value)
886 self.error(obj, value)
882
887
883 class CInt(Int):
888 class CInt(Int):
884 """A casting version of the int trait."""
889 """A casting version of the int trait."""
885
890
886 def validate(self, obj, value):
891 def validate(self, obj, value):
887 try:
892 try:
888 return int(value)
893 return int(value)
889 except:
894 except:
890 self.error(obj, value)
895 self.error(obj, value)
891
896
892 if py3compat.PY3:
897 if py3compat.PY3:
893 Long, CLong = Int, CInt
898 Long, CLong = Int, CInt
894 Integer = Int
899 Integer = Int
895 else:
900 else:
896 class Long(TraitType):
901 class Long(TraitType):
897 """A long integer trait."""
902 """A long integer trait."""
898
903
899 default_value = 0L
904 default_value = 0L
900 info_text = 'a long'
905 info_text = 'a long'
901
906
902 def validate(self, obj, value):
907 def validate(self, obj, value):
903 if isinstance(value, long):
908 if isinstance(value, long):
904 return value
909 return value
905 if isinstance(value, int):
910 if isinstance(value, int):
906 return long(value)
911 return long(value)
907 self.error(obj, value)
912 self.error(obj, value)
908
913
909
914
910 class CLong(Long):
915 class CLong(Long):
911 """A casting version of the long integer trait."""
916 """A casting version of the long integer trait."""
912
917
913 def validate(self, obj, value):
918 def validate(self, obj, value):
914 try:
919 try:
915 return long(value)
920 return long(value)
916 except:
921 except:
917 self.error(obj, value)
922 self.error(obj, value)
918
923
919 class Integer(TraitType):
924 class Integer(TraitType):
920 """An integer trait.
925 """An integer trait.
921
926
922 Longs that are unnecessary (<= sys.maxint) are cast to ints."""
927 Longs that are unnecessary (<= sys.maxint) are cast to ints."""
923
928
924 default_value = 0
929 default_value = 0
925 info_text = 'an integer'
930 info_text = 'an integer'
926
931
927 def validate(self, obj, value):
932 def validate(self, obj, value):
928 if isinstance(value, int):
933 if isinstance(value, int):
929 return value
934 return value
930 if isinstance(value, long):
935 if isinstance(value, long):
931 # downcast longs that fit in int:
936 # downcast longs that fit in int:
932 # note that int(n > sys.maxint) returns a long, so
937 # note that int(n > sys.maxint) returns a long, so
933 # we don't need a condition on this cast
938 # we don't need a condition on this cast
934 return int(value)
939 return int(value)
935 if sys.platform == "cli":
940 if sys.platform == "cli":
936 from System import Int64
941 from System import Int64
937 if isinstance(value, Int64):
942 if isinstance(value, Int64):
938 return int(value)
943 return int(value)
939 self.error(obj, value)
944 self.error(obj, value)
940
945
941
946
942 class Float(TraitType):
947 class Float(TraitType):
943 """A float trait."""
948 """A float trait."""
944
949
945 default_value = 0.0
950 default_value = 0.0
946 info_text = 'a float'
951 info_text = 'a float'
947
952
948 def validate(self, obj, value):
953 def validate(self, obj, value):
949 if isinstance(value, float):
954 if isinstance(value, float):
950 return value
955 return value
951 if isinstance(value, int):
956 if isinstance(value, int):
952 return float(value)
957 return float(value)
953 self.error(obj, value)
958 self.error(obj, value)
954
959
955
960
956 class CFloat(Float):
961 class CFloat(Float):
957 """A casting version of the float trait."""
962 """A casting version of the float trait."""
958
963
959 def validate(self, obj, value):
964 def validate(self, obj, value):
960 try:
965 try:
961 return float(value)
966 return float(value)
962 except:
967 except:
963 self.error(obj, value)
968 self.error(obj, value)
964
969
965 class Complex(TraitType):
970 class Complex(TraitType):
966 """A trait for complex numbers."""
971 """A trait for complex numbers."""
967
972
968 default_value = 0.0 + 0.0j
973 default_value = 0.0 + 0.0j
969 info_text = 'a complex number'
974 info_text = 'a complex number'
970
975
971 def validate(self, obj, value):
976 def validate(self, obj, value):
972 if isinstance(value, complex):
977 if isinstance(value, complex):
973 return value
978 return value
974 if isinstance(value, (float, int)):
979 if isinstance(value, (float, int)):
975 return complex(value)
980 return complex(value)
976 self.error(obj, value)
981 self.error(obj, value)
977
982
978
983
979 class CComplex(Complex):
984 class CComplex(Complex):
980 """A casting version of the complex number trait."""
985 """A casting version of the complex number trait."""
981
986
982 def validate (self, obj, value):
987 def validate (self, obj, value):
983 try:
988 try:
984 return complex(value)
989 return complex(value)
985 except:
990 except:
986 self.error(obj, value)
991 self.error(obj, value)
987
992
988 # We should always be explicit about whether we're using bytes or unicode, both
993 # We should always be explicit about whether we're using bytes or unicode, both
989 # for Python 3 conversion and for reliable unicode behaviour on Python 2. So
994 # for Python 3 conversion and for reliable unicode behaviour on Python 2. So
990 # we don't have a Str type.
995 # we don't have a Str type.
991 class Bytes(TraitType):
996 class Bytes(TraitType):
992 """A trait for byte strings."""
997 """A trait for byte strings."""
993
998
994 default_value = b''
999 default_value = b''
995 info_text = 'a string'
1000 info_text = 'a string'
996
1001
997 def validate(self, obj, value):
1002 def validate(self, obj, value):
998 if isinstance(value, bytes):
1003 if isinstance(value, bytes):
999 return value
1004 return value
1000 self.error(obj, value)
1005 self.error(obj, value)
1001
1006
1002
1007
1003 class CBytes(Bytes):
1008 class CBytes(Bytes):
1004 """A casting version of the byte string trait."""
1009 """A casting version of the byte string trait."""
1005
1010
1006 def validate(self, obj, value):
1011 def validate(self, obj, value):
1007 try:
1012 try:
1008 return bytes(value)
1013 return bytes(value)
1009 except:
1014 except:
1010 self.error(obj, value)
1015 self.error(obj, value)
1011
1016
1012
1017
1013 class Unicode(TraitType):
1018 class Unicode(TraitType):
1014 """A trait for unicode strings."""
1019 """A trait for unicode strings."""
1015
1020
1016 default_value = u''
1021 default_value = u''
1017 info_text = 'a unicode string'
1022 info_text = 'a unicode string'
1018
1023
1019 def validate(self, obj, value):
1024 def validate(self, obj, value):
1020 if isinstance(value, unicode):
1025 if isinstance(value, unicode):
1021 return value
1026 return value
1022 if isinstance(value, bytes):
1027 if isinstance(value, bytes):
1023 return unicode(value)
1028 return unicode(value)
1024 self.error(obj, value)
1029 self.error(obj, value)
1025
1030
1026
1031
1027 class CUnicode(Unicode):
1032 class CUnicode(Unicode):
1028 """A casting version of the unicode trait."""
1033 """A casting version of the unicode trait."""
1029
1034
1030 def validate(self, obj, value):
1035 def validate(self, obj, value):
1031 try:
1036 try:
1032 return unicode(value)
1037 return unicode(value)
1033 except:
1038 except:
1034 self.error(obj, value)
1039 self.error(obj, value)
1035
1040
1036
1041
1037 class ObjectName(TraitType):
1042 class ObjectName(TraitType):
1038 """A string holding a valid object name in this version of Python.
1043 """A string holding a valid object name in this version of Python.
1039
1044
1040 This does not check that the name exists in any scope."""
1045 This does not check that the name exists in any scope."""
1041 info_text = "a valid object identifier in Python"
1046 info_text = "a valid object identifier in Python"
1042
1047
1043 if py3compat.PY3:
1048 if py3compat.PY3:
1044 # Python 3:
1049 # Python 3:
1045 coerce_str = staticmethod(lambda _,s: s)
1050 coerce_str = staticmethod(lambda _,s: s)
1046
1051
1047 else:
1052 else:
1048 # Python 2:
1053 # Python 2:
1049 def coerce_str(self, obj, value):
1054 def coerce_str(self, obj, value):
1050 "In Python 2, coerce ascii-only unicode to str"
1055 "In Python 2, coerce ascii-only unicode to str"
1051 if isinstance(value, unicode):
1056 if isinstance(value, unicode):
1052 try:
1057 try:
1053 return str(value)
1058 return str(value)
1054 except UnicodeEncodeError:
1059 except UnicodeEncodeError:
1055 self.error(obj, value)
1060 self.error(obj, value)
1056 return value
1061 return value
1057
1062
1058 def validate(self, obj, value):
1063 def validate(self, obj, value):
1059 value = self.coerce_str(obj, value)
1064 value = self.coerce_str(obj, value)
1060
1065
1061 if isinstance(value, str) and py3compat.isidentifier(value):
1066 if isinstance(value, str) and py3compat.isidentifier(value):
1062 return value
1067 return value
1063 self.error(obj, value)
1068 self.error(obj, value)
1064
1069
1065 class DottedObjectName(ObjectName):
1070 class DottedObjectName(ObjectName):
1066 """A string holding a valid dotted object name in Python, such as A.b3._c"""
1071 """A string holding a valid dotted object name in Python, such as A.b3._c"""
1067 def validate(self, obj, value):
1072 def validate(self, obj, value):
1068 value = self.coerce_str(obj, value)
1073 value = self.coerce_str(obj, value)
1069
1074
1070 if isinstance(value, str) and py3compat.isidentifier(value, dotted=True):
1075 if isinstance(value, str) and py3compat.isidentifier(value, dotted=True):
1071 return value
1076 return value
1072 self.error(obj, value)
1077 self.error(obj, value)
1073
1078
1074
1079
1075 class Bool(TraitType):
1080 class Bool(TraitType):
1076 """A boolean (True, False) trait."""
1081 """A boolean (True, False) trait."""
1077
1082
1078 default_value = False
1083 default_value = False
1079 info_text = 'a boolean'
1084 info_text = 'a boolean'
1080
1085
1081 def validate(self, obj, value):
1086 def validate(self, obj, value):
1082 if isinstance(value, bool):
1087 if isinstance(value, bool):
1083 return value
1088 return value
1084 self.error(obj, value)
1089 self.error(obj, value)
1085
1090
1086
1091
1087 class CBool(Bool):
1092 class CBool(Bool):
1088 """A casting version of the boolean trait."""
1093 """A casting version of the boolean trait."""
1089
1094
1090 def validate(self, obj, value):
1095 def validate(self, obj, value):
1091 try:
1096 try:
1092 return bool(value)
1097 return bool(value)
1093 except:
1098 except:
1094 self.error(obj, value)
1099 self.error(obj, value)
1095
1100
1096
1101
1097 class Enum(TraitType):
1102 class Enum(TraitType):
1098 """An enum that whose value must be in a given sequence."""
1103 """An enum that whose value must be in a given sequence."""
1099
1104
1100 def __init__(self, values, default_value=None, allow_none=True, **metadata):
1105 def __init__(self, values, default_value=None, allow_none=True, **metadata):
1101 self.values = values
1106 self.values = values
1102 self._allow_none = allow_none
1107 self._allow_none = allow_none
1103 super(Enum, self).__init__(default_value, **metadata)
1108 super(Enum, self).__init__(default_value, **metadata)
1104
1109
1105 def validate(self, obj, value):
1110 def validate(self, obj, value):
1106 if value is None:
1111 if value is None:
1107 if self._allow_none:
1112 if self._allow_none:
1108 return value
1113 return value
1109
1114
1110 if value in self.values:
1115 if value in self.values:
1111 return value
1116 return value
1112 self.error(obj, value)
1117 self.error(obj, value)
1113
1118
1114 def info(self):
1119 def info(self):
1115 """ Returns a description of the trait."""
1120 """ Returns a description of the trait."""
1116 result = 'any of ' + repr(self.values)
1121 result = 'any of ' + repr(self.values)
1117 if self._allow_none:
1122 if self._allow_none:
1118 return result + ' or None'
1123 return result + ' or None'
1119 return result
1124 return result
1120
1125
1121 class CaselessStrEnum(Enum):
1126 class CaselessStrEnum(Enum):
1122 """An enum of strings that are caseless in validate."""
1127 """An enum of strings that are caseless in validate."""
1123
1128
1124 def validate(self, obj, value):
1129 def validate(self, obj, value):
1125 if value is None:
1130 if value is None:
1126 if self._allow_none:
1131 if self._allow_none:
1127 return value
1132 return value
1128
1133
1129 if not isinstance(value, basestring):
1134 if not isinstance(value, basestring):
1130 self.error(obj, value)
1135 self.error(obj, value)
1131
1136
1132 for v in self.values:
1137 for v in self.values:
1133 if v.lower() == value.lower():
1138 if v.lower() == value.lower():
1134 return v
1139 return v
1135 self.error(obj, value)
1140 self.error(obj, value)
1136
1141
1137 class Container(Instance):
1142 class Container(Instance):
1138 """An instance of a container (list, set, etc.)
1143 """An instance of a container (list, set, etc.)
1139
1144
1140 To be subclassed by overriding klass.
1145 To be subclassed by overriding klass.
1141 """
1146 """
1142 klass = None
1147 klass = None
1143 _valid_defaults = SequenceTypes
1148 _valid_defaults = SequenceTypes
1144 _trait = None
1149 _trait = None
1145
1150
1146 def __init__(self, trait=None, default_value=None, allow_none=True,
1151 def __init__(self, trait=None, default_value=None, allow_none=True,
1147 **metadata):
1152 **metadata):
1148 """Create a container trait type from a list, set, or tuple.
1153 """Create a container trait type from a list, set, or tuple.
1149
1154
1150 The default value is created by doing ``List(default_value)``,
1155 The default value is created by doing ``List(default_value)``,
1151 which creates a copy of the ``default_value``.
1156 which creates a copy of the ``default_value``.
1152
1157
1153 ``trait`` can be specified, which restricts the type of elements
1158 ``trait`` can be specified, which restricts the type of elements
1154 in the container to that TraitType.
1159 in the container to that TraitType.
1155
1160
1156 If only one arg is given and it is not a Trait, it is taken as
1161 If only one arg is given and it is not a Trait, it is taken as
1157 ``default_value``:
1162 ``default_value``:
1158
1163
1159 ``c = List([1,2,3])``
1164 ``c = List([1,2,3])``
1160
1165
1161 Parameters
1166 Parameters
1162 ----------
1167 ----------
1163
1168
1164 trait : TraitType [ optional ]
1169 trait : TraitType [ optional ]
1165 the type for restricting the contents of the Container. If unspecified,
1170 the type for restricting the contents of the Container. If unspecified,
1166 types are not checked.
1171 types are not checked.
1167
1172
1168 default_value : SequenceType [ optional ]
1173 default_value : SequenceType [ optional ]
1169 The default value for the Trait. Must be list/tuple/set, and
1174 The default value for the Trait. Must be list/tuple/set, and
1170 will be cast to the container type.
1175 will be cast to the container type.
1171
1176
1172 allow_none : Bool [ default True ]
1177 allow_none : Bool [ default True ]
1173 Whether to allow the value to be None
1178 Whether to allow the value to be None
1174
1179
1175 **metadata : any
1180 **metadata : any
1176 further keys for extensions to the Trait (e.g. config)
1181 further keys for extensions to the Trait (e.g. config)
1177
1182
1178 """
1183 """
1179 # allow List([values]):
1184 # allow List([values]):
1180 if default_value is None and not is_trait(trait):
1185 if default_value is None and not is_trait(trait):
1181 default_value = trait
1186 default_value = trait
1182 trait = None
1187 trait = None
1183
1188
1184 if default_value is None:
1189 if default_value is None:
1185 args = ()
1190 args = ()
1186 elif isinstance(default_value, self._valid_defaults):
1191 elif isinstance(default_value, self._valid_defaults):
1187 args = (default_value,)
1192 args = (default_value,)
1188 else:
1193 else:
1189 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1194 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1190
1195
1191 if is_trait(trait):
1196 if is_trait(trait):
1192 self._trait = trait() if isinstance(trait, type) else trait
1197 self._trait = trait() if isinstance(trait, type) else trait
1193 self._trait.name = 'element'
1198 self._trait.name = 'element'
1194 elif trait is not None:
1199 elif trait is not None:
1195 raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
1200 raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
1196
1201
1197 super(Container,self).__init__(klass=self.klass, args=args,
1202 super(Container,self).__init__(klass=self.klass, args=args,
1198 allow_none=allow_none, **metadata)
1203 allow_none=allow_none, **metadata)
1199
1204
1200 def element_error(self, obj, element, validator):
1205 def element_error(self, obj, element, validator):
1201 e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
1206 e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
1202 % (self.name, class_of(obj), validator.info(), repr_type(element))
1207 % (self.name, class_of(obj), validator.info(), repr_type(element))
1203 raise TraitError(e)
1208 raise TraitError(e)
1204
1209
1205 def validate(self, obj, value):
1210 def validate(self, obj, value):
1206 value = super(Container, self).validate(obj, value)
1211 value = super(Container, self).validate(obj, value)
1207 if value is None:
1212 if value is None:
1208 return value
1213 return value
1209
1214
1210 value = self.validate_elements(obj, value)
1215 value = self.validate_elements(obj, value)
1211
1216
1212 return value
1217 return value
1213
1218
1214 def validate_elements(self, obj, value):
1219 def validate_elements(self, obj, value):
1215 validated = []
1220 validated = []
1216 if self._trait is None or isinstance(self._trait, Any):
1221 if self._trait is None or isinstance(self._trait, Any):
1217 return value
1222 return value
1218 for v in value:
1223 for v in value:
1219 try:
1224 try:
1220 v = self._trait.validate(obj, v)
1225 v = self._trait.validate(obj, v)
1221 except TraitError:
1226 except TraitError:
1222 self.element_error(obj, v, self._trait)
1227 self.element_error(obj, v, self._trait)
1223 else:
1228 else:
1224 validated.append(v)
1229 validated.append(v)
1225 return self.klass(validated)
1230 return self.klass(validated)
1226
1231
1227
1232
1228 class List(Container):
1233 class List(Container):
1229 """An instance of a Python list."""
1234 """An instance of a Python list."""
1230 klass = list
1235 klass = list
1231
1236
1232 def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxsize,
1237 def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxsize,
1233 allow_none=True, **metadata):
1238 allow_none=True, **metadata):
1234 """Create a List trait type from a list, set, or tuple.
1239 """Create a List trait type from a list, set, or tuple.
1235
1240
1236 The default value is created by doing ``List(default_value)``,
1241 The default value is created by doing ``List(default_value)``,
1237 which creates a copy of the ``default_value``.
1242 which creates a copy of the ``default_value``.
1238
1243
1239 ``trait`` can be specified, which restricts the type of elements
1244 ``trait`` can be specified, which restricts the type of elements
1240 in the container to that TraitType.
1245 in the container to that TraitType.
1241
1246
1242 If only one arg is given and it is not a Trait, it is taken as
1247 If only one arg is given and it is not a Trait, it is taken as
1243 ``default_value``:
1248 ``default_value``:
1244
1249
1245 ``c = List([1,2,3])``
1250 ``c = List([1,2,3])``
1246
1251
1247 Parameters
1252 Parameters
1248 ----------
1253 ----------
1249
1254
1250 trait : TraitType [ optional ]
1255 trait : TraitType [ optional ]
1251 the type for restricting the contents of the Container. If unspecified,
1256 the type for restricting the contents of the Container. If unspecified,
1252 types are not checked.
1257 types are not checked.
1253
1258
1254 default_value : SequenceType [ optional ]
1259 default_value : SequenceType [ optional ]
1255 The default value for the Trait. Must be list/tuple/set, and
1260 The default value for the Trait. Must be list/tuple/set, and
1256 will be cast to the container type.
1261 will be cast to the container type.
1257
1262
1258 minlen : Int [ default 0 ]
1263 minlen : Int [ default 0 ]
1259 The minimum length of the input list
1264 The minimum length of the input list
1260
1265
1261 maxlen : Int [ default sys.maxsize ]
1266 maxlen : Int [ default sys.maxsize ]
1262 The maximum length of the input list
1267 The maximum length of the input list
1263
1268
1264 allow_none : Bool [ default True ]
1269 allow_none : Bool [ default True ]
1265 Whether to allow the value to be None
1270 Whether to allow the value to be None
1266
1271
1267 **metadata : any
1272 **metadata : any
1268 further keys for extensions to the Trait (e.g. config)
1273 further keys for extensions to the Trait (e.g. config)
1269
1274
1270 """
1275 """
1271 self._minlen = minlen
1276 self._minlen = minlen
1272 self._maxlen = maxlen
1277 self._maxlen = maxlen
1273 super(List, self).__init__(trait=trait, default_value=default_value,
1278 super(List, self).__init__(trait=trait, default_value=default_value,
1274 allow_none=allow_none, **metadata)
1279 allow_none=allow_none, **metadata)
1275
1280
1276 def length_error(self, obj, value):
1281 def length_error(self, obj, value):
1277 e = "The '%s' trait of %s instance must be of length %i <= L <= %i, but a value of %s was specified." \
1282 e = "The '%s' trait of %s instance must be of length %i <= L <= %i, but a value of %s was specified." \
1278 % (self.name, class_of(obj), self._minlen, self._maxlen, value)
1283 % (self.name, class_of(obj), self._minlen, self._maxlen, value)
1279 raise TraitError(e)
1284 raise TraitError(e)
1280
1285
1281 def validate_elements(self, obj, value):
1286 def validate_elements(self, obj, value):
1282 length = len(value)
1287 length = len(value)
1283 if length < self._minlen or length > self._maxlen:
1288 if length < self._minlen or length > self._maxlen:
1284 self.length_error(obj, value)
1289 self.length_error(obj, value)
1285
1290
1286 return super(List, self).validate_elements(obj, value)
1291 return super(List, self).validate_elements(obj, value)
1287
1292
1288
1293
1289 class Set(Container):
1294 class Set(Container):
1290 """An instance of a Python set."""
1295 """An instance of a Python set."""
1291 klass = set
1296 klass = set
1292
1297
1293 class Tuple(Container):
1298 class Tuple(Container):
1294 """An instance of a Python tuple."""
1299 """An instance of a Python tuple."""
1295 klass = tuple
1300 klass = tuple
1296
1301
1297 def __init__(self, *traits, **metadata):
1302 def __init__(self, *traits, **metadata):
1298 """Tuple(*traits, default_value=None, allow_none=True, **medatata)
1303 """Tuple(*traits, default_value=None, allow_none=True, **medatata)
1299
1304
1300 Create a tuple from a list, set, or tuple.
1305 Create a tuple from a list, set, or tuple.
1301
1306
1302 Create a fixed-type tuple with Traits:
1307 Create a fixed-type tuple with Traits:
1303
1308
1304 ``t = Tuple(Int, Str, CStr)``
1309 ``t = Tuple(Int, Str, CStr)``
1305
1310
1306 would be length 3, with Int,Str,CStr for each element.
1311 would be length 3, with Int,Str,CStr for each element.
1307
1312
1308 If only one arg is given and it is not a Trait, it is taken as
1313 If only one arg is given and it is not a Trait, it is taken as
1309 default_value:
1314 default_value:
1310
1315
1311 ``t = Tuple((1,2,3))``
1316 ``t = Tuple((1,2,3))``
1312
1317
1313 Otherwise, ``default_value`` *must* be specified by keyword.
1318 Otherwise, ``default_value`` *must* be specified by keyword.
1314
1319
1315 Parameters
1320 Parameters
1316 ----------
1321 ----------
1317
1322
1318 *traits : TraitTypes [ optional ]
1323 *traits : TraitTypes [ optional ]
1319 the tsype for restricting the contents of the Tuple. If unspecified,
1324 the tsype for restricting the contents of the Tuple. If unspecified,
1320 types are not checked. If specified, then each positional argument
1325 types are not checked. If specified, then each positional argument
1321 corresponds to an element of the tuple. Tuples defined with traits
1326 corresponds to an element of the tuple. Tuples defined with traits
1322 are of fixed length.
1327 are of fixed length.
1323
1328
1324 default_value : SequenceType [ optional ]
1329 default_value : SequenceType [ optional ]
1325 The default value for the Tuple. Must be list/tuple/set, and
1330 The default value for the Tuple. Must be list/tuple/set, and
1326 will be cast to a tuple. If `traits` are specified, the
1331 will be cast to a tuple. If `traits` are specified, the
1327 `default_value` must conform to the shape and type they specify.
1332 `default_value` must conform to the shape and type they specify.
1328
1333
1329 allow_none : Bool [ default True ]
1334 allow_none : Bool [ default True ]
1330 Whether to allow the value to be None
1335 Whether to allow the value to be None
1331
1336
1332 **metadata : any
1337 **metadata : any
1333 further keys for extensions to the Trait (e.g. config)
1338 further keys for extensions to the Trait (e.g. config)
1334
1339
1335 """
1340 """
1336 default_value = metadata.pop('default_value', None)
1341 default_value = metadata.pop('default_value', None)
1337 allow_none = metadata.pop('allow_none', True)
1342 allow_none = metadata.pop('allow_none', True)
1338
1343
1339 # allow Tuple((values,)):
1344 # allow Tuple((values,)):
1340 if len(traits) == 1 and default_value is None and not is_trait(traits[0]):
1345 if len(traits) == 1 and default_value is None and not is_trait(traits[0]):
1341 default_value = traits[0]
1346 default_value = traits[0]
1342 traits = ()
1347 traits = ()
1343
1348
1344 if default_value is None:
1349 if default_value is None:
1345 args = ()
1350 args = ()
1346 elif isinstance(default_value, self._valid_defaults):
1351 elif isinstance(default_value, self._valid_defaults):
1347 args = (default_value,)
1352 args = (default_value,)
1348 else:
1353 else:
1349 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1354 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1350
1355
1351 self._traits = []
1356 self._traits = []
1352 for trait in traits:
1357 for trait in traits:
1353 t = trait() if isinstance(trait, type) else trait
1358 t = trait() if isinstance(trait, type) else trait
1354 t.name = 'element'
1359 t.name = 'element'
1355 self._traits.append(t)
1360 self._traits.append(t)
1356
1361
1357 if self._traits and default_value is None:
1362 if self._traits and default_value is None:
1358 # don't allow default to be an empty container if length is specified
1363 # don't allow default to be an empty container if length is specified
1359 args = None
1364 args = None
1360 super(Container,self).__init__(klass=self.klass, args=args,
1365 super(Container,self).__init__(klass=self.klass, args=args,
1361 allow_none=allow_none, **metadata)
1366 allow_none=allow_none, **metadata)
1362
1367
1363 def validate_elements(self, obj, value):
1368 def validate_elements(self, obj, value):
1364 if not self._traits:
1369 if not self._traits:
1365 # nothing to validate
1370 # nothing to validate
1366 return value
1371 return value
1367 if len(value) != len(self._traits):
1372 if len(value) != len(self._traits):
1368 e = "The '%s' trait of %s instance requires %i elements, but a value of %s was specified." \
1373 e = "The '%s' trait of %s instance requires %i elements, but a value of %s was specified." \
1369 % (self.name, class_of(obj), len(self._traits), repr_type(value))
1374 % (self.name, class_of(obj), len(self._traits), repr_type(value))
1370 raise TraitError(e)
1375 raise TraitError(e)
1371
1376
1372 validated = []
1377 validated = []
1373 for t,v in zip(self._traits, value):
1378 for t,v in zip(self._traits, value):
1374 try:
1379 try:
1375 v = t.validate(obj, v)
1380 v = t.validate(obj, v)
1376 except TraitError:
1381 except TraitError:
1377 self.element_error(obj, v, t)
1382 self.element_error(obj, v, t)
1378 else:
1383 else:
1379 validated.append(v)
1384 validated.append(v)
1380 return tuple(validated)
1385 return tuple(validated)
1381
1386
1382
1387
1383 class Dict(Instance):
1388 class Dict(Instance):
1384 """An instance of a Python dict."""
1389 """An instance of a Python dict."""
1385
1390
1386 def __init__(self, default_value=None, allow_none=True, **metadata):
1391 def __init__(self, default_value=None, allow_none=True, **metadata):
1387 """Create a dict trait type from a dict.
1392 """Create a dict trait type from a dict.
1388
1393
1389 The default value is created by doing ``dict(default_value)``,
1394 The default value is created by doing ``dict(default_value)``,
1390 which creates a copy of the ``default_value``.
1395 which creates a copy of the ``default_value``.
1391 """
1396 """
1392 if default_value is None:
1397 if default_value is None:
1393 args = ((),)
1398 args = ((),)
1394 elif isinstance(default_value, dict):
1399 elif isinstance(default_value, dict):
1395 args = (default_value,)
1400 args = (default_value,)
1396 elif isinstance(default_value, SequenceTypes):
1401 elif isinstance(default_value, SequenceTypes):
1397 args = (default_value,)
1402 args = (default_value,)
1398 else:
1403 else:
1399 raise TypeError('default value of Dict was %s' % default_value)
1404 raise TypeError('default value of Dict was %s' % default_value)
1400
1405
1401 super(Dict,self).__init__(klass=dict, args=args,
1406 super(Dict,self).__init__(klass=dict, args=args,
1402 allow_none=allow_none, **metadata)
1407 allow_none=allow_none, **metadata)
1403
1408
1404 class TCPAddress(TraitType):
1409 class TCPAddress(TraitType):
1405 """A trait for an (ip, port) tuple.
1410 """A trait for an (ip, port) tuple.
1406
1411
1407 This allows for both IPv4 IP addresses as well as hostnames.
1412 This allows for both IPv4 IP addresses as well as hostnames.
1408 """
1413 """
1409
1414
1410 default_value = ('127.0.0.1', 0)
1415 default_value = ('127.0.0.1', 0)
1411 info_text = 'an (ip, port) tuple'
1416 info_text = 'an (ip, port) tuple'
1412
1417
1413 def validate(self, obj, value):
1418 def validate(self, obj, value):
1414 if isinstance(value, tuple):
1419 if isinstance(value, tuple):
1415 if len(value) == 2:
1420 if len(value) == 2:
1416 if isinstance(value[0], basestring) and isinstance(value[1], int):
1421 if isinstance(value[0], basestring) and isinstance(value[1], int):
1417 port = value[1]
1422 port = value[1]
1418 if port >= 0 and port <= 65535:
1423 if port >= 0 and port <= 65535:
1419 return value
1424 return value
1420 self.error(obj, value)
1425 self.error(obj, value)
1421
1426
1422 class CRegExp(TraitType):
1427 class CRegExp(TraitType):
1423 """A casting compiled regular expression trait.
1428 """A casting compiled regular expression trait.
1424
1429
1425 Accepts both strings and compiled regular expressions. The resulting
1430 Accepts both strings and compiled regular expressions. The resulting
1426 attribute will be a compiled regular expression."""
1431 attribute will be a compiled regular expression."""
1427
1432
1428 info_text = 'a regular expression'
1433 info_text = 'a regular expression'
1429
1434
1430 def validate(self, obj, value):
1435 def validate(self, obj, value):
1431 try:
1436 try:
1432 return re.compile(value)
1437 return re.compile(value)
1433 except:
1438 except:
1434 self.error(obj, value)
1439 self.error(obj, value)
@@ -1,417 +1,412 b''
1 """Attempt to generate templates for module reference with Sphinx
1 """Attempt to generate templates for module reference with Sphinx
2
2
3 XXX - we exclude extension modules
3 XXX - we exclude extension modules
4
4
5 To include extension modules, first identify them as valid in the
5 To include extension modules, first identify them as valid in the
6 ``_uri2path`` method, then handle them in the ``_parse_module`` script.
6 ``_uri2path`` method, then handle them in the ``_parse_module`` script.
7
7
8 We get functions and classes by parsing the text of .py files.
8 We get functions and classes by parsing the text of .py files.
9 Alternatively we could import the modules for discovery, and we'd have
9 Alternatively we could import the modules for discovery, and we'd have
10 to do that for extension modules. This would involve changing the
10 to do that for extension modules. This would involve changing the
11 ``_parse_module`` method to work via import and introspection, and
11 ``_parse_module`` method to work via import and introspection, and
12 might involve changing ``discover_modules`` (which determines which
12 might involve changing ``discover_modules`` (which determines which
13 files are modules, and therefore which module URIs will be passed to
13 files are modules, and therefore which module URIs will be passed to
14 ``_parse_module``).
14 ``_parse_module``).
15
15
16 NOTE: this is a modified version of a script originally shipped with the
16 NOTE: this is a modified version of a script originally shipped with the
17 PyMVPA project, which we've adapted for NIPY use. PyMVPA is an MIT-licensed
17 PyMVPA project, which we've adapted for NIPY use. PyMVPA is an MIT-licensed
18 project."""
18 project."""
19
19
20 # Stdlib imports
20 # Stdlib imports
21 import ast
21 import ast
22 import os
22 import os
23 import re
23 import re
24
24
25 class Obj(object):
25 class Obj(object):
26 '''Namespace to hold arbitrary information.'''
26 '''Namespace to hold arbitrary information.'''
27 def __init__(self, **kwargs):
27 def __init__(self, **kwargs):
28 for k, v in kwargs.items():
28 for k, v in kwargs.items():
29 setattr(self, k, v)
29 setattr(self, k, v)
30
30
31 # Functions and classes
31 # Functions and classes
32 class ApiDocWriter(object):
32 class ApiDocWriter(object):
33 ''' Class for automatic detection and parsing of API docs
33 ''' Class for automatic detection and parsing of API docs
34 to Sphinx-parsable reST format'''
34 to Sphinx-parsable reST format'''
35
35
36 # only separating first two levels
36 # only separating first two levels
37 rst_section_levels = ['*', '=', '-', '~', '^']
37 rst_section_levels = ['*', '=', '-', '~', '^']
38
38
39 def __init__(self,
39 def __init__(self,
40 package_name,
40 package_name,
41 rst_extension='.rst',
41 rst_extension='.rst',
42 package_skip_patterns=None,
42 package_skip_patterns=None,
43 module_skip_patterns=None,
43 module_skip_patterns=None,
44 ):
44 ):
45 ''' Initialize package for parsing
45 ''' Initialize package for parsing
46
46
47 Parameters
47 Parameters
48 ----------
48 ----------
49 package_name : string
49 package_name : string
50 Name of the top-level package. *package_name* must be the
50 Name of the top-level package. *package_name* must be the
51 name of an importable package
51 name of an importable package
52 rst_extension : string, optional
52 rst_extension : string, optional
53 Extension for reST files, default '.rst'
53 Extension for reST files, default '.rst'
54 package_skip_patterns : None or sequence of {strings, regexps}
54 package_skip_patterns : None or sequence of {strings, regexps}
55 Sequence of strings giving URIs of packages to be excluded
55 Sequence of strings giving URIs of packages to be excluded
56 Operates on the package path, starting at (including) the
56 Operates on the package path, starting at (including) the
57 first dot in the package path, after *package_name* - so,
57 first dot in the package path, after *package_name* - so,
58 if *package_name* is ``sphinx``, then ``sphinx.util`` will
58 if *package_name* is ``sphinx``, then ``sphinx.util`` will
59 result in ``.util`` being passed for earching by these
59 result in ``.util`` being passed for earching by these
60 regexps. If is None, gives default. Default is:
60 regexps. If is None, gives default. Default is:
61 ['\.tests$']
61 ['\.tests$']
62 module_skip_patterns : None or sequence
62 module_skip_patterns : None or sequence
63 Sequence of strings giving URIs of modules to be excluded
63 Sequence of strings giving URIs of modules to be excluded
64 Operates on the module name including preceding URI path,
64 Operates on the module name including preceding URI path,
65 back to the first dot after *package_name*. For example
65 back to the first dot after *package_name*. For example
66 ``sphinx.util.console`` results in the string to search of
66 ``sphinx.util.console`` results in the string to search of
67 ``.util.console``
67 ``.util.console``
68 If is None, gives default. Default is:
68 If is None, gives default. Default is:
69 ['\.setup$', '\._']
69 ['\.setup$', '\._']
70 '''
70 '''
71 if package_skip_patterns is None:
71 if package_skip_patterns is None:
72 package_skip_patterns = ['\\.tests$']
72 package_skip_patterns = ['\\.tests$']
73 if module_skip_patterns is None:
73 if module_skip_patterns is None:
74 module_skip_patterns = ['\\.setup$', '\\._']
74 module_skip_patterns = ['\\.setup$', '\\._']
75 self.package_name = package_name
75 self.package_name = package_name
76 self.rst_extension = rst_extension
76 self.rst_extension = rst_extension
77 self.package_skip_patterns = package_skip_patterns
77 self.package_skip_patterns = package_skip_patterns
78 self.module_skip_patterns = module_skip_patterns
78 self.module_skip_patterns = module_skip_patterns
79
79
80 def get_package_name(self):
80 def get_package_name(self):
81 return self._package_name
81 return self._package_name
82
82
83 def set_package_name(self, package_name):
83 def set_package_name(self, package_name):
84 ''' Set package_name
84 ''' Set package_name
85
85
86 >>> docwriter = ApiDocWriter('sphinx')
86 >>> docwriter = ApiDocWriter('sphinx')
87 >>> import sphinx
87 >>> import sphinx
88 >>> docwriter.root_path == sphinx.__path__[0]
88 >>> docwriter.root_path == sphinx.__path__[0]
89 True
89 True
90 >>> docwriter.package_name = 'docutils'
90 >>> docwriter.package_name = 'docutils'
91 >>> import docutils
91 >>> import docutils
92 >>> docwriter.root_path == docutils.__path__[0]
92 >>> docwriter.root_path == docutils.__path__[0]
93 True
93 True
94 '''
94 '''
95 # It's also possible to imagine caching the module parsing here
95 # It's also possible to imagine caching the module parsing here
96 self._package_name = package_name
96 self._package_name = package_name
97 self.root_module = __import__(package_name)
97 self.root_module = __import__(package_name)
98 self.root_path = self.root_module.__path__[0]
98 self.root_path = self.root_module.__path__[0]
99 self.written_modules = None
99 self.written_modules = None
100
100
101 package_name = property(get_package_name, set_package_name, None,
101 package_name = property(get_package_name, set_package_name, None,
102 'get/set package_name')
102 'get/set package_name')
103
103
104 def _uri2path(self, uri):
104 def _uri2path(self, uri):
105 ''' Convert uri to absolute filepath
105 ''' Convert uri to absolute filepath
106
106
107 Parameters
107 Parameters
108 ----------
108 ----------
109 uri : string
109 uri : string
110 URI of python module to return path for
110 URI of python module to return path for
111
111
112 Returns
112 Returns
113 -------
113 -------
114 path : None or string
114 path : None or string
115 Returns None if there is no valid path for this URI
115 Returns None if there is no valid path for this URI
116 Otherwise returns absolute file system path for URI
116 Otherwise returns absolute file system path for URI
117
117
118 Examples
118 Examples
119 --------
119 --------
120 >>> docwriter = ApiDocWriter('sphinx')
120 >>> docwriter = ApiDocWriter('sphinx')
121 >>> import sphinx
121 >>> import sphinx
122 >>> modpath = sphinx.__path__[0]
122 >>> modpath = sphinx.__path__[0]
123 >>> res = docwriter._uri2path('sphinx.builder')
123 >>> res = docwriter._uri2path('sphinx.builder')
124 >>> res == os.path.join(modpath, 'builder.py')
124 >>> res == os.path.join(modpath, 'builder.py')
125 True
125 True
126 >>> res = docwriter._uri2path('sphinx')
126 >>> res = docwriter._uri2path('sphinx')
127 >>> res == os.path.join(modpath, '__init__.py')
127 >>> res == os.path.join(modpath, '__init__.py')
128 True
128 True
129 >>> docwriter._uri2path('sphinx.does_not_exist')
129 >>> docwriter._uri2path('sphinx.does_not_exist')
130
130
131 '''
131 '''
132 if uri == self.package_name:
132 if uri == self.package_name:
133 return os.path.join(self.root_path, '__init__.py')
133 return os.path.join(self.root_path, '__init__.py')
134 path = uri.replace('.', os.path.sep)
134 path = uri.replace('.', os.path.sep)
135 path = path.replace(self.package_name + os.path.sep, '')
135 path = path.replace(self.package_name + os.path.sep, '')
136 path = os.path.join(self.root_path, path)
136 path = os.path.join(self.root_path, path)
137 # XXX maybe check for extensions as well?
137 # XXX maybe check for extensions as well?
138 if os.path.exists(path + '.py'): # file
138 if os.path.exists(path + '.py'): # file
139 path += '.py'
139 path += '.py'
140 elif os.path.exists(os.path.join(path, '__init__.py')):
140 elif os.path.exists(os.path.join(path, '__init__.py')):
141 path = os.path.join(path, '__init__.py')
141 path = os.path.join(path, '__init__.py')
142 else:
142 else:
143 return None
143 return None
144 return path
144 return path
145
145
146 def _path2uri(self, dirpath):
146 def _path2uri(self, dirpath):
147 ''' Convert directory path to uri '''
147 ''' Convert directory path to uri '''
148 relpath = dirpath.replace(self.root_path, self.package_name)
148 relpath = dirpath.replace(self.root_path, self.package_name)
149 if relpath.startswith(os.path.sep):
149 if relpath.startswith(os.path.sep):
150 relpath = relpath[1:]
150 relpath = relpath[1:]
151 return relpath.replace(os.path.sep, '.')
151 return relpath.replace(os.path.sep, '.')
152
152
153 def _parse_module(self, uri):
153 def _parse_module(self, uri):
154 ''' Parse module defined in *uri* '''
154 ''' Parse module defined in *uri* '''
155 filename = self._uri2path(uri)
155 filename = self._uri2path(uri)
156 if filename is None:
156 if filename is None:
157 # nothing that we could handle here.
157 # nothing that we could handle here.
158 return ([],[])
158 return ([],[])
159 with open(filename, 'rb') as f:
159 with open(filename, 'rb') as f:
160 mod = ast.parse(f.read())
160 mod = ast.parse(f.read())
161 return self._find_functions_classes(mod)
161 return self._find_functions_classes(mod)
162
162
163 @staticmethod
163 @staticmethod
164 def _find_functions_classes(mod):
164 def _find_functions_classes(mod):
165 """Extract top-level functions and classes from a module AST.
165 """Extract top-level functions and classes from a module AST.
166
166
167 Skips objects with an @undoc decorator, or a name starting with '_'.
167 Skips objects with an @undoc decorator, or a name starting with '_'.
168 """
168 """
169 def has_undoc_decorator(node):
169 def has_undoc_decorator(node):
170 return any(isinstance(d, ast.Name) and d.id == 'undoc' \
170 return any(isinstance(d, ast.Name) and d.id == 'undoc' \
171 for d in node.decorator_list)
171 for d in node.decorator_list)
172
172
173 functions, classes = [], []
173 functions, classes = [], []
174 for node in mod.body:
174 for node in mod.body:
175 if isinstance(node, ast.FunctionDef) and \
175 if isinstance(node, ast.FunctionDef) and \
176 not node.name.startswith('_') and \
176 not node.name.startswith('_') and \
177 not has_undoc_decorator(node):
177 not has_undoc_decorator(node):
178 functions.append(node.name)
178 functions.append(node.name)
179 elif isinstance(node, ast.ClassDef) and \
179 elif isinstance(node, ast.ClassDef) and \
180 not node.name.startswith('_') and \
180 not node.name.startswith('_') and \
181 not has_undoc_decorator(node):
181 not has_undoc_decorator(node):
182 cls = Obj(name=node.name)
182 cls = Obj(name=node.name)
183 cls.has_init = any(isinstance(n, ast.FunctionDef) and \
183 cls.has_init = any(isinstance(n, ast.FunctionDef) and \
184 n.name=='__init__' for n in node.body)
184 n.name=='__init__' for n in node.body)
185 classes.append(cls)
185 classes.append(cls)
186
186
187 return functions, classes
187 return functions, classes
188
188
189 def generate_api_doc(self, uri):
189 def generate_api_doc(self, uri):
190 '''Make autodoc documentation template string for a module
190 '''Make autodoc documentation template string for a module
191
191
192 Parameters
192 Parameters
193 ----------
193 ----------
194 uri : string
194 uri : string
195 python location of module - e.g 'sphinx.builder'
195 python location of module - e.g 'sphinx.builder'
196
196
197 Returns
197 Returns
198 -------
198 -------
199 S : string
199 S : string
200 Contents of API doc
200 Contents of API doc
201 '''
201 '''
202 # get the names of all classes and functions
202 # get the names of all classes and functions
203 functions, classes = self._parse_module(uri)
203 functions, classes = self._parse_module(uri)
204 if not len(functions) and not len(classes):
204 if not len(functions) and not len(classes):
205 print 'WARNING: Empty -',uri # dbg
205 print 'WARNING: Empty -',uri # dbg
206 return ''
206 return ''
207
207
208 # Make a shorter version of the uri that omits the package name for
208 # Make a shorter version of the uri that omits the package name for
209 # titles
209 # titles
210 uri_short = re.sub(r'^%s\.' % self.package_name,'',uri)
210 uri_short = re.sub(r'^%s\.' % self.package_name,'',uri)
211
211
212 ad = '.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n'
212 ad = '.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n'
213
213
214 # Set the chapter title to read 'Module:' for all modules except for the
214 # Set the chapter title to read 'Module:' for all modules except for the
215 # main packages
215 # main packages
216 if '.' in uri:
216 if '.' in uri:
217 chap_title = 'Module: :mod:`' + uri_short + '`'
217 chap_title = 'Module: :mod:`' + uri_short + '`'
218 else:
218 else:
219 chap_title = ':mod:`' + uri_short + '`'
219 chap_title = ':mod:`' + uri_short + '`'
220 ad += chap_title + '\n' + self.rst_section_levels[1] * len(chap_title)
220 ad += chap_title + '\n' + self.rst_section_levels[1] * len(chap_title)
221
221
222 if len(classes):
223 ad += '\nInheritance diagram for ``%s``:\n\n' % uri
224 ad += '.. inheritance-diagram:: %s \n' % uri
225 ad += ' :parts: 3\n'
226
227 ad += '\n.. automodule:: ' + uri + '\n'
222 ad += '\n.. automodule:: ' + uri + '\n'
228 ad += '\n.. currentmodule:: ' + uri + '\n'
223 ad += '\n.. currentmodule:: ' + uri + '\n'
229 multi_class = len(classes) > 1
224 multi_class = len(classes) > 1
230 multi_fx = len(functions) > 1
225 multi_fx = len(functions) > 1
231 if multi_class:
226 if multi_class:
232 ad += '\n' + 'Classes' + '\n' + \
227 ad += '\n' + 'Classes' + '\n' + \
233 self.rst_section_levels[2] * 7 + '\n'
228 self.rst_section_levels[2] * 7 + '\n'
234 elif len(classes) and multi_fx:
229 elif len(classes) and multi_fx:
235 ad += '\n' + 'Class' + '\n' + \
230 ad += '\n' + 'Class' + '\n' + \
236 self.rst_section_levels[2] * 5 + '\n'
231 self.rst_section_levels[2] * 5 + '\n'
237 for c in classes:
232 for c in classes:
238 ad += '\n:class:`' + c.name + '`\n' \
233 ad += '\n:class:`' + c.name + '`\n' \
239 + self.rst_section_levels[multi_class + 2 ] * \
234 + self.rst_section_levels[multi_class + 2 ] * \
240 (len(c.name)+9) + '\n\n'
235 (len(c.name)+9) + '\n\n'
241 ad += '\n.. autoclass:: ' + c.name + '\n'
236 ad += '\n.. autoclass:: ' + c.name + '\n'
242 # must NOT exclude from index to keep cross-refs working
237 # must NOT exclude from index to keep cross-refs working
243 ad += ' :members:\n' \
238 ad += ' :members:\n' \
244 ' :show-inheritance:\n'
239 ' :show-inheritance:\n'
245 if c.has_init:
240 if c.has_init:
246 ad += '\n .. automethod:: __init__\n'
241 ad += '\n .. automethod:: __init__\n'
247 if multi_fx:
242 if multi_fx:
248 ad += '\n' + 'Functions' + '\n' + \
243 ad += '\n' + 'Functions' + '\n' + \
249 self.rst_section_levels[2] * 9 + '\n\n'
244 self.rst_section_levels[2] * 9 + '\n\n'
250 elif len(functions) and multi_class:
245 elif len(functions) and multi_class:
251 ad += '\n' + 'Function' + '\n' + \
246 ad += '\n' + 'Function' + '\n' + \
252 self.rst_section_levels[2] * 8 + '\n\n'
247 self.rst_section_levels[2] * 8 + '\n\n'
253 for f in functions:
248 for f in functions:
254 # must NOT exclude from index to keep cross-refs working
249 # must NOT exclude from index to keep cross-refs working
255 ad += '\n.. autofunction:: ' + uri + '.' + f + '\n\n'
250 ad += '\n.. autofunction:: ' + uri + '.' + f + '\n\n'
256 return ad
251 return ad
257
252
258 def _survives_exclude(self, matchstr, match_type):
253 def _survives_exclude(self, matchstr, match_type):
259 ''' Returns True if *matchstr* does not match patterns
254 ''' Returns True if *matchstr* does not match patterns
260
255
261 ``self.package_name`` removed from front of string if present
256 ``self.package_name`` removed from front of string if present
262
257
263 Examples
258 Examples
264 --------
259 --------
265 >>> dw = ApiDocWriter('sphinx')
260 >>> dw = ApiDocWriter('sphinx')
266 >>> dw._survives_exclude('sphinx.okpkg', 'package')
261 >>> dw._survives_exclude('sphinx.okpkg', 'package')
267 True
262 True
268 >>> dw.package_skip_patterns.append('^\\.badpkg$')
263 >>> dw.package_skip_patterns.append('^\\.badpkg$')
269 >>> dw._survives_exclude('sphinx.badpkg', 'package')
264 >>> dw._survives_exclude('sphinx.badpkg', 'package')
270 False
265 False
271 >>> dw._survives_exclude('sphinx.badpkg', 'module')
266 >>> dw._survives_exclude('sphinx.badpkg', 'module')
272 True
267 True
273 >>> dw._survives_exclude('sphinx.badmod', 'module')
268 >>> dw._survives_exclude('sphinx.badmod', 'module')
274 True
269 True
275 >>> dw.module_skip_patterns.append('^\\.badmod$')
270 >>> dw.module_skip_patterns.append('^\\.badmod$')
276 >>> dw._survives_exclude('sphinx.badmod', 'module')
271 >>> dw._survives_exclude('sphinx.badmod', 'module')
277 False
272 False
278 '''
273 '''
279 if match_type == 'module':
274 if match_type == 'module':
280 patterns = self.module_skip_patterns
275 patterns = self.module_skip_patterns
281 elif match_type == 'package':
276 elif match_type == 'package':
282 patterns = self.package_skip_patterns
277 patterns = self.package_skip_patterns
283 else:
278 else:
284 raise ValueError('Cannot interpret match type "%s"'
279 raise ValueError('Cannot interpret match type "%s"'
285 % match_type)
280 % match_type)
286 # Match to URI without package name
281 # Match to URI without package name
287 L = len(self.package_name)
282 L = len(self.package_name)
288 if matchstr[:L] == self.package_name:
283 if matchstr[:L] == self.package_name:
289 matchstr = matchstr[L:]
284 matchstr = matchstr[L:]
290 for pat in patterns:
285 for pat in patterns:
291 try:
286 try:
292 pat.search
287 pat.search
293 except AttributeError:
288 except AttributeError:
294 pat = re.compile(pat)
289 pat = re.compile(pat)
295 if pat.search(matchstr):
290 if pat.search(matchstr):
296 return False
291 return False
297 return True
292 return True
298
293
299 def discover_modules(self):
294 def discover_modules(self):
300 ''' Return module sequence discovered from ``self.package_name``
295 ''' Return module sequence discovered from ``self.package_name``
301
296
302
297
303 Parameters
298 Parameters
304 ----------
299 ----------
305 None
300 None
306
301
307 Returns
302 Returns
308 -------
303 -------
309 mods : sequence
304 mods : sequence
310 Sequence of module names within ``self.package_name``
305 Sequence of module names within ``self.package_name``
311
306
312 Examples
307 Examples
313 --------
308 --------
314 >>> dw = ApiDocWriter('sphinx')
309 >>> dw = ApiDocWriter('sphinx')
315 >>> mods = dw.discover_modules()
310 >>> mods = dw.discover_modules()
316 >>> 'sphinx.util' in mods
311 >>> 'sphinx.util' in mods
317 True
312 True
318 >>> dw.package_skip_patterns.append('\.util$')
313 >>> dw.package_skip_patterns.append('\.util$')
319 >>> 'sphinx.util' in dw.discover_modules()
314 >>> 'sphinx.util' in dw.discover_modules()
320 False
315 False
321 >>>
316 >>>
322 '''
317 '''
323 modules = [self.package_name]
318 modules = [self.package_name]
324 # raw directory parsing
319 # raw directory parsing
325 for dirpath, dirnames, filenames in os.walk(self.root_path):
320 for dirpath, dirnames, filenames in os.walk(self.root_path):
326 # Check directory names for packages
321 # Check directory names for packages
327 root_uri = self._path2uri(os.path.join(self.root_path,
322 root_uri = self._path2uri(os.path.join(self.root_path,
328 dirpath))
323 dirpath))
329 for dirname in dirnames[:]: # copy list - we modify inplace
324 for dirname in dirnames[:]: # copy list - we modify inplace
330 package_uri = '.'.join((root_uri, dirname))
325 package_uri = '.'.join((root_uri, dirname))
331 if (self._uri2path(package_uri) and
326 if (self._uri2path(package_uri) and
332 self._survives_exclude(package_uri, 'package')):
327 self._survives_exclude(package_uri, 'package')):
333 modules.append(package_uri)
328 modules.append(package_uri)
334 else:
329 else:
335 dirnames.remove(dirname)
330 dirnames.remove(dirname)
336 # Check filenames for modules
331 # Check filenames for modules
337 for filename in filenames:
332 for filename in filenames:
338 module_name = filename[:-3]
333 module_name = filename[:-3]
339 module_uri = '.'.join((root_uri, module_name))
334 module_uri = '.'.join((root_uri, module_name))
340 if (self._uri2path(module_uri) and
335 if (self._uri2path(module_uri) and
341 self._survives_exclude(module_uri, 'module')):
336 self._survives_exclude(module_uri, 'module')):
342 modules.append(module_uri)
337 modules.append(module_uri)
343 return sorted(modules)
338 return sorted(modules)
344
339
345 def write_modules_api(self, modules,outdir):
340 def write_modules_api(self, modules,outdir):
346 # write the list
341 # write the list
347 written_modules = []
342 written_modules = []
348 for m in modules:
343 for m in modules:
349 api_str = self.generate_api_doc(m)
344 api_str = self.generate_api_doc(m)
350 if not api_str:
345 if not api_str:
351 continue
346 continue
352 # write out to file
347 # write out to file
353 outfile = os.path.join(outdir,
348 outfile = os.path.join(outdir,
354 m + self.rst_extension)
349 m + self.rst_extension)
355 fileobj = open(outfile, 'wt')
350 fileobj = open(outfile, 'wt')
356 fileobj.write(api_str)
351 fileobj.write(api_str)
357 fileobj.close()
352 fileobj.close()
358 written_modules.append(m)
353 written_modules.append(m)
359 self.written_modules = written_modules
354 self.written_modules = written_modules
360
355
361 def write_api_docs(self, outdir):
356 def write_api_docs(self, outdir):
362 """Generate API reST files.
357 """Generate API reST files.
363
358
364 Parameters
359 Parameters
365 ----------
360 ----------
366 outdir : string
361 outdir : string
367 Directory name in which to store files
362 Directory name in which to store files
368 We create automatic filenames for each module
363 We create automatic filenames for each module
369
364
370 Returns
365 Returns
371 -------
366 -------
372 None
367 None
373
368
374 Notes
369 Notes
375 -----
370 -----
376 Sets self.written_modules to list of written modules
371 Sets self.written_modules to list of written modules
377 """
372 """
378 if not os.path.exists(outdir):
373 if not os.path.exists(outdir):
379 os.mkdir(outdir)
374 os.mkdir(outdir)
380 # compose list of modules
375 # compose list of modules
381 modules = self.discover_modules()
376 modules = self.discover_modules()
382 self.write_modules_api(modules,outdir)
377 self.write_modules_api(modules,outdir)
383
378
384 def write_index(self, outdir, froot='gen', relative_to=None):
379 def write_index(self, outdir, froot='gen', relative_to=None):
385 """Make a reST API index file from written files
380 """Make a reST API index file from written files
386
381
387 Parameters
382 Parameters
388 ----------
383 ----------
389 path : string
384 path : string
390 Filename to write index to
385 Filename to write index to
391 outdir : string
386 outdir : string
392 Directory to which to write generated index file
387 Directory to which to write generated index file
393 froot : string, optional
388 froot : string, optional
394 root (filename without extension) of filename to write to
389 root (filename without extension) of filename to write to
395 Defaults to 'gen'. We add ``self.rst_extension``.
390 Defaults to 'gen'. We add ``self.rst_extension``.
396 relative_to : string
391 relative_to : string
397 path to which written filenames are relative. This
392 path to which written filenames are relative. This
398 component of the written file path will be removed from
393 component of the written file path will be removed from
399 outdir, in the generated index. Default is None, meaning,
394 outdir, in the generated index. Default is None, meaning,
400 leave path as it is.
395 leave path as it is.
401 """
396 """
402 if self.written_modules is None:
397 if self.written_modules is None:
403 raise ValueError('No modules written')
398 raise ValueError('No modules written')
404 # Get full filename path
399 # Get full filename path
405 path = os.path.join(outdir, froot+self.rst_extension)
400 path = os.path.join(outdir, froot+self.rst_extension)
406 # Path written into index is relative to rootpath
401 # Path written into index is relative to rootpath
407 if relative_to is not None:
402 if relative_to is not None:
408 relpath = outdir.replace(relative_to + os.path.sep, '')
403 relpath = outdir.replace(relative_to + os.path.sep, '')
409 else:
404 else:
410 relpath = outdir
405 relpath = outdir
411 idx = open(path,'wt')
406 idx = open(path,'wt')
412 w = idx.write
407 w = idx.write
413 w('.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n')
408 w('.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n')
414 w('.. toctree::\n\n')
409 w('.. toctree::\n\n')
415 for f in self.written_modules:
410 for f in self.written_modules:
416 w(' %s\n' % os.path.join(relpath,f))
411 w(' %s\n' % os.path.join(relpath,f))
417 idx.close()
412 idx.close()
General Comments 0
You need to be logged in to leave comments. Login now