##// END OF EJS Templates
Only include inheritance diagram where it's useful.
Thomas Kluyver -
Show More
@@ -1,351 +1,356 b''
1 1 # encoding: utf-8
2 2 """
3 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 10 Authors:
6 11
7 12 * Brian Granger
8 13 * Fernando Perez
9 14 * Min RK
10 15 """
11 16
12 17 #-----------------------------------------------------------------------------
13 18 # Copyright (C) 2008-2011 The IPython Development Team
14 19 #
15 20 # Distributed under the terms of the BSD License. The full license is in
16 21 # the file COPYING, distributed as part of this software.
17 22 #-----------------------------------------------------------------------------
18 23
19 24 #-----------------------------------------------------------------------------
20 25 # Imports
21 26 #-----------------------------------------------------------------------------
22 27
23 28 import datetime
24 29 from copy import deepcopy
25 30
26 31 from loader import Config
27 32 from IPython.utils.traitlets import HasTraits, Instance
28 33 from IPython.utils.text import indent, wrap_paragraphs
29 34
30 35
31 36 #-----------------------------------------------------------------------------
32 37 # Helper classes for Configurables
33 38 #-----------------------------------------------------------------------------
34 39
35 40
36 41 class ConfigurableError(Exception):
37 42 pass
38 43
39 44
40 45 class MultipleInstanceError(ConfigurableError):
41 46 pass
42 47
43 48 #-----------------------------------------------------------------------------
44 49 # Configurable implementation
45 50 #-----------------------------------------------------------------------------
46 51
47 52 class Configurable(HasTraits):
48 53
49 54 config = Instance(Config,(),{})
50 55 created = None
51 56
52 57 def __init__(self, **kwargs):
53 58 """Create a configurable given a config config.
54 59
55 60 Parameters
56 61 ----------
57 62 config : Config
58 63 If this is empty, default values are used. If config is a
59 64 :class:`Config` instance, it will be used to configure the
60 65 instance.
61 66
62 67 Notes
63 68 -----
64 69 Subclasses of Configurable must call the :meth:`__init__` method of
65 70 :class:`Configurable` *before* doing anything else and using
66 71 :func:`super`::
67 72
68 73 class MyConfigurable(Configurable):
69 74 def __init__(self, config=None):
70 75 super(MyConfigurable, self).__init__(config)
71 76 # Then any other code you need to finish initialization.
72 77
73 78 This ensures that instances will be configured properly.
74 79 """
75 80 config = kwargs.pop('config', None)
76 81 if config is not None:
77 82 # We used to deepcopy, but for now we are trying to just save
78 83 # by reference. This *could* have side effects as all components
79 84 # will share config. In fact, I did find such a side effect in
80 85 # _config_changed below. If a config attribute value was a mutable type
81 86 # all instances of a component were getting the same copy, effectively
82 87 # making that a class attribute.
83 88 # self.config = deepcopy(config)
84 89 self.config = config
85 90 # This should go second so individual keyword arguments override
86 91 # the values in config.
87 92 super(Configurable, self).__init__(**kwargs)
88 93 self.created = datetime.datetime.now()
89 94
90 95 #-------------------------------------------------------------------------
91 96 # Static trait notifiations
92 97 #-------------------------------------------------------------------------
93 98
94 99 def _config_changed(self, name, old, new):
95 100 """Update all the class traits having ``config=True`` as metadata.
96 101
97 102 For any class trait with a ``config`` metadata attribute that is
98 103 ``True``, we update the trait with the value of the corresponding
99 104 config entry.
100 105 """
101 106 # Get all traits with a config metadata entry that is True
102 107 traits = self.traits(config=True)
103 108
104 109 # We auto-load config section for this class as well as any parent
105 110 # classes that are Configurable subclasses. This starts with Configurable
106 111 # and works down the mro loading the config for each section.
107 112 section_names = [cls.__name__ for cls in \
108 113 reversed(self.__class__.__mro__) if
109 114 issubclass(cls, Configurable) and issubclass(self.__class__, cls)]
110 115
111 116 for sname in section_names:
112 117 # Don't do a blind getattr as that would cause the config to
113 118 # dynamically create the section with name self.__class__.__name__.
114 119 if new._has_section(sname):
115 120 my_config = new[sname]
116 121 for k, v in traits.iteritems():
117 122 # Don't allow traitlets with config=True to start with
118 123 # uppercase. Otherwise, they are confused with Config
119 124 # subsections. But, developers shouldn't have uppercase
120 125 # attributes anyways! (PEP 6)
121 126 if k[0].upper()==k[0] and not k.startswith('_'):
122 127 raise ConfigurableError('Configurable traitlets with '
123 128 'config=True must start with a lowercase so they are '
124 129 'not confused with Config subsections: %s.%s' % \
125 130 (self.__class__.__name__, k))
126 131 try:
127 132 # Here we grab the value from the config
128 133 # If k has the naming convention of a config
129 134 # section, it will be auto created.
130 135 config_value = my_config[k]
131 136 except KeyError:
132 137 pass
133 138 else:
134 139 # print "Setting %s.%s from %s.%s=%r" % \
135 140 # (self.__class__.__name__,k,sname,k,config_value)
136 141 # We have to do a deepcopy here if we don't deepcopy the entire
137 142 # config object. If we don't, a mutable config_value will be
138 143 # shared by all instances, effectively making it a class attribute.
139 144 setattr(self, k, deepcopy(config_value))
140 145
141 146 def update_config(self, config):
142 147 """Fire the traits events when the config is updated."""
143 148 # Save a copy of the current config.
144 149 newconfig = deepcopy(self.config)
145 150 # Merge the new config into the current one.
146 151 newconfig._merge(config)
147 152 # Save the combined config as self.config, which triggers the traits
148 153 # events.
149 154 self.config = newconfig
150 155
151 156 @classmethod
152 157 def class_get_help(cls, inst=None):
153 158 """Get the help string for this class in ReST format.
154 159
155 160 If `inst` is given, it's current trait values will be used in place of
156 161 class defaults.
157 162 """
158 163 assert inst is None or isinstance(inst, cls)
159 164 cls_traits = cls.class_traits(config=True)
160 165 final_help = []
161 166 final_help.append(u'%s options' % cls.__name__)
162 167 final_help.append(len(final_help[0])*u'-')
163 168 for k,v in sorted(cls.class_traits(config=True).iteritems()):
164 169 help = cls.class_get_trait_help(v, inst)
165 170 final_help.append(help)
166 171 return '\n'.join(final_help)
167 172
168 173 @classmethod
169 174 def class_get_trait_help(cls, trait, inst=None):
170 175 """Get the help string for a single trait.
171 176
172 177 If `inst` is given, it's current trait values will be used in place of
173 178 the class default.
174 179 """
175 180 assert inst is None or isinstance(inst, cls)
176 181 lines = []
177 182 header = "--%s.%s=<%s>" % (cls.__name__, trait.name, trait.__class__.__name__)
178 183 lines.append(header)
179 184 if inst is not None:
180 185 lines.append(indent('Current: %r' % getattr(inst, trait.name), 4))
181 186 else:
182 187 try:
183 188 dvr = repr(trait.get_default_value())
184 189 except Exception:
185 190 dvr = None # ignore defaults we can't construct
186 191 if dvr is not None:
187 192 if len(dvr) > 64:
188 193 dvr = dvr[:61]+'...'
189 194 lines.append(indent('Default: %s' % dvr, 4))
190 195 if 'Enum' in trait.__class__.__name__:
191 196 # include Enum choices
192 197 lines.append(indent('Choices: %r' % (trait.values,)))
193 198
194 199 help = trait.get_metadata('help')
195 200 if help is not None:
196 201 help = '\n'.join(wrap_paragraphs(help, 76))
197 202 lines.append(indent(help, 4))
198 203 return '\n'.join(lines)
199 204
200 205 @classmethod
201 206 def class_print_help(cls, inst=None):
202 207 """Get the help string for a single trait and print it."""
203 208 print cls.class_get_help(inst)
204 209
205 210 @classmethod
206 211 def class_config_section(cls):
207 212 """Get the config class config section"""
208 213 def c(s):
209 214 """return a commented, wrapped block."""
210 215 s = '\n\n'.join(wrap_paragraphs(s, 78))
211 216
212 217 return '# ' + s.replace('\n', '\n# ')
213 218
214 219 # section header
215 220 breaker = '#' + '-'*78
216 221 s = "# %s configuration"%cls.__name__
217 222 lines = [breaker, s, breaker, '']
218 223 # get the description trait
219 224 desc = cls.class_traits().get('description')
220 225 if desc:
221 226 desc = desc.default_value
222 227 else:
223 228 # no description trait, use __doc__
224 229 desc = getattr(cls, '__doc__', '')
225 230 if desc:
226 231 lines.append(c(desc))
227 232 lines.append('')
228 233
229 234 parents = []
230 235 for parent in cls.mro():
231 236 # only include parents that are not base classes
232 237 # and are not the class itself
233 238 # and have some configurable traits to inherit
234 239 if parent is not cls and issubclass(parent, Configurable) and \
235 240 parent.class_traits(config=True):
236 241 parents.append(parent)
237 242
238 243 if parents:
239 244 pstr = ', '.join([ p.__name__ for p in parents ])
240 245 lines.append(c('%s will inherit config from: %s'%(cls.__name__, pstr)))
241 246 lines.append('')
242 247
243 248 for name,trait in cls.class_traits(config=True).iteritems():
244 249 help = trait.get_metadata('help') or ''
245 250 lines.append(c(help))
246 251 lines.append('# c.%s.%s = %r'%(cls.__name__, name, trait.get_default_value()))
247 252 lines.append('')
248 253 return '\n'.join(lines)
249 254
250 255
251 256
252 257 class SingletonConfigurable(Configurable):
253 258 """A configurable that only allows one instance.
254 259
255 260 This class is for classes that should only have one instance of itself
256 261 or *any* subclass. To create and retrieve such a class use the
257 262 :meth:`SingletonConfigurable.instance` method.
258 263 """
259 264
260 265 _instance = None
261 266
262 267 @classmethod
263 268 def _walk_mro(cls):
264 269 """Walk the cls.mro() for parent classes that are also singletons
265 270
266 271 For use in instance()
267 272 """
268 273
269 274 for subclass in cls.mro():
270 275 if issubclass(cls, subclass) and \
271 276 issubclass(subclass, SingletonConfigurable) and \
272 277 subclass != SingletonConfigurable:
273 278 yield subclass
274 279
275 280 @classmethod
276 281 def clear_instance(cls):
277 282 """unset _instance for this class and singleton parents.
278 283 """
279 284 if not cls.initialized():
280 285 return
281 286 for subclass in cls._walk_mro():
282 287 if isinstance(subclass._instance, cls):
283 288 # only clear instances that are instances
284 289 # of the calling class
285 290 subclass._instance = None
286 291
287 292 @classmethod
288 293 def instance(cls, *args, **kwargs):
289 294 """Returns a global instance of this class.
290 295
291 296 This method create a new instance if none have previously been created
292 297 and returns a previously created instance is one already exists.
293 298
294 299 The arguments and keyword arguments passed to this method are passed
295 300 on to the :meth:`__init__` method of the class upon instantiation.
296 301
297 302 Examples
298 303 --------
299 304
300 305 Create a singleton class using instance, and retrieve it::
301 306
302 307 >>> from IPython.config.configurable import SingletonConfigurable
303 308 >>> class Foo(SingletonConfigurable): pass
304 309 >>> foo = Foo.instance()
305 310 >>> foo == Foo.instance()
306 311 True
307 312
308 313 Create a subclass that is retrived using the base class instance::
309 314
310 315 >>> class Bar(SingletonConfigurable): pass
311 316 >>> class Bam(Bar): pass
312 317 >>> bam = Bam.instance()
313 318 >>> bam == Bar.instance()
314 319 True
315 320 """
316 321 # Create and save the instance
317 322 if cls._instance is None:
318 323 inst = cls(*args, **kwargs)
319 324 # Now make sure that the instance will also be returned by
320 325 # parent classes' _instance attribute.
321 326 for subclass in cls._walk_mro():
322 327 subclass._instance = inst
323 328
324 329 if isinstance(cls._instance, cls):
325 330 return cls._instance
326 331 else:
327 332 raise MultipleInstanceError(
328 333 'Multiple incompatible subclass instances of '
329 334 '%s are being created.' % cls.__name__
330 335 )
331 336
332 337 @classmethod
333 338 def initialized(cls):
334 339 """Has an instance been created?"""
335 340 return hasattr(cls, "_instance") and cls._instance is not None
336 341
337 342
338 343 class LoggingConfigurable(Configurable):
339 344 """A parent class for Configurables that log.
340 345
341 346 Subclasses have a log trait, and the default behavior
342 347 is to get the logger from the currently running Application
343 348 via Application.instance().log.
344 349 """
345 350
346 351 log = Instance('logging.Logger')
347 352 def _log_default(self):
348 353 from IPython.config.application import Application
349 354 return Application.instance().log
350 355
351 356
@@ -1,696 +1,701 b''
1 1 """A simple configuration system.
2 2
3 Inheritance diagram:
4
5 .. inheritance-diagram:: IPython.config.loader
6 :parts: 3
7
3 8 Authors
4 9 -------
5 10 * Brian Granger
6 11 * Fernando Perez
7 12 * Min RK
8 13 """
9 14
10 15 #-----------------------------------------------------------------------------
11 16 # Copyright (C) 2008-2011 The IPython Development Team
12 17 #
13 18 # Distributed under the terms of the BSD License. The full license is in
14 19 # the file COPYING, distributed as part of this software.
15 20 #-----------------------------------------------------------------------------
16 21
17 22 #-----------------------------------------------------------------------------
18 23 # Imports
19 24 #-----------------------------------------------------------------------------
20 25
21 26 import __builtin__ as builtin_mod
22 27 import os
23 28 import re
24 29 import sys
25 30
26 31 from IPython.external import argparse
27 32 from IPython.utils.path import filefind, get_ipython_dir
28 33 from IPython.utils import py3compat, text, warn
29 34 from IPython.utils.encoding import DEFAULT_ENCODING
30 35
31 36 #-----------------------------------------------------------------------------
32 37 # Exceptions
33 38 #-----------------------------------------------------------------------------
34 39
35 40
36 41 class ConfigError(Exception):
37 42 pass
38 43
39 44 class ConfigLoaderError(ConfigError):
40 45 pass
41 46
42 47 class ConfigFileNotFound(ConfigError):
43 48 pass
44 49
45 50 class ArgumentError(ConfigLoaderError):
46 51 pass
47 52
48 53 #-----------------------------------------------------------------------------
49 54 # Argparse fix
50 55 #-----------------------------------------------------------------------------
51 56
52 57 # Unfortunately argparse by default prints help messages to stderr instead of
53 58 # stdout. This makes it annoying to capture long help screens at the command
54 59 # line, since one must know how to pipe stderr, which many users don't know how
55 60 # to do. So we override the print_help method with one that defaults to
56 61 # stdout and use our class instead.
57 62
58 63 class ArgumentParser(argparse.ArgumentParser):
59 64 """Simple argparse subclass that prints help to stdout by default."""
60 65
61 66 def print_help(self, file=None):
62 67 if file is None:
63 68 file = sys.stdout
64 69 return super(ArgumentParser, self).print_help(file)
65 70
66 71 print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__
67 72
68 73 #-----------------------------------------------------------------------------
69 74 # Config class for holding config information
70 75 #-----------------------------------------------------------------------------
71 76
72 77
73 78 class Config(dict):
74 79 """An attribute based dict that can do smart merges."""
75 80
76 81 def __init__(self, *args, **kwds):
77 82 dict.__init__(self, *args, **kwds)
78 83 # This sets self.__dict__ = self, but it has to be done this way
79 84 # because we are also overriding __setattr__.
80 85 dict.__setattr__(self, '__dict__', self)
81 86
82 87 def _merge(self, other):
83 88 to_update = {}
84 89 for k, v in other.iteritems():
85 90 if k not in self:
86 91 to_update[k] = v
87 92 else: # I have this key
88 93 if isinstance(v, Config):
89 94 # Recursively merge common sub Configs
90 95 self[k]._merge(v)
91 96 else:
92 97 # Plain updates for non-Configs
93 98 to_update[k] = v
94 99
95 100 self.update(to_update)
96 101
97 102 def _is_section_key(self, key):
98 103 if key[0].upper()==key[0] and not key.startswith('_'):
99 104 return True
100 105 else:
101 106 return False
102 107
103 108 def __contains__(self, key):
104 109 if self._is_section_key(key):
105 110 return True
106 111 else:
107 112 return super(Config, self).__contains__(key)
108 113 # .has_key is deprecated for dictionaries.
109 114 has_key = __contains__
110 115
111 116 def _has_section(self, key):
112 117 if self._is_section_key(key):
113 118 if super(Config, self).__contains__(key):
114 119 return True
115 120 return False
116 121
117 122 def copy(self):
118 123 return type(self)(dict.copy(self))
119 124
120 125 def __copy__(self):
121 126 return self.copy()
122 127
123 128 def __deepcopy__(self, memo):
124 129 import copy
125 130 return type(self)(copy.deepcopy(self.items()))
126 131
127 132 def __getitem__(self, key):
128 133 # We cannot use directly self._is_section_key, because it triggers
129 134 # infinite recursion on top of PyPy. Instead, we manually fish the
130 135 # bound method.
131 136 is_section_key = self.__class__._is_section_key.__get__(self)
132 137
133 138 # Because we use this for an exec namespace, we need to delegate
134 139 # the lookup of names in __builtin__ to itself. This means
135 140 # that you can't have section or attribute names that are
136 141 # builtins.
137 142 try:
138 143 return getattr(builtin_mod, key)
139 144 except AttributeError:
140 145 pass
141 146 if is_section_key(key):
142 147 try:
143 148 return dict.__getitem__(self, key)
144 149 except KeyError:
145 150 c = Config()
146 151 dict.__setitem__(self, key, c)
147 152 return c
148 153 else:
149 154 return dict.__getitem__(self, key)
150 155
151 156 def __setitem__(self, key, value):
152 157 # Don't allow names in __builtin__ to be modified.
153 158 if hasattr(builtin_mod, key):
154 159 raise ConfigError('Config variable names cannot have the same name '
155 160 'as a Python builtin: %s' % key)
156 161 if self._is_section_key(key):
157 162 if not isinstance(value, Config):
158 163 raise ValueError('values whose keys begin with an uppercase '
159 164 'char must be Config instances: %r, %r' % (key, value))
160 165 else:
161 166 dict.__setitem__(self, key, value)
162 167
163 168 def __getattr__(self, key):
164 169 try:
165 170 return self.__getitem__(key)
166 171 except KeyError as e:
167 172 raise AttributeError(e)
168 173
169 174 def __setattr__(self, key, value):
170 175 try:
171 176 self.__setitem__(key, value)
172 177 except KeyError as e:
173 178 raise AttributeError(e)
174 179
175 180 def __delattr__(self, key):
176 181 try:
177 182 dict.__delitem__(self, key)
178 183 except KeyError as e:
179 184 raise AttributeError(e)
180 185
181 186
182 187 #-----------------------------------------------------------------------------
183 188 # Config loading classes
184 189 #-----------------------------------------------------------------------------
185 190
186 191
187 192 class ConfigLoader(object):
188 193 """A object for loading configurations from just about anywhere.
189 194
190 195 The resulting configuration is packaged as a :class:`Struct`.
191 196
192 197 Notes
193 198 -----
194 199 A :class:`ConfigLoader` does one thing: load a config from a source
195 200 (file, command line arguments) and returns the data as a :class:`Struct`.
196 201 There are lots of things that :class:`ConfigLoader` does not do. It does
197 202 not implement complex logic for finding config files. It does not handle
198 203 default values or merge multiple configs. These things need to be
199 204 handled elsewhere.
200 205 """
201 206
202 207 def __init__(self):
203 208 """A base class for config loaders.
204 209
205 210 Examples
206 211 --------
207 212
208 213 >>> cl = ConfigLoader()
209 214 >>> config = cl.load_config()
210 215 >>> config
211 216 {}
212 217 """
213 218 self.clear()
214 219
215 220 def clear(self):
216 221 self.config = Config()
217 222
218 223 def load_config(self):
219 224 """Load a config from somewhere, return a :class:`Config` instance.
220 225
221 226 Usually, this will cause self.config to be set and then returned.
222 227 However, in most cases, :meth:`ConfigLoader.clear` should be called
223 228 to erase any previous state.
224 229 """
225 230 self.clear()
226 231 return self.config
227 232
228 233
229 234 class FileConfigLoader(ConfigLoader):
230 235 """A base class for file based configurations.
231 236
232 237 As we add more file based config loaders, the common logic should go
233 238 here.
234 239 """
235 240 pass
236 241
237 242
238 243 class PyFileConfigLoader(FileConfigLoader):
239 244 """A config loader for pure python files.
240 245
241 246 This calls execfile on a plain python file and looks for attributes
242 247 that are all caps. These attribute are added to the config Struct.
243 248 """
244 249
245 250 def __init__(self, filename, path=None):
246 251 """Build a config loader for a filename and path.
247 252
248 253 Parameters
249 254 ----------
250 255 filename : str
251 256 The file name of the config file.
252 257 path : str, list, tuple
253 258 The path to search for the config file on, or a sequence of
254 259 paths to try in order.
255 260 """
256 261 super(PyFileConfigLoader, self).__init__()
257 262 self.filename = filename
258 263 self.path = path
259 264 self.full_filename = ''
260 265 self.data = None
261 266
262 267 def load_config(self):
263 268 """Load the config from a file and return it as a Struct."""
264 269 self.clear()
265 270 try:
266 271 self._find_file()
267 272 except IOError as e:
268 273 raise ConfigFileNotFound(str(e))
269 274 self._read_file_as_dict()
270 275 self._convert_to_config()
271 276 return self.config
272 277
273 278 def _find_file(self):
274 279 """Try to find the file by searching the paths."""
275 280 self.full_filename = filefind(self.filename, self.path)
276 281
277 282 def _read_file_as_dict(self):
278 283 """Load the config file into self.config, with recursive loading."""
279 284 # This closure is made available in the namespace that is used
280 285 # to exec the config file. It allows users to call
281 286 # load_subconfig('myconfig.py') to load config files recursively.
282 287 # It needs to be a closure because it has references to self.path
283 288 # and self.config. The sub-config is loaded with the same path
284 289 # as the parent, but it uses an empty config which is then merged
285 290 # with the parents.
286 291
287 292 # If a profile is specified, the config file will be loaded
288 293 # from that profile
289 294
290 295 def load_subconfig(fname, profile=None):
291 296 # import here to prevent circular imports
292 297 from IPython.core.profiledir import ProfileDir, ProfileDirError
293 298 if profile is not None:
294 299 try:
295 300 profile_dir = ProfileDir.find_profile_dir_by_name(
296 301 get_ipython_dir(),
297 302 profile,
298 303 )
299 304 except ProfileDirError:
300 305 return
301 306 path = profile_dir.location
302 307 else:
303 308 path = self.path
304 309 loader = PyFileConfigLoader(fname, path)
305 310 try:
306 311 sub_config = loader.load_config()
307 312 except ConfigFileNotFound:
308 313 # Pass silently if the sub config is not there. This happens
309 314 # when a user s using a profile, but not the default config.
310 315 pass
311 316 else:
312 317 self.config._merge(sub_config)
313 318
314 319 # Again, this needs to be a closure and should be used in config
315 320 # files to get the config being loaded.
316 321 def get_config():
317 322 return self.config
318 323
319 324 namespace = dict(load_subconfig=load_subconfig, get_config=get_config)
320 325 fs_encoding = sys.getfilesystemencoding() or 'ascii'
321 326 conf_filename = self.full_filename.encode(fs_encoding)
322 327 py3compat.execfile(conf_filename, namespace)
323 328
324 329 def _convert_to_config(self):
325 330 if self.data is None:
326 331 ConfigLoaderError('self.data does not exist')
327 332
328 333
329 334 class CommandLineConfigLoader(ConfigLoader):
330 335 """A config loader for command line arguments.
331 336
332 337 As we add more command line based loaders, the common logic should go
333 338 here.
334 339 """
335 340
336 341 def _exec_config_str(self, lhs, rhs):
337 342 """execute self.config.<lhs> = <rhs>
338 343
339 344 * expands ~ with expanduser
340 345 * tries to assign with raw eval, otherwise assigns with just the string,
341 346 allowing `--C.a=foobar` and `--C.a="foobar"` to be equivalent. *Not*
342 347 equivalent are `--C.a=4` and `--C.a='4'`.
343 348 """
344 349 rhs = os.path.expanduser(rhs)
345 350 try:
346 351 # Try to see if regular Python syntax will work. This
347 352 # won't handle strings as the quote marks are removed
348 353 # by the system shell.
349 354 value = eval(rhs)
350 355 except (NameError, SyntaxError):
351 356 # This case happens if the rhs is a string.
352 357 value = rhs
353 358
354 359 exec u'self.config.%s = value' % lhs
355 360
356 361 def _load_flag(self, cfg):
357 362 """update self.config from a flag, which can be a dict or Config"""
358 363 if isinstance(cfg, (dict, Config)):
359 364 # don't clobber whole config sections, update
360 365 # each section from config:
361 366 for sec,c in cfg.iteritems():
362 367 self.config[sec].update(c)
363 368 else:
364 369 raise TypeError("Invalid flag: %r" % cfg)
365 370
366 371 # raw --identifier=value pattern
367 372 # but *also* accept '-' as wordsep, for aliases
368 373 # accepts: --foo=a
369 374 # --Class.trait=value
370 375 # --alias-name=value
371 376 # rejects: -foo=value
372 377 # --foo
373 378 # --Class.trait
374 379 kv_pattern = re.compile(r'\-\-[A-Za-z][\w\-]*(\.[\w\-]+)*\=.*')
375 380
376 381 # just flags, no assignments, with two *or one* leading '-'
377 382 # accepts: --foo
378 383 # -foo-bar-again
379 384 # rejects: --anything=anything
380 385 # --two.word
381 386
382 387 flag_pattern = re.compile(r'\-\-?\w+[\-\w]*$')
383 388
384 389 class KeyValueConfigLoader(CommandLineConfigLoader):
385 390 """A config loader that loads key value pairs from the command line.
386 391
387 392 This allows command line options to be gives in the following form::
388 393
389 394 ipython --profile="foo" --InteractiveShell.autocall=False
390 395 """
391 396
392 397 def __init__(self, argv=None, aliases=None, flags=None):
393 398 """Create a key value pair config loader.
394 399
395 400 Parameters
396 401 ----------
397 402 argv : list
398 403 A list that has the form of sys.argv[1:] which has unicode
399 404 elements of the form u"key=value". If this is None (default),
400 405 then sys.argv[1:] will be used.
401 406 aliases : dict
402 407 A dict of aliases for configurable traits.
403 408 Keys are the short aliases, Values are the resolved trait.
404 409 Of the form: `{'alias' : 'Configurable.trait'}`
405 410 flags : dict
406 411 A dict of flags, keyed by str name. Vaues can be Config objects,
407 412 dicts, or "key=value" strings. If Config or dict, when the flag
408 413 is triggered, The flag is loaded as `self.config.update(m)`.
409 414
410 415 Returns
411 416 -------
412 417 config : Config
413 418 The resulting Config object.
414 419
415 420 Examples
416 421 --------
417 422
418 423 >>> from IPython.config.loader import KeyValueConfigLoader
419 424 >>> cl = KeyValueConfigLoader()
420 425 >>> d = cl.load_config(["--A.name='brian'","--B.number=0"])
421 426 >>> sorted(d.items())
422 427 [('A', {'name': 'brian'}), ('B', {'number': 0})]
423 428 """
424 429 self.clear()
425 430 if argv is None:
426 431 argv = sys.argv[1:]
427 432 self.argv = argv
428 433 self.aliases = aliases or {}
429 434 self.flags = flags or {}
430 435
431 436
432 437 def clear(self):
433 438 super(KeyValueConfigLoader, self).clear()
434 439 self.extra_args = []
435 440
436 441
437 442 def _decode_argv(self, argv, enc=None):
438 443 """decode argv if bytes, using stin.encoding, falling back on default enc"""
439 444 uargv = []
440 445 if enc is None:
441 446 enc = DEFAULT_ENCODING
442 447 for arg in argv:
443 448 if not isinstance(arg, unicode):
444 449 # only decode if not already decoded
445 450 arg = arg.decode(enc)
446 451 uargv.append(arg)
447 452 return uargv
448 453
449 454
450 455 def load_config(self, argv=None, aliases=None, flags=None):
451 456 """Parse the configuration and generate the Config object.
452 457
453 458 After loading, any arguments that are not key-value or
454 459 flags will be stored in self.extra_args - a list of
455 460 unparsed command-line arguments. This is used for
456 461 arguments such as input files or subcommands.
457 462
458 463 Parameters
459 464 ----------
460 465 argv : list, optional
461 466 A list that has the form of sys.argv[1:] which has unicode
462 467 elements of the form u"key=value". If this is None (default),
463 468 then self.argv will be used.
464 469 aliases : dict
465 470 A dict of aliases for configurable traits.
466 471 Keys are the short aliases, Values are the resolved trait.
467 472 Of the form: `{'alias' : 'Configurable.trait'}`
468 473 flags : dict
469 474 A dict of flags, keyed by str name. Values can be Config objects
470 475 or dicts. When the flag is triggered, The config is loaded as
471 476 `self.config.update(cfg)`.
472 477 """
473 478 from IPython.config.configurable import Configurable
474 479
475 480 self.clear()
476 481 if argv is None:
477 482 argv = self.argv
478 483 if aliases is None:
479 484 aliases = self.aliases
480 485 if flags is None:
481 486 flags = self.flags
482 487
483 488 # ensure argv is a list of unicode strings:
484 489 uargv = self._decode_argv(argv)
485 490 for idx,raw in enumerate(uargv):
486 491 # strip leading '-'
487 492 item = raw.lstrip('-')
488 493
489 494 if raw == '--':
490 495 # don't parse arguments after '--'
491 496 # this is useful for relaying arguments to scripts, e.g.
492 497 # ipython -i foo.py --pylab=qt -- args after '--' go-to-foo.py
493 498 self.extra_args.extend(uargv[idx+1:])
494 499 break
495 500
496 501 if kv_pattern.match(raw):
497 502 lhs,rhs = item.split('=',1)
498 503 # Substitute longnames for aliases.
499 504 if lhs in aliases:
500 505 lhs = aliases[lhs]
501 506 if '.' not in lhs:
502 507 # probably a mistyped alias, but not technically illegal
503 508 warn.warn("Unrecognized alias: '%s', it will probably have no effect."%lhs)
504 509 try:
505 510 self._exec_config_str(lhs, rhs)
506 511 except Exception:
507 512 raise ArgumentError("Invalid argument: '%s'" % raw)
508 513
509 514 elif flag_pattern.match(raw):
510 515 if item in flags:
511 516 cfg,help = flags[item]
512 517 self._load_flag(cfg)
513 518 else:
514 519 raise ArgumentError("Unrecognized flag: '%s'"%raw)
515 520 elif raw.startswith('-'):
516 521 kv = '--'+item
517 522 if kv_pattern.match(kv):
518 523 raise ArgumentError("Invalid argument: '%s', did you mean '%s'?"%(raw, kv))
519 524 else:
520 525 raise ArgumentError("Invalid argument: '%s'"%raw)
521 526 else:
522 527 # keep all args that aren't valid in a list,
523 528 # in case our parent knows what to do with them.
524 529 self.extra_args.append(item)
525 530 return self.config
526 531
527 532 class ArgParseConfigLoader(CommandLineConfigLoader):
528 533 """A loader that uses the argparse module to load from the command line."""
529 534
530 535 def __init__(self, argv=None, aliases=None, flags=None, *parser_args, **parser_kw):
531 536 """Create a config loader for use with argparse.
532 537
533 538 Parameters
534 539 ----------
535 540
536 541 argv : optional, list
537 542 If given, used to read command-line arguments from, otherwise
538 543 sys.argv[1:] is used.
539 544
540 545 parser_args : tuple
541 546 A tuple of positional arguments that will be passed to the
542 547 constructor of :class:`argparse.ArgumentParser`.
543 548
544 549 parser_kw : dict
545 550 A tuple of keyword arguments that will be passed to the
546 551 constructor of :class:`argparse.ArgumentParser`.
547 552
548 553 Returns
549 554 -------
550 555 config : Config
551 556 The resulting Config object.
552 557 """
553 558 super(CommandLineConfigLoader, self).__init__()
554 559 self.clear()
555 560 if argv is None:
556 561 argv = sys.argv[1:]
557 562 self.argv = argv
558 563 self.aliases = aliases or {}
559 564 self.flags = flags or {}
560 565
561 566 self.parser_args = parser_args
562 567 self.version = parser_kw.pop("version", None)
563 568 kwargs = dict(argument_default=argparse.SUPPRESS)
564 569 kwargs.update(parser_kw)
565 570 self.parser_kw = kwargs
566 571
567 572 def load_config(self, argv=None, aliases=None, flags=None):
568 573 """Parse command line arguments and return as a Config object.
569 574
570 575 Parameters
571 576 ----------
572 577
573 578 args : optional, list
574 579 If given, a list with the structure of sys.argv[1:] to parse
575 580 arguments from. If not given, the instance's self.argv attribute
576 581 (given at construction time) is used."""
577 582 self.clear()
578 583 if argv is None:
579 584 argv = self.argv
580 585 if aliases is None:
581 586 aliases = self.aliases
582 587 if flags is None:
583 588 flags = self.flags
584 589 self._create_parser(aliases, flags)
585 590 self._parse_args(argv)
586 591 self._convert_to_config()
587 592 return self.config
588 593
589 594 def get_extra_args(self):
590 595 if hasattr(self, 'extra_args'):
591 596 return self.extra_args
592 597 else:
593 598 return []
594 599
595 600 def _create_parser(self, aliases=None, flags=None):
596 601 self.parser = ArgumentParser(*self.parser_args, **self.parser_kw)
597 602 self._add_arguments(aliases, flags)
598 603
599 604 def _add_arguments(self, aliases=None, flags=None):
600 605 raise NotImplementedError("subclasses must implement _add_arguments")
601 606
602 607 def _parse_args(self, args):
603 608 """self.parser->self.parsed_data"""
604 609 # decode sys.argv to support unicode command-line options
605 610 enc = DEFAULT_ENCODING
606 611 uargs = [py3compat.cast_unicode(a, enc) for a in args]
607 612 self.parsed_data, self.extra_args = self.parser.parse_known_args(uargs)
608 613
609 614 def _convert_to_config(self):
610 615 """self.parsed_data->self.config"""
611 616 for k, v in vars(self.parsed_data).iteritems():
612 617 exec "self.config.%s = v"%k in locals(), globals()
613 618
614 619 class KVArgParseConfigLoader(ArgParseConfigLoader):
615 620 """A config loader that loads aliases and flags with argparse,
616 621 but will use KVLoader for the rest. This allows better parsing
617 622 of common args, such as `ipython -c 'print 5'`, but still gets
618 623 arbitrary config with `ipython --InteractiveShell.use_readline=False`"""
619 624
620 625 def _add_arguments(self, aliases=None, flags=None):
621 626 self.alias_flags = {}
622 627 # print aliases, flags
623 628 if aliases is None:
624 629 aliases = self.aliases
625 630 if flags is None:
626 631 flags = self.flags
627 632 paa = self.parser.add_argument
628 633 for key,value in aliases.iteritems():
629 634 if key in flags:
630 635 # flags
631 636 nargs = '?'
632 637 else:
633 638 nargs = None
634 639 if len(key) is 1:
635 640 paa('-'+key, '--'+key, type=unicode, dest=value, nargs=nargs)
636 641 else:
637 642 paa('--'+key, type=unicode, dest=value, nargs=nargs)
638 643 for key, (value, help) in flags.iteritems():
639 644 if key in self.aliases:
640 645 #
641 646 self.alias_flags[self.aliases[key]] = value
642 647 continue
643 648 if len(key) is 1:
644 649 paa('-'+key, '--'+key, action='append_const', dest='_flags', const=value)
645 650 else:
646 651 paa('--'+key, action='append_const', dest='_flags', const=value)
647 652
648 653 def _convert_to_config(self):
649 654 """self.parsed_data->self.config, parse unrecognized extra args via KVLoader."""
650 655 # remove subconfigs list from namespace before transforming the Namespace
651 656 if '_flags' in self.parsed_data:
652 657 subcs = self.parsed_data._flags
653 658 del self.parsed_data._flags
654 659 else:
655 660 subcs = []
656 661
657 662 for k, v in vars(self.parsed_data).iteritems():
658 663 if v is None:
659 664 # it was a flag that shares the name of an alias
660 665 subcs.append(self.alias_flags[k])
661 666 else:
662 667 # eval the KV assignment
663 668 self._exec_config_str(k, v)
664 669
665 670 for subc in subcs:
666 671 self._load_flag(subc)
667 672
668 673 if self.extra_args:
669 674 sub_parser = KeyValueConfigLoader()
670 675 sub_parser.load_config(self.extra_args)
671 676 self.config._merge(sub_parser.config)
672 677 self.extra_args = sub_parser.extra_args
673 678
674 679
675 680 def load_pyconfig_files(config_files, path):
676 681 """Load multiple Python config files, merging each of them in turn.
677 682
678 683 Parameters
679 684 ==========
680 685 config_files : list of str
681 686 List of config files names to load and merge into the config.
682 687 path : unicode
683 688 The full path to the location of the config files.
684 689 """
685 690 config = Config()
686 691 for cf in config_files:
687 692 loader = PyFileConfigLoader(cf, path=path)
688 693 try:
689 694 next_config = loader.load_config()
690 695 except ConfigFileNotFound:
691 696 pass
692 697 except:
693 698 raise
694 699 else:
695 700 config._merge(next_config)
696 701 return config
@@ -1,621 +1,625 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Display formatters.
3 3
4 Inheritance diagram:
5
6 .. inheritance-diagram:: IPython.core.formatters
7 :parts: 3
4 8
5 9 Authors:
6 10
7 11 * Robert Kern
8 12 * Brian Granger
9 13 """
10 14 #-----------------------------------------------------------------------------
11 15 # Copyright (C) 2010-2011, IPython Development Team.
12 16 #
13 17 # Distributed under the terms of the Modified BSD License.
14 18 #
15 19 # The full license is in the file COPYING.txt, distributed with this software.
16 20 #-----------------------------------------------------------------------------
17 21
18 22 #-----------------------------------------------------------------------------
19 23 # Imports
20 24 #-----------------------------------------------------------------------------
21 25
22 26 # Stdlib imports
23 27 import abc
24 28 import sys
25 29 # We must use StringIO, as cStringIO doesn't handle unicode properly.
26 30 from StringIO import StringIO
27 31
28 32 # Our own imports
29 33 from IPython.config.configurable import Configurable
30 34 from IPython.lib import pretty
31 35 from IPython.utils.traitlets import Bool, Dict, Integer, Unicode, CUnicode, ObjectName
32 36 from IPython.utils.py3compat import unicode_to_str
33 37
34 38
35 39 #-----------------------------------------------------------------------------
36 40 # The main DisplayFormatter class
37 41 #-----------------------------------------------------------------------------
38 42
39 43
40 44 class DisplayFormatter(Configurable):
41 45
42 46 # When set to true only the default plain text formatter will be used.
43 47 plain_text_only = Bool(False, config=True)
44 48
45 49 # A dict of formatter whose keys are format types (MIME types) and whose
46 50 # values are subclasses of BaseFormatter.
47 51 formatters = Dict()
48 52 def _formatters_default(self):
49 53 """Activate the default formatters."""
50 54 formatter_classes = [
51 55 PlainTextFormatter,
52 56 HTMLFormatter,
53 57 SVGFormatter,
54 58 PNGFormatter,
55 59 JPEGFormatter,
56 60 LatexFormatter,
57 61 JSONFormatter,
58 62 JavascriptFormatter
59 63 ]
60 64 d = {}
61 65 for cls in formatter_classes:
62 66 f = cls(config=self.config)
63 67 d[f.format_type] = f
64 68 return d
65 69
66 70 def format(self, obj, include=None, exclude=None):
67 71 """Return a format data dict for an object.
68 72
69 73 By default all format types will be computed.
70 74
71 75 The following MIME types are currently implemented:
72 76
73 77 * text/plain
74 78 * text/html
75 79 * text/latex
76 80 * application/json
77 81 * application/javascript
78 82 * image/png
79 83 * image/jpeg
80 84 * image/svg+xml
81 85
82 86 Parameters
83 87 ----------
84 88 obj : object
85 89 The Python object whose format data will be computed.
86 90 include : list or tuple, optional
87 91 A list of format type strings (MIME types) to include in the
88 92 format data dict. If this is set *only* the format types included
89 93 in this list will be computed.
90 94 exclude : list or tuple, optional
91 95 A list of format type string (MIME types) to exclue in the format
92 96 data dict. If this is set all format types will be computed,
93 97 except for those included in this argument.
94 98
95 99 Returns
96 100 -------
97 101 format_dict : dict
98 102 A dictionary of key/value pairs, one or each format that was
99 103 generated for the object. The keys are the format types, which
100 104 will usually be MIME type strings and the values and JSON'able
101 105 data structure containing the raw data for the representation in
102 106 that format.
103 107 """
104 108 format_dict = {}
105 109
106 110 # If plain text only is active
107 111 if self.plain_text_only:
108 112 formatter = self.formatters['text/plain']
109 113 try:
110 114 data = formatter(obj)
111 115 except:
112 116 # FIXME: log the exception
113 117 raise
114 118 if data is not None:
115 119 format_dict['text/plain'] = data
116 120 return format_dict
117 121
118 122 for format_type, formatter in self.formatters.items():
119 123 if include is not None:
120 124 if format_type not in include:
121 125 continue
122 126 if exclude is not None:
123 127 if format_type in exclude:
124 128 continue
125 129 try:
126 130 data = formatter(obj)
127 131 except:
128 132 # FIXME: log the exception
129 133 raise
130 134 if data is not None:
131 135 format_dict[format_type] = data
132 136 return format_dict
133 137
134 138 @property
135 139 def format_types(self):
136 140 """Return the format types (MIME types) of the active formatters."""
137 141 return self.formatters.keys()
138 142
139 143
140 144 #-----------------------------------------------------------------------------
141 145 # Formatters for specific format types (text, html, svg, etc.)
142 146 #-----------------------------------------------------------------------------
143 147
144 148
145 149 class FormatterABC(object):
146 150 """ Abstract base class for Formatters.
147 151
148 152 A formatter is a callable class that is responsible for computing the
149 153 raw format data for a particular format type (MIME type). For example,
150 154 an HTML formatter would have a format type of `text/html` and would return
151 155 the HTML representation of the object when called.
152 156 """
153 157 __metaclass__ = abc.ABCMeta
154 158
155 159 # The format type of the data returned, usually a MIME type.
156 160 format_type = 'text/plain'
157 161
158 162 # Is the formatter enabled...
159 163 enabled = True
160 164
161 165 @abc.abstractmethod
162 166 def __call__(self, obj):
163 167 """Return a JSON'able representation of the object.
164 168
165 169 If the object cannot be formatted by this formatter, then return None
166 170 """
167 171 try:
168 172 return repr(obj)
169 173 except TypeError:
170 174 return None
171 175
172 176
173 177 class BaseFormatter(Configurable):
174 178 """A base formatter class that is configurable.
175 179
176 180 This formatter should usually be used as the base class of all formatters.
177 181 It is a traited :class:`Configurable` class and includes an extensible
178 182 API for users to determine how their objects are formatted. The following
179 183 logic is used to find a function to format an given object.
180 184
181 185 1. The object is introspected to see if it has a method with the name
182 186 :attr:`print_method`. If is does, that object is passed to that method
183 187 for formatting.
184 188 2. If no print method is found, three internal dictionaries are consulted
185 189 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
186 190 and :attr:`deferred_printers`.
187 191
188 192 Users should use these dictionaries to register functions that will be
189 193 used to compute the format data for their objects (if those objects don't
190 194 have the special print methods). The easiest way of using these
191 195 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
192 196 methods.
193 197
194 198 If no function/callable is found to compute the format data, ``None`` is
195 199 returned and this format type is not used.
196 200 """
197 201
198 202 format_type = Unicode('text/plain')
199 203
200 204 enabled = Bool(True, config=True)
201 205
202 206 print_method = ObjectName('__repr__')
203 207
204 208 # The singleton printers.
205 209 # Maps the IDs of the builtin singleton objects to the format functions.
206 210 singleton_printers = Dict(config=True)
207 211 def _singleton_printers_default(self):
208 212 return {}
209 213
210 214 # The type-specific printers.
211 215 # Map type objects to the format functions.
212 216 type_printers = Dict(config=True)
213 217 def _type_printers_default(self):
214 218 return {}
215 219
216 220 # The deferred-import type-specific printers.
217 221 # Map (modulename, classname) pairs to the format functions.
218 222 deferred_printers = Dict(config=True)
219 223 def _deferred_printers_default(self):
220 224 return {}
221 225
222 226 def __call__(self, obj):
223 227 """Compute the format for an object."""
224 228 if self.enabled:
225 229 obj_id = id(obj)
226 230 try:
227 231 obj_class = getattr(obj, '__class__', None) or type(obj)
228 232 # First try to find registered singleton printers for the type.
229 233 try:
230 234 printer = self.singleton_printers[obj_id]
231 235 except (TypeError, KeyError):
232 236 pass
233 237 else:
234 238 return printer(obj)
235 239 # Next look for type_printers.
236 240 for cls in pretty._get_mro(obj_class):
237 241 if cls in self.type_printers:
238 242 return self.type_printers[cls](obj)
239 243 else:
240 244 printer = self._in_deferred_types(cls)
241 245 if printer is not None:
242 246 return printer(obj)
243 247 # Finally look for special method names.
244 248 if hasattr(obj_class, self.print_method):
245 249 printer = getattr(obj_class, self.print_method)
246 250 return printer(obj)
247 251 return None
248 252 except Exception:
249 253 pass
250 254 else:
251 255 return None
252 256
253 257 def for_type(self, typ, func):
254 258 """Add a format function for a given type.
255 259
256 260 Parameters
257 261 -----------
258 262 typ : class
259 263 The class of the object that will be formatted using `func`.
260 264 func : callable
261 265 The callable that will be called to compute the format data. The
262 266 call signature of this function is simple, it must take the
263 267 object to be formatted and return the raw data for the given
264 268 format. Subclasses may use a different call signature for the
265 269 `func` argument.
266 270 """
267 271 oldfunc = self.type_printers.get(typ, None)
268 272 if func is not None:
269 273 # To support easy restoration of old printers, we need to ignore
270 274 # Nones.
271 275 self.type_printers[typ] = func
272 276 return oldfunc
273 277
274 278 def for_type_by_name(self, type_module, type_name, func):
275 279 """Add a format function for a type specified by the full dotted
276 280 module and name of the type, rather than the type of the object.
277 281
278 282 Parameters
279 283 ----------
280 284 type_module : str
281 285 The full dotted name of the module the type is defined in, like
282 286 ``numpy``.
283 287 type_name : str
284 288 The name of the type (the class name), like ``dtype``
285 289 func : callable
286 290 The callable that will be called to compute the format data. The
287 291 call signature of this function is simple, it must take the
288 292 object to be formatted and return the raw data for the given
289 293 format. Subclasses may use a different call signature for the
290 294 `func` argument.
291 295 """
292 296 key = (type_module, type_name)
293 297 oldfunc = self.deferred_printers.get(key, None)
294 298 if func is not None:
295 299 # To support easy restoration of old printers, we need to ignore
296 300 # Nones.
297 301 self.deferred_printers[key] = func
298 302 return oldfunc
299 303
300 304 def _in_deferred_types(self, cls):
301 305 """
302 306 Check if the given class is specified in the deferred type registry.
303 307
304 308 Returns the printer from the registry if it exists, and None if the
305 309 class is not in the registry. Successful matches will be moved to the
306 310 regular type registry for future use.
307 311 """
308 312 mod = getattr(cls, '__module__', None)
309 313 name = getattr(cls, '__name__', None)
310 314 key = (mod, name)
311 315 printer = None
312 316 if key in self.deferred_printers:
313 317 # Move the printer over to the regular registry.
314 318 printer = self.deferred_printers.pop(key)
315 319 self.type_printers[cls] = printer
316 320 return printer
317 321
318 322
319 323 class PlainTextFormatter(BaseFormatter):
320 324 """The default pretty-printer.
321 325
322 326 This uses :mod:`IPython.lib.pretty` to compute the format data of
323 327 the object. If the object cannot be pretty printed, :func:`repr` is used.
324 328 See the documentation of :mod:`IPython.lib.pretty` for details on
325 329 how to write pretty printers. Here is a simple example::
326 330
327 331 def dtype_pprinter(obj, p, cycle):
328 332 if cycle:
329 333 return p.text('dtype(...)')
330 334 if hasattr(obj, 'fields'):
331 335 if obj.fields is None:
332 336 p.text(repr(obj))
333 337 else:
334 338 p.begin_group(7, 'dtype([')
335 339 for i, field in enumerate(obj.descr):
336 340 if i > 0:
337 341 p.text(',')
338 342 p.breakable()
339 343 p.pretty(field)
340 344 p.end_group(7, '])')
341 345 """
342 346
343 347 # The format type of data returned.
344 348 format_type = Unicode('text/plain')
345 349
346 350 # This subclass ignores this attribute as it always need to return
347 351 # something.
348 352 enabled = Bool(True, config=False)
349 353
350 354 # Look for a _repr_pretty_ methods to use for pretty printing.
351 355 print_method = ObjectName('_repr_pretty_')
352 356
353 357 # Whether to pretty-print or not.
354 358 pprint = Bool(True, config=True)
355 359
356 360 # Whether to be verbose or not.
357 361 verbose = Bool(False, config=True)
358 362
359 363 # The maximum width.
360 364 max_width = Integer(79, config=True)
361 365
362 366 # The newline character.
363 367 newline = Unicode('\n', config=True)
364 368
365 369 # format-string for pprinting floats
366 370 float_format = Unicode('%r')
367 371 # setter for float precision, either int or direct format-string
368 372 float_precision = CUnicode('', config=True)
369 373
370 374 def _float_precision_changed(self, name, old, new):
371 375 """float_precision changed, set float_format accordingly.
372 376
373 377 float_precision can be set by int or str.
374 378 This will set float_format, after interpreting input.
375 379 If numpy has been imported, numpy print precision will also be set.
376 380
377 381 integer `n` sets format to '%.nf', otherwise, format set directly.
378 382
379 383 An empty string returns to defaults (repr for float, 8 for numpy).
380 384
381 385 This parameter can be set via the '%precision' magic.
382 386 """
383 387
384 388 if '%' in new:
385 389 # got explicit format string
386 390 fmt = new
387 391 try:
388 392 fmt%3.14159
389 393 except Exception:
390 394 raise ValueError("Precision must be int or format string, not %r"%new)
391 395 elif new:
392 396 # otherwise, should be an int
393 397 try:
394 398 i = int(new)
395 399 assert i >= 0
396 400 except ValueError:
397 401 raise ValueError("Precision must be int or format string, not %r"%new)
398 402 except AssertionError:
399 403 raise ValueError("int precision must be non-negative, not %r"%i)
400 404
401 405 fmt = '%%.%if'%i
402 406 if 'numpy' in sys.modules:
403 407 # set numpy precision if it has been imported
404 408 import numpy
405 409 numpy.set_printoptions(precision=i)
406 410 else:
407 411 # default back to repr
408 412 fmt = '%r'
409 413 if 'numpy' in sys.modules:
410 414 import numpy
411 415 # numpy default is 8
412 416 numpy.set_printoptions(precision=8)
413 417 self.float_format = fmt
414 418
415 419 # Use the default pretty printers from IPython.lib.pretty.
416 420 def _singleton_printers_default(self):
417 421 return pretty._singleton_pprinters.copy()
418 422
419 423 def _type_printers_default(self):
420 424 d = pretty._type_pprinters.copy()
421 425 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
422 426 return d
423 427
424 428 def _deferred_printers_default(self):
425 429 return pretty._deferred_type_pprinters.copy()
426 430
427 431 #### FormatterABC interface ####
428 432
429 433 def __call__(self, obj):
430 434 """Compute the pretty representation of the object."""
431 435 if not self.pprint:
432 436 try:
433 437 return repr(obj)
434 438 except TypeError:
435 439 return ''
436 440 else:
437 441 # This uses use StringIO, as cStringIO doesn't handle unicode.
438 442 stream = StringIO()
439 443 # self.newline.encode() is a quick fix for issue gh-597. We need to
440 444 # ensure that stream does not get a mix of unicode and bytestrings,
441 445 # or it will cause trouble.
442 446 printer = pretty.RepresentationPrinter(stream, self.verbose,
443 447 self.max_width, unicode_to_str(self.newline),
444 448 singleton_pprinters=self.singleton_printers,
445 449 type_pprinters=self.type_printers,
446 450 deferred_pprinters=self.deferred_printers)
447 451 printer.pretty(obj)
448 452 printer.flush()
449 453 return stream.getvalue()
450 454
451 455
452 456 class HTMLFormatter(BaseFormatter):
453 457 """An HTML formatter.
454 458
455 459 To define the callables that compute the HTML representation of your
456 460 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
457 461 or :meth:`for_type_by_name` methods to register functions that handle
458 462 this.
459 463
460 464 The return value of this formatter should be a valid HTML snippet that
461 465 could be injected into an existing DOM. It should *not* include the
462 466 ```<html>`` or ```<body>`` tags.
463 467 """
464 468 format_type = Unicode('text/html')
465 469
466 470 print_method = ObjectName('_repr_html_')
467 471
468 472
469 473 class SVGFormatter(BaseFormatter):
470 474 """An SVG formatter.
471 475
472 476 To define the callables that compute the SVG representation of your
473 477 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
474 478 or :meth:`for_type_by_name` methods to register functions that handle
475 479 this.
476 480
477 481 The return value of this formatter should be valid SVG enclosed in
478 482 ```<svg>``` tags, that could be injected into an existing DOM. It should
479 483 *not* include the ```<html>`` or ```<body>`` tags.
480 484 """
481 485 format_type = Unicode('image/svg+xml')
482 486
483 487 print_method = ObjectName('_repr_svg_')
484 488
485 489
486 490 class PNGFormatter(BaseFormatter):
487 491 """A PNG formatter.
488 492
489 493 To define the callables that compute the PNG representation of your
490 494 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
491 495 or :meth:`for_type_by_name` methods to register functions that handle
492 496 this.
493 497
494 498 The return value of this formatter should be raw PNG data, *not*
495 499 base64 encoded.
496 500 """
497 501 format_type = Unicode('image/png')
498 502
499 503 print_method = ObjectName('_repr_png_')
500 504
501 505
502 506 class JPEGFormatter(BaseFormatter):
503 507 """A JPEG formatter.
504 508
505 509 To define the callables that compute the JPEG representation of your
506 510 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
507 511 or :meth:`for_type_by_name` methods to register functions that handle
508 512 this.
509 513
510 514 The return value of this formatter should be raw JPEG data, *not*
511 515 base64 encoded.
512 516 """
513 517 format_type = Unicode('image/jpeg')
514 518
515 519 print_method = ObjectName('_repr_jpeg_')
516 520
517 521
518 522 class LatexFormatter(BaseFormatter):
519 523 """A LaTeX formatter.
520 524
521 525 To define the callables that compute the LaTeX representation of your
522 526 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
523 527 or :meth:`for_type_by_name` methods to register functions that handle
524 528 this.
525 529
526 530 The return value of this formatter should be a valid LaTeX equation,
527 531 enclosed in either ```$```, ```$$``` or another LaTeX equation
528 532 environment.
529 533 """
530 534 format_type = Unicode('text/latex')
531 535
532 536 print_method = ObjectName('_repr_latex_')
533 537
534 538
535 539 class JSONFormatter(BaseFormatter):
536 540 """A JSON string formatter.
537 541
538 542 To define the callables that compute the JSON string representation of
539 543 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
540 544 or :meth:`for_type_by_name` methods to register functions that handle
541 545 this.
542 546
543 547 The return value of this formatter should be a valid JSON string.
544 548 """
545 549 format_type = Unicode('application/json')
546 550
547 551 print_method = ObjectName('_repr_json_')
548 552
549 553
550 554 class JavascriptFormatter(BaseFormatter):
551 555 """A Javascript formatter.
552 556
553 557 To define the callables that compute the Javascript representation of
554 558 your objects, define a :meth:`_repr_javascript_` method or use the
555 559 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
556 560 that handle this.
557 561
558 562 The return value of this formatter should be valid Javascript code and
559 563 should *not* be enclosed in ```<script>``` tags.
560 564 """
561 565 format_type = Unicode('application/javascript')
562 566
563 567 print_method = ObjectName('_repr_javascript_')
564 568
565 569 FormatterABC.register(BaseFormatter)
566 570 FormatterABC.register(PlainTextFormatter)
567 571 FormatterABC.register(HTMLFormatter)
568 572 FormatterABC.register(SVGFormatter)
569 573 FormatterABC.register(PNGFormatter)
570 574 FormatterABC.register(JPEGFormatter)
571 575 FormatterABC.register(LatexFormatter)
572 576 FormatterABC.register(JSONFormatter)
573 577 FormatterABC.register(JavascriptFormatter)
574 578
575 579
576 580 def format_display_data(obj, include=None, exclude=None):
577 581 """Return a format data dict for an object.
578 582
579 583 By default all format types will be computed.
580 584
581 585 The following MIME types are currently implemented:
582 586
583 587 * text/plain
584 588 * text/html
585 589 * text/latex
586 590 * application/json
587 591 * application/javascript
588 592 * image/png
589 593 * image/jpeg
590 594 * image/svg+xml
591 595
592 596 Parameters
593 597 ----------
594 598 obj : object
595 599 The Python object whose format data will be computed.
596 600
597 601 Returns
598 602 -------
599 603 format_dict : dict
600 604 A dictionary of key/value pairs, one or each format that was
601 605 generated for the object. The keys are the format types, which
602 606 will usually be MIME type strings and the values and JSON'able
603 607 data structure containing the raw data for the representation in
604 608 that format.
605 609 include : list or tuple, optional
606 610 A list of format type strings (MIME types) to include in the
607 611 format data dict. If this is set *only* the format types included
608 612 in this list will be computed.
609 613 exclude : list or tuple, optional
610 614 A list of format type string (MIME types) to exclue in the format
611 615 data dict. If this is set all format types will be computed,
612 616 except for those included in this argument.
613 617 """
614 618 from IPython.core.interactiveshell import InteractiveShell
615 619
616 620 InteractiveShell.instance().display_formatter.format(
617 621 obj,
618 622 include,
619 623 exclude
620 624 )
621 625
@@ -1,241 +1,246 b''
1 1 ''' A decorator-based method of constructing IPython magics with `argparse`
2 2 option handling.
3 3
4 4 New magic functions can be defined like so::
5 5
6 6 from IPython.core.magic_arguments import (argument, magic_arguments,
7 7 parse_argstring)
8 8
9 9 @magic_arguments()
10 10 @argument('-o', '--option', help='An optional argument.')
11 11 @argument('arg', type=int, help='An integer positional argument.')
12 12 def magic_cool(self, arg):
13 13 """ A really cool magic command.
14 14
15 15 """
16 16 args = parse_argstring(magic_cool, arg)
17 17 ...
18 18
19 19 The `@magic_arguments` decorator marks the function as having argparse arguments.
20 20 The `@argument` decorator adds an argument using the same syntax as argparse's
21 21 `add_argument()` method. More sophisticated uses may also require the
22 22 `@argument_group` or `@kwds` decorator to customize the formatting and the
23 23 parsing.
24 24
25 25 Help text for the magic is automatically generated from the docstring and the
26 26 arguments::
27 27
28 28 In[1]: %cool?
29 29 %cool [-o OPTION] arg
30 30
31 31 A really cool magic command.
32 32
33 33 positional arguments:
34 34 arg An integer positional argument.
35 35
36 36 optional arguments:
37 37 -o OPTION, --option OPTION
38 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 47 # Copyright (C) 2010-2011, IPython Development Team.
43 48 #
44 49 # Distributed under the terms of the Modified BSD License.
45 50 #
46 51 # The full license is in the file COPYING.txt, distributed with this software.
47 52 #-----------------------------------------------------------------------------
48 53
49 54 # Our own imports
50 55 from IPython.external import argparse
51 56 from IPython.core.error import UsageError
52 57 from IPython.utils.process import arg_split
53 58 from IPython.utils.text import dedent
54 59
55 60 class MagicHelpFormatter(argparse.RawDescriptionHelpFormatter):
56 61 """ A HelpFormatter which dedents but otherwise preserves indentation.
57 62 """
58 63 def _fill_text(self, text, width, indent):
59 64 return argparse.RawDescriptionHelpFormatter._fill_text(self, dedent(text), width, indent)
60 65
61 66 class MagicArgumentParser(argparse.ArgumentParser):
62 67 """ An ArgumentParser tweaked for use by IPython magics.
63 68 """
64 69 def __init__(self,
65 70 prog=None,
66 71 usage=None,
67 72 description=None,
68 73 epilog=None,
69 74 parents=None,
70 75 formatter_class=MagicHelpFormatter,
71 76 prefix_chars='-',
72 77 argument_default=None,
73 78 conflict_handler='error',
74 79 add_help=False):
75 80 if parents is None:
76 81 parents = []
77 82 super(MagicArgumentParser, self).__init__(prog=prog, usage=usage,
78 83 description=description, epilog=epilog,
79 84 parents=parents, formatter_class=formatter_class,
80 85 prefix_chars=prefix_chars, argument_default=argument_default,
81 86 conflict_handler=conflict_handler, add_help=add_help)
82 87
83 88 def error(self, message):
84 89 """ Raise a catchable error instead of exiting.
85 90 """
86 91 raise UsageError(message)
87 92
88 93 def parse_argstring(self, argstring):
89 94 """ Split a string into an argument list and parse that argument list.
90 95 """
91 96 argv = arg_split(argstring)
92 97 return self.parse_args(argv)
93 98
94 99
95 100 def construct_parser(magic_func):
96 101 """ Construct an argument parser using the function decorations.
97 102 """
98 103 kwds = getattr(magic_func, 'argcmd_kwds', {})
99 104 if 'description' not in kwds:
100 105 kwds['description'] = getattr(magic_func, '__doc__', None)
101 106 arg_name = real_name(magic_func)
102 107 parser = MagicArgumentParser(arg_name, **kwds)
103 108 # Reverse the list of decorators in order to apply them in the
104 109 # order in which they appear in the source.
105 110 group = None
106 111 for deco in magic_func.decorators[::-1]:
107 112 result = deco.add_to_parser(parser, group)
108 113 if result is not None:
109 114 group = result
110 115
111 116 # Replace the starting 'usage: ' with IPython's %.
112 117 help_text = parser.format_help()
113 118 if help_text.startswith('usage: '):
114 119 help_text = help_text.replace('usage: ', '%', 1)
115 120 else:
116 121 help_text = '%' + help_text
117 122
118 123 # Replace the magic function's docstring with the full help text.
119 124 magic_func.__doc__ = help_text
120 125
121 126 return parser
122 127
123 128
124 129 def parse_argstring(magic_func, argstring):
125 130 """ Parse the string of arguments for the given magic function.
126 131 """
127 132 return magic_func.parser.parse_argstring(argstring)
128 133
129 134
130 135 def real_name(magic_func):
131 136 """ Find the real name of the magic.
132 137 """
133 138 magic_name = magic_func.__name__
134 139 if magic_name.startswith('magic_'):
135 140 magic_name = magic_name[len('magic_'):]
136 141 return getattr(magic_func, 'argcmd_name', magic_name)
137 142
138 143
139 144 class ArgDecorator(object):
140 145 """ Base class for decorators to add ArgumentParser information to a method.
141 146 """
142 147
143 148 def __call__(self, func):
144 149 if not getattr(func, 'has_arguments', False):
145 150 func.has_arguments = True
146 151 func.decorators = []
147 152 func.decorators.append(self)
148 153 return func
149 154
150 155 def add_to_parser(self, parser, group):
151 156 """ Add this object's information to the parser, if necessary.
152 157 """
153 158 pass
154 159
155 160
156 161 class magic_arguments(ArgDecorator):
157 162 """ Mark the magic as having argparse arguments and possibly adjust the
158 163 name.
159 164 """
160 165
161 166 def __init__(self, name=None):
162 167 self.name = name
163 168
164 169 def __call__(self, func):
165 170 if not getattr(func, 'has_arguments', False):
166 171 func.has_arguments = True
167 172 func.decorators = []
168 173 if self.name is not None:
169 174 func.argcmd_name = self.name
170 175 # This should be the first decorator in the list of decorators, thus the
171 176 # last to execute. Build the parser.
172 177 func.parser = construct_parser(func)
173 178 return func
174 179
175 180
176 181 class ArgMethodWrapper(ArgDecorator):
177 182
178 183 """
179 184 Base class to define a wrapper for ArgumentParser method.
180 185
181 186 Child class must define either `_method_name` or `add_to_parser`.
182 187
183 188 """
184 189
185 190 _method_name = None
186 191
187 192 def __init__(self, *args, **kwds):
188 193 self.args = args
189 194 self.kwds = kwds
190 195
191 196 def add_to_parser(self, parser, group):
192 197 """ Add this object's information to the parser.
193 198 """
194 199 if group is not None:
195 200 parser = group
196 201 getattr(parser, self._method_name)(*self.args, **self.kwds)
197 202 return None
198 203
199 204
200 205 class argument(ArgMethodWrapper):
201 206 """ Store arguments and keywords to pass to add_argument().
202 207
203 208 Instances also serve to decorate command methods.
204 209 """
205 210 _method_name = 'add_argument'
206 211
207 212
208 213 class defaults(ArgMethodWrapper):
209 214 """ Store arguments and keywords to pass to set_defaults().
210 215
211 216 Instances also serve to decorate command methods.
212 217 """
213 218 _method_name = 'set_defaults'
214 219
215 220
216 221 class argument_group(ArgMethodWrapper):
217 222 """ Store arguments and keywords to pass to add_argument_group().
218 223
219 224 Instances also serve to decorate command methods.
220 225 """
221 226
222 227 def add_to_parser(self, parser, group):
223 228 """ Add this object's information to the parser.
224 229 """
225 230 return parser.add_argument_group(*self.args, **self.kwds)
226 231
227 232
228 233 class kwds(ArgDecorator):
229 234 """ Provide other keywords to the sub-parser constructor.
230 235 """
231 236 def __init__(self, **kwds):
232 237 self.kwds = kwds
233 238
234 239 def __call__(self, func):
235 240 func = super(kwds, self).__call__(func)
236 241 func.argcmd_kwds = self.kwds
237 242 return func
238 243
239 244
240 245 __all__ = ['magic_arguments', 'argument', 'argument_group', 'kwds',
241 246 'parse_argstring']
@@ -1,1242 +1,1247 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 ultratb.py -- Spice up your tracebacks!
4 4
5 5 * ColorTB
6 6 I've always found it a bit hard to visually parse tracebacks in Python. The
7 7 ColorTB class is a solution to that problem. It colors the different parts of a
8 8 traceback in a manner similar to what you would expect from a syntax-highlighting
9 9 text editor.
10 10
11 11 Installation instructions for ColorTB:
12 12 import sys,ultratb
13 13 sys.excepthook = ultratb.ColorTB()
14 14
15 15 * VerboseTB
16 16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
17 17 of useful info when a traceback occurs. Ping originally had it spit out HTML
18 18 and intended it for CGI programmers, but why should they have all the fun? I
19 19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
20 20 but kind of neat, and maybe useful for long-running programs that you believe
21 21 are bug-free. If a crash *does* occur in that type of program you want details.
22 22 Give it a shot--you'll love it or you'll hate it.
23 23
24 24 Note:
25 25
26 26 The Verbose mode prints the variables currently visible where the exception
27 27 happened (shortening their strings if too long). This can potentially be
28 28 very slow, if you happen to have a huge data structure whose string
29 29 representation is complex to compute. Your computer may appear to freeze for
30 30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
31 31 with Ctrl-C (maybe hitting it more than once).
32 32
33 33 If you encounter this kind of situation often, you may want to use the
34 34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
35 35 variables (but otherwise includes the information and context given by
36 36 Verbose).
37 37
38 38
39 39 Installation instructions for ColorTB:
40 40 import sys,ultratb
41 41 sys.excepthook = ultratb.VerboseTB()
42 42
43 43 Note: Much of the code in this module was lifted verbatim from the standard
44 44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
45 45
46 46 * Color schemes
47 47 The colors are defined in the class TBTools through the use of the
48 48 ColorSchemeTable class. Currently the following exist:
49 49
50 50 - NoColor: allows all of this module to be used in any terminal (the color
51 51 escapes are just dummy blank strings).
52 52
53 53 - Linux: is meant to look good in a terminal like the Linux console (black
54 54 or very dark background).
55 55
56 56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
57 57 in light background terminals.
58 58
59 59 You can implement other color schemes easily, the syntax is fairly
60 60 self-explanatory. Please send back new schemes you develop to the author for
61 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 70 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
66 71 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
67 72 #
68 73 # Distributed under the terms of the BSD License. The full license is in
69 74 # the file COPYING, distributed as part of this software.
70 75 #*****************************************************************************
71 76
72 77 from __future__ import unicode_literals
73 78
74 79 import inspect
75 80 import keyword
76 81 import linecache
77 82 import os
78 83 import pydoc
79 84 import re
80 85 import sys
81 86 import time
82 87 import tokenize
83 88 import traceback
84 89 import types
85 90
86 91 try: # Python 2
87 92 generate_tokens = tokenize.generate_tokens
88 93 except AttributeError: # Python 3
89 94 generate_tokens = tokenize.tokenize
90 95
91 96 # For purposes of monkeypatching inspect to fix a bug in it.
92 97 from inspect import getsourcefile, getfile, getmodule,\
93 98 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
94 99
95 100 # IPython's own modules
96 101 # Modified pdb which doesn't damage IPython's readline handling
97 102 from IPython.core import debugger, ipapi
98 103 from IPython.core.display_trap import DisplayTrap
99 104 from IPython.core.excolors import exception_colors
100 105 from IPython.utils import PyColorize
101 106 from IPython.utils import io
102 107 from IPython.utils import path as util_path
103 108 from IPython.utils import py3compat
104 109 from IPython.utils import pyfile
105 110 from IPython.utils import ulinecache
106 111 from IPython.utils.data import uniq_stable
107 112 from IPython.utils.openpy import read_py_file
108 113 from IPython.utils.warn import info, error
109 114
110 115 # Globals
111 116 # amount of space to put line numbers before verbose tracebacks
112 117 INDENT_SIZE = 8
113 118
114 119 # Default color scheme. This is used, for example, by the traceback
115 120 # formatter. When running in an actual IPython instance, the user's rc.colors
116 121 # value is used, but havinga module global makes this functionality available
117 122 # to users of ultratb who are NOT running inside ipython.
118 123 DEFAULT_SCHEME = 'NoColor'
119 124
120 125 #---------------------------------------------------------------------------
121 126 # Code begins
122 127
123 128 # Utility functions
124 129 def inspect_error():
125 130 """Print a message about internal inspect errors.
126 131
127 132 These are unfortunately quite common."""
128 133
129 134 error('Internal Python error in the inspect module.\n'
130 135 'Below is the traceback from this internal error.\n')
131 136
132 137 # This function is a monkeypatch we apply to the Python inspect module. We have
133 138 # now found when it's needed (see discussion on issue gh-1456), and we have a
134 139 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
135 140 # the monkeypatch is not applied. TK, Aug 2012.
136 141 def findsource(object):
137 142 """Return the entire source file and starting line number for an object.
138 143
139 144 The argument may be a module, class, method, function, traceback, frame,
140 145 or code object. The source code is returned as a list of all the lines
141 146 in the file and the line number indexes a line in that list. An IOError
142 147 is raised if the source code cannot be retrieved.
143 148
144 149 FIXED version with which we monkeypatch the stdlib to work around a bug."""
145 150
146 151 file = getsourcefile(object) or getfile(object)
147 152 # If the object is a frame, then trying to get the globals dict from its
148 153 # module won't work. Instead, the frame object itself has the globals
149 154 # dictionary.
150 155 globals_dict = None
151 156 if inspect.isframe(object):
152 157 # XXX: can this ever be false?
153 158 globals_dict = object.f_globals
154 159 else:
155 160 module = getmodule(object, file)
156 161 if module:
157 162 globals_dict = module.__dict__
158 163 lines = linecache.getlines(file, globals_dict)
159 164 if not lines:
160 165 raise IOError('could not get source code')
161 166
162 167 if ismodule(object):
163 168 return lines, 0
164 169
165 170 if isclass(object):
166 171 name = object.__name__
167 172 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
168 173 # make some effort to find the best matching class definition:
169 174 # use the one with the least indentation, which is the one
170 175 # that's most probably not inside a function definition.
171 176 candidates = []
172 177 for i in range(len(lines)):
173 178 match = pat.match(lines[i])
174 179 if match:
175 180 # if it's at toplevel, it's already the best one
176 181 if lines[i][0] == 'c':
177 182 return lines, i
178 183 # else add whitespace to candidate list
179 184 candidates.append((match.group(1), i))
180 185 if candidates:
181 186 # this will sort by whitespace, and by line number,
182 187 # less whitespace first
183 188 candidates.sort()
184 189 return lines, candidates[0][1]
185 190 else:
186 191 raise IOError('could not find class definition')
187 192
188 193 if ismethod(object):
189 194 object = object.im_func
190 195 if isfunction(object):
191 196 object = object.func_code
192 197 if istraceback(object):
193 198 object = object.tb_frame
194 199 if isframe(object):
195 200 object = object.f_code
196 201 if iscode(object):
197 202 if not hasattr(object, 'co_firstlineno'):
198 203 raise IOError('could not find function definition')
199 204 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
200 205 pmatch = pat.match
201 206 # fperez - fix: sometimes, co_firstlineno can give a number larger than
202 207 # the length of lines, which causes an error. Safeguard against that.
203 208 lnum = min(object.co_firstlineno,len(lines))-1
204 209 while lnum > 0:
205 210 if pmatch(lines[lnum]): break
206 211 lnum -= 1
207 212
208 213 return lines, lnum
209 214 raise IOError('could not find code object')
210 215
211 216 # Monkeypatch inspect to apply our bugfix. This code only works with Python >= 2.5
212 217 inspect.findsource = findsource
213 218
214 219 def fix_frame_records_filenames(records):
215 220 """Try to fix the filenames in each record from inspect.getinnerframes().
216 221
217 222 Particularly, modules loaded from within zip files have useless filenames
218 223 attached to their code object, and inspect.getinnerframes() just uses it.
219 224 """
220 225 fixed_records = []
221 226 for frame, filename, line_no, func_name, lines, index in records:
222 227 # Look inside the frame's globals dictionary for __file__, which should
223 228 # be better.
224 229 better_fn = frame.f_globals.get('__file__', None)
225 230 if isinstance(better_fn, str):
226 231 # Check the type just in case someone did something weird with
227 232 # __file__. It might also be None if the error occurred during
228 233 # import.
229 234 filename = better_fn
230 235 fixed_records.append((frame, filename, line_no, func_name, lines, index))
231 236 return fixed_records
232 237
233 238
234 239 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
235 240 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
236 241
237 242 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
238 243
239 244 # If the error is at the console, don't build any context, since it would
240 245 # otherwise produce 5 blank lines printed out (there is no file at the
241 246 # console)
242 247 rec_check = records[tb_offset:]
243 248 try:
244 249 rname = rec_check[0][1]
245 250 if rname == '<ipython console>' or rname.endswith('<string>'):
246 251 return rec_check
247 252 except IndexError:
248 253 pass
249 254
250 255 aux = traceback.extract_tb(etb)
251 256 assert len(records) == len(aux)
252 257 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
253 258 maybeStart = lnum-1 - context//2
254 259 start = max(maybeStart, 0)
255 260 end = start + context
256 261 lines = ulinecache.getlines(file)[start:end]
257 262 buf = list(records[i])
258 263 buf[LNUM_POS] = lnum
259 264 buf[INDEX_POS] = lnum - 1 - start
260 265 buf[LINES_POS] = lines
261 266 records[i] = tuple(buf)
262 267 return records[tb_offset:]
263 268
264 269 # Helper function -- largely belongs to VerboseTB, but we need the same
265 270 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
266 271 # can be recognized properly by ipython.el's py-traceback-line-re
267 272 # (SyntaxErrors have to be treated specially because they have no traceback)
268 273
269 274 _parser = PyColorize.Parser()
270 275
271 276 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
272 277 numbers_width = INDENT_SIZE - 1
273 278 res = []
274 279 i = lnum - index
275 280
276 281 # This lets us get fully syntax-highlighted tracebacks.
277 282 if scheme is None:
278 283 ipinst = ipapi.get()
279 284 if ipinst is not None:
280 285 scheme = ipinst.colors
281 286 else:
282 287 scheme = DEFAULT_SCHEME
283 288
284 289 _line_format = _parser.format2
285 290
286 291 for line in lines:
287 292 line = py3compat.cast_unicode(line)
288 293
289 294 new_line, err = _line_format(line, 'str', scheme)
290 295 if not err: line = new_line
291 296
292 297 if i == lnum:
293 298 # This is the line with the error
294 299 pad = numbers_width - len(str(i))
295 300 if pad >= 3:
296 301 marker = '-'*(pad-3) + '-> '
297 302 elif pad == 2:
298 303 marker = '> '
299 304 elif pad == 1:
300 305 marker = '>'
301 306 else:
302 307 marker = ''
303 308 num = marker + str(i)
304 309 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
305 310 Colors.line, line, Colors.Normal)
306 311 else:
307 312 num = '%*s' % (numbers_width,i)
308 313 line = '%s%s%s %s' %(Colors.lineno, num,
309 314 Colors.Normal, line)
310 315
311 316 res.append(line)
312 317 if lvals and i == lnum:
313 318 res.append(lvals + '\n')
314 319 i = i + 1
315 320 return res
316 321
317 322
318 323 #---------------------------------------------------------------------------
319 324 # Module classes
320 325 class TBTools(object):
321 326 """Basic tools used by all traceback printer classes."""
322 327
323 328 # Number of frames to skip when reporting tracebacks
324 329 tb_offset = 0
325 330
326 331 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
327 332 # Whether to call the interactive pdb debugger after printing
328 333 # tracebacks or not
329 334 self.call_pdb = call_pdb
330 335
331 336 # Output stream to write to. Note that we store the original value in
332 337 # a private attribute and then make the public ostream a property, so
333 338 # that we can delay accessing io.stdout until runtime. The way
334 339 # things are written now, the io.stdout object is dynamically managed
335 340 # so a reference to it should NEVER be stored statically. This
336 341 # property approach confines this detail to a single location, and all
337 342 # subclasses can simply access self.ostream for writing.
338 343 self._ostream = ostream
339 344
340 345 # Create color table
341 346 self.color_scheme_table = exception_colors()
342 347
343 348 self.set_colors(color_scheme)
344 349 self.old_scheme = color_scheme # save initial value for toggles
345 350
346 351 if call_pdb:
347 352 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
348 353 else:
349 354 self.pdb = None
350 355
351 356 def _get_ostream(self):
352 357 """Output stream that exceptions are written to.
353 358
354 359 Valid values are:
355 360
356 361 - None: the default, which means that IPython will dynamically resolve
357 362 to io.stdout. This ensures compatibility with most tools, including
358 363 Windows (where plain stdout doesn't recognize ANSI escapes).
359 364
360 365 - Any object with 'write' and 'flush' attributes.
361 366 """
362 367 return io.stdout if self._ostream is None else self._ostream
363 368
364 369 def _set_ostream(self, val):
365 370 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
366 371 self._ostream = val
367 372
368 373 ostream = property(_get_ostream, _set_ostream)
369 374
370 375 def set_colors(self,*args,**kw):
371 376 """Shorthand access to the color table scheme selector method."""
372 377
373 378 # Set own color table
374 379 self.color_scheme_table.set_active_scheme(*args,**kw)
375 380 # for convenience, set Colors to the active scheme
376 381 self.Colors = self.color_scheme_table.active_colors
377 382 # Also set colors of debugger
378 383 if hasattr(self,'pdb') and self.pdb is not None:
379 384 self.pdb.set_colors(*args,**kw)
380 385
381 386 def color_toggle(self):
382 387 """Toggle between the currently active color scheme and NoColor."""
383 388
384 389 if self.color_scheme_table.active_scheme_name == 'NoColor':
385 390 self.color_scheme_table.set_active_scheme(self.old_scheme)
386 391 self.Colors = self.color_scheme_table.active_colors
387 392 else:
388 393 self.old_scheme = self.color_scheme_table.active_scheme_name
389 394 self.color_scheme_table.set_active_scheme('NoColor')
390 395 self.Colors = self.color_scheme_table.active_colors
391 396
392 397 def stb2text(self, stb):
393 398 """Convert a structured traceback (a list) to a string."""
394 399 return '\n'.join(stb)
395 400
396 401 def text(self, etype, value, tb, tb_offset=None, context=5):
397 402 """Return formatted traceback.
398 403
399 404 Subclasses may override this if they add extra arguments.
400 405 """
401 406 tb_list = self.structured_traceback(etype, value, tb,
402 407 tb_offset, context)
403 408 return self.stb2text(tb_list)
404 409
405 410 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
406 411 context=5, mode=None):
407 412 """Return a list of traceback frames.
408 413
409 414 Must be implemented by each class.
410 415 """
411 416 raise NotImplementedError()
412 417
413 418
414 419 #---------------------------------------------------------------------------
415 420 class ListTB(TBTools):
416 421 """Print traceback information from a traceback list, with optional color.
417 422
418 423 Calling: requires 3 arguments:
419 424 (etype, evalue, elist)
420 425 as would be obtained by:
421 426 etype, evalue, tb = sys.exc_info()
422 427 if tb:
423 428 elist = traceback.extract_tb(tb)
424 429 else:
425 430 elist = None
426 431
427 432 It can thus be used by programs which need to process the traceback before
428 433 printing (such as console replacements based on the code module from the
429 434 standard library).
430 435
431 436 Because they are meant to be called without a full traceback (only a
432 437 list), instances of this class can't call the interactive pdb debugger."""
433 438
434 439 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
435 440 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
436 441 ostream=ostream)
437 442
438 443 def __call__(self, etype, value, elist):
439 444 self.ostream.flush()
440 445 self.ostream.write(self.text(etype, value, elist))
441 446 self.ostream.write('\n')
442 447
443 448 def structured_traceback(self, etype, value, elist, tb_offset=None,
444 449 context=5):
445 450 """Return a color formatted string with the traceback info.
446 451
447 452 Parameters
448 453 ----------
449 454 etype : exception type
450 455 Type of the exception raised.
451 456
452 457 value : object
453 458 Data stored in the exception
454 459
455 460 elist : list
456 461 List of frames, see class docstring for details.
457 462
458 463 tb_offset : int, optional
459 464 Number of frames in the traceback to skip. If not given, the
460 465 instance value is used (set in constructor).
461 466
462 467 context : int, optional
463 468 Number of lines of context information to print.
464 469
465 470 Returns
466 471 -------
467 472 String with formatted exception.
468 473 """
469 474 tb_offset = self.tb_offset if tb_offset is None else tb_offset
470 475 Colors = self.Colors
471 476 out_list = []
472 477 if elist:
473 478
474 479 if tb_offset and len(elist) > tb_offset:
475 480 elist = elist[tb_offset:]
476 481
477 482 out_list.append('Traceback %s(most recent call last)%s:' %
478 483 (Colors.normalEm, Colors.Normal) + '\n')
479 484 out_list.extend(self._format_list(elist))
480 485 # The exception info should be a single entry in the list.
481 486 lines = ''.join(self._format_exception_only(etype, value))
482 487 out_list.append(lines)
483 488
484 489 # Note: this code originally read:
485 490
486 491 ## for line in lines[:-1]:
487 492 ## out_list.append(" "+line)
488 493 ## out_list.append(lines[-1])
489 494
490 495 # This means it was indenting everything but the last line by a little
491 496 # bit. I've disabled this for now, but if we see ugliness somewhre we
492 497 # can restore it.
493 498
494 499 return out_list
495 500
496 501 def _format_list(self, extracted_list):
497 502 """Format a list of traceback entry tuples for printing.
498 503
499 504 Given a list of tuples as returned by extract_tb() or
500 505 extract_stack(), return a list of strings ready for printing.
501 506 Each string in the resulting list corresponds to the item with the
502 507 same index in the argument list. Each string ends in a newline;
503 508 the strings may contain internal newlines as well, for those items
504 509 whose source text line is not None.
505 510
506 511 Lifted almost verbatim from traceback.py
507 512 """
508 513
509 514 Colors = self.Colors
510 515 list = []
511 516 for filename, lineno, name, line in extracted_list[:-1]:
512 517 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
513 518 (Colors.filename, filename, Colors.Normal,
514 519 Colors.lineno, lineno, Colors.Normal,
515 520 Colors.name, name, Colors.Normal)
516 521 if line:
517 522 item += ' %s\n' % line.strip()
518 523 list.append(item)
519 524 # Emphasize the last entry
520 525 filename, lineno, name, line = extracted_list[-1]
521 526 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
522 527 (Colors.normalEm,
523 528 Colors.filenameEm, filename, Colors.normalEm,
524 529 Colors.linenoEm, lineno, Colors.normalEm,
525 530 Colors.nameEm, name, Colors.normalEm,
526 531 Colors.Normal)
527 532 if line:
528 533 item += '%s %s%s\n' % (Colors.line, line.strip(),
529 534 Colors.Normal)
530 535 list.append(item)
531 536 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
532 537 return list
533 538
534 539 def _format_exception_only(self, etype, value):
535 540 """Format the exception part of a traceback.
536 541
537 542 The arguments are the exception type and value such as given by
538 543 sys.exc_info()[:2]. The return value is a list of strings, each ending
539 544 in a newline. Normally, the list contains a single string; however,
540 545 for SyntaxError exceptions, it contains several lines that (when
541 546 printed) display detailed information about where the syntax error
542 547 occurred. The message indicating which exception occurred is the
543 548 always last string in the list.
544 549
545 550 Also lifted nearly verbatim from traceback.py
546 551 """
547 552 have_filedata = False
548 553 Colors = self.Colors
549 554 list = []
550 555 stype = Colors.excName + etype.__name__ + Colors.Normal
551 556 if value is None:
552 557 # Not sure if this can still happen in Python 2.6 and above
553 558 list.append( py3compat.cast_unicode(stype) + '\n')
554 559 else:
555 560 if issubclass(etype, SyntaxError):
556 561 have_filedata = True
557 562 #print 'filename is',filename # dbg
558 563 if not value.filename: value.filename = "<string>"
559 564 if value.lineno:
560 565 lineno = value.lineno
561 566 textline = ulinecache.getline(value.filename, value.lineno)
562 567 else:
563 568 lineno = 'unknown'
564 569 textline = ''
565 570 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
566 571 (Colors.normalEm,
567 572 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
568 573 Colors.linenoEm, lineno, Colors.Normal ))
569 574 if textline == '':
570 575 textline = py3compat.cast_unicode(value.text, "utf-8")
571 576
572 577 if textline is not None:
573 578 i = 0
574 579 while i < len(textline) and textline[i].isspace():
575 580 i += 1
576 581 list.append('%s %s%s\n' % (Colors.line,
577 582 textline.strip(),
578 583 Colors.Normal))
579 584 if value.offset is not None:
580 585 s = ' '
581 586 for c in textline[i:value.offset-1]:
582 587 if c.isspace():
583 588 s += c
584 589 else:
585 590 s += ' '
586 591 list.append('%s%s^%s\n' % (Colors.caret, s,
587 592 Colors.Normal) )
588 593
589 594 try:
590 595 s = value.msg
591 596 except Exception:
592 597 s = self._some_str(value)
593 598 if s:
594 599 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
595 600 Colors.Normal, s))
596 601 else:
597 602 list.append('%s\n' % str(stype))
598 603
599 604 # sync with user hooks
600 605 if have_filedata:
601 606 ipinst = ipapi.get()
602 607 if ipinst is not None:
603 608 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
604 609
605 610 return list
606 611
607 612 def get_exception_only(self, etype, value):
608 613 """Only print the exception type and message, without a traceback.
609 614
610 615 Parameters
611 616 ----------
612 617 etype : exception type
613 618 value : exception value
614 619 """
615 620 return ListTB.structured_traceback(self, etype, value, [])
616 621
617 622
618 623 def show_exception_only(self, etype, evalue):
619 624 """Only print the exception type and message, without a traceback.
620 625
621 626 Parameters
622 627 ----------
623 628 etype : exception type
624 629 value : exception value
625 630 """
626 631 # This method needs to use __call__ from *this* class, not the one from
627 632 # a subclass whose signature or behavior may be different
628 633 ostream = self.ostream
629 634 ostream.flush()
630 635 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
631 636 ostream.flush()
632 637
633 638 def _some_str(self, value):
634 639 # Lifted from traceback.py
635 640 try:
636 641 return str(value)
637 642 except:
638 643 return '<unprintable %s object>' % type(value).__name__
639 644
640 645 #----------------------------------------------------------------------------
641 646 class VerboseTB(TBTools):
642 647 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
643 648 of HTML. Requires inspect and pydoc. Crazy, man.
644 649
645 650 Modified version which optionally strips the topmost entries from the
646 651 traceback, to be used with alternate interpreters (because their own code
647 652 would appear in the traceback)."""
648 653
649 654 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
650 655 tb_offset=0, long_header=False, include_vars=True,
651 656 check_cache=None):
652 657 """Specify traceback offset, headers and color scheme.
653 658
654 659 Define how many frames to drop from the tracebacks. Calling it with
655 660 tb_offset=1 allows use of this handler in interpreters which will have
656 661 their own code at the top of the traceback (VerboseTB will first
657 662 remove that frame before printing the traceback info)."""
658 663 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
659 664 ostream=ostream)
660 665 self.tb_offset = tb_offset
661 666 self.long_header = long_header
662 667 self.include_vars = include_vars
663 668 # By default we use linecache.checkcache, but the user can provide a
664 669 # different check_cache implementation. This is used by the IPython
665 670 # kernel to provide tracebacks for interactive code that is cached,
666 671 # by a compiler instance that flushes the linecache but preserves its
667 672 # own code cache.
668 673 if check_cache is None:
669 674 check_cache = linecache.checkcache
670 675 self.check_cache = check_cache
671 676
672 677 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
673 678 context=5):
674 679 """Return a nice text document describing the traceback."""
675 680
676 681 tb_offset = self.tb_offset if tb_offset is None else tb_offset
677 682
678 683 # some locals
679 684 try:
680 685 etype = etype.__name__
681 686 except AttributeError:
682 687 pass
683 688 Colors = self.Colors # just a shorthand + quicker name lookup
684 689 ColorsNormal = Colors.Normal # used a lot
685 690 col_scheme = self.color_scheme_table.active_scheme_name
686 691 indent = ' '*INDENT_SIZE
687 692 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
688 693 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
689 694 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
690 695
691 696 # some internal-use functions
692 697 def text_repr(value):
693 698 """Hopefully pretty robust repr equivalent."""
694 699 # this is pretty horrible but should always return *something*
695 700 try:
696 701 return pydoc.text.repr(value)
697 702 except KeyboardInterrupt:
698 703 raise
699 704 except:
700 705 try:
701 706 return repr(value)
702 707 except KeyboardInterrupt:
703 708 raise
704 709 except:
705 710 try:
706 711 # all still in an except block so we catch
707 712 # getattr raising
708 713 name = getattr(value, '__name__', None)
709 714 if name:
710 715 # ick, recursion
711 716 return text_repr(name)
712 717 klass = getattr(value, '__class__', None)
713 718 if klass:
714 719 return '%s instance' % text_repr(klass)
715 720 except KeyboardInterrupt:
716 721 raise
717 722 except:
718 723 return 'UNRECOVERABLE REPR FAILURE'
719 724 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
720 725 def nullrepr(value, repr=text_repr): return ''
721 726
722 727 # meat of the code begins
723 728 try:
724 729 etype = etype.__name__
725 730 except AttributeError:
726 731 pass
727 732
728 733 if self.long_header:
729 734 # Header with the exception type, python version, and date
730 735 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
731 736 date = time.ctime(time.time())
732 737
733 738 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
734 739 exc, ' '*(75-len(str(etype))-len(pyver)),
735 740 pyver, date.rjust(75) )
736 741 head += "\nA problem occured executing Python code. Here is the sequence of function"\
737 742 "\ncalls leading up to the error, with the most recent (innermost) call last."
738 743 else:
739 744 # Simplified header
740 745 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
741 746 'Traceback (most recent call last)'.\
742 747 rjust(75 - len(str(etype)) ) )
743 748 frames = []
744 749 # Flush cache before calling inspect. This helps alleviate some of the
745 750 # problems with python 2.3's inspect.py.
746 751 ##self.check_cache()
747 752 # Drop topmost frames if requested
748 753 try:
749 754 # Try the default getinnerframes and Alex's: Alex's fixes some
750 755 # problems, but it generates empty tracebacks for console errors
751 756 # (5 blanks lines) where none should be returned.
752 757 #records = inspect.getinnerframes(etb, context)[tb_offset:]
753 758 #print 'python records:', records # dbg
754 759 records = _fixed_getinnerframes(etb, context, tb_offset)
755 760 #print 'alex records:', records # dbg
756 761 except:
757 762
758 763 # FIXME: I've been getting many crash reports from python 2.3
759 764 # users, traceable to inspect.py. If I can find a small test-case
760 765 # to reproduce this, I should either write a better workaround or
761 766 # file a bug report against inspect (if that's the real problem).
762 767 # So far, I haven't been able to find an isolated example to
763 768 # reproduce the problem.
764 769 inspect_error()
765 770 traceback.print_exc(file=self.ostream)
766 771 info('\nUnfortunately, your original traceback can not be constructed.\n')
767 772 return ''
768 773
769 774 # build some color string templates outside these nested loops
770 775 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
771 776 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
772 777 ColorsNormal)
773 778 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
774 779 (Colors.vName, Colors.valEm, ColorsNormal)
775 780 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
776 781 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
777 782 Colors.vName, ColorsNormal)
778 783 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
779 784 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
780 785 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
781 786 ColorsNormal)
782 787
783 788 # now, loop over all records printing context and info
784 789 abspath = os.path.abspath
785 790 for frame, file, lnum, func, lines, index in records:
786 791 #print '*** record:',file,lnum,func,lines,index # dbg
787 792 if not file:
788 793 file = '?'
789 794 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
790 795 # Guess that filenames like <string> aren't real filenames, so
791 796 # don't call abspath on them.
792 797 try:
793 798 file = abspath(file)
794 799 except OSError:
795 800 # Not sure if this can still happen: abspath now works with
796 801 # file names like <string>
797 802 pass
798 803 file = py3compat.cast_unicode(file, util_path.fs_encoding)
799 804 link = tpl_link % file
800 805 args, varargs, varkw, locals = inspect.getargvalues(frame)
801 806
802 807 if func == '?':
803 808 call = ''
804 809 else:
805 810 # Decide whether to include variable details or not
806 811 var_repr = self.include_vars and eqrepr or nullrepr
807 812 try:
808 813 call = tpl_call % (func,inspect.formatargvalues(args,
809 814 varargs, varkw,
810 815 locals,formatvalue=var_repr))
811 816 except KeyError:
812 817 # This happens in situations like errors inside generator
813 818 # expressions, where local variables are listed in the
814 819 # line, but can't be extracted from the frame. I'm not
815 820 # 100% sure this isn't actually a bug in inspect itself,
816 821 # but since there's no info for us to compute with, the
817 822 # best we can do is report the failure and move on. Here
818 823 # we must *not* call any traceback construction again,
819 824 # because that would mess up use of %debug later on. So we
820 825 # simply report the failure and move on. The only
821 826 # limitation will be that this frame won't have locals
822 827 # listed in the call signature. Quite subtle problem...
823 828 # I can't think of a good way to validate this in a unit
824 829 # test, but running a script consisting of:
825 830 # dict( (k,v.strip()) for (k,v) in range(10) )
826 831 # will illustrate the error, if this exception catch is
827 832 # disabled.
828 833 call = tpl_call_fail % func
829 834
830 835 # Don't attempt to tokenize binary files.
831 836 if file.endswith(('.so', '.pyd', '.dll')):
832 837 frames.append('%s %s\n' % (link,call))
833 838 continue
834 839 elif file.endswith(('.pyc','.pyo')):
835 840 # Look up the corresponding source file.
836 841 file = pyfile.source_from_cache(file)
837 842
838 843 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
839 844 line = getline(file, lnum[0])
840 845 lnum[0] += 1
841 846 return line
842 847
843 848 # Build the list of names on this line of code where the exception
844 849 # occurred.
845 850 try:
846 851 names = []
847 852 name_cont = False
848 853
849 854 for token_type, token, start, end, line in generate_tokens(linereader):
850 855 # build composite names
851 856 if token_type == tokenize.NAME and token not in keyword.kwlist:
852 857 if name_cont:
853 858 # Continuation of a dotted name
854 859 try:
855 860 names[-1].append(token)
856 861 except IndexError:
857 862 names.append([token])
858 863 name_cont = False
859 864 else:
860 865 # Regular new names. We append everything, the caller
861 866 # will be responsible for pruning the list later. It's
862 867 # very tricky to try to prune as we go, b/c composite
863 868 # names can fool us. The pruning at the end is easy
864 869 # to do (or the caller can print a list with repeated
865 870 # names if so desired.
866 871 names.append([token])
867 872 elif token == '.':
868 873 name_cont = True
869 874 elif token_type == tokenize.NEWLINE:
870 875 break
871 876
872 877 except (IndexError, UnicodeDecodeError):
873 878 # signals exit of tokenizer
874 879 pass
875 880 except tokenize.TokenError as msg:
876 881 _m = ("An unexpected error occurred while tokenizing input\n"
877 882 "The following traceback may be corrupted or invalid\n"
878 883 "The error message is: %s\n" % msg)
879 884 error(_m)
880 885
881 886 # Join composite names (e.g. "dict.fromkeys")
882 887 names = ['.'.join(n) for n in names]
883 888 # prune names list of duplicates, but keep the right order
884 889 unique_names = uniq_stable(names)
885 890
886 891 # Start loop over vars
887 892 lvals = []
888 893 if self.include_vars:
889 894 for name_full in unique_names:
890 895 name_base = name_full.split('.',1)[0]
891 896 if name_base in frame.f_code.co_varnames:
892 897 if name_base in locals:
893 898 try:
894 899 value = repr(eval(name_full,locals))
895 900 except:
896 901 value = undefined
897 902 else:
898 903 value = undefined
899 904 name = tpl_local_var % name_full
900 905 else:
901 906 if name_base in frame.f_globals:
902 907 try:
903 908 value = repr(eval(name_full,frame.f_globals))
904 909 except:
905 910 value = undefined
906 911 else:
907 912 value = undefined
908 913 name = tpl_global_var % name_full
909 914 lvals.append(tpl_name_val % (name,value))
910 915 if lvals:
911 916 lvals = '%s%s' % (indent,em_normal.join(lvals))
912 917 else:
913 918 lvals = ''
914 919
915 920 level = '%s %s\n' % (link,call)
916 921
917 922 if index is None:
918 923 frames.append(level)
919 924 else:
920 925 frames.append('%s%s' % (level,''.join(
921 926 _format_traceback_lines(lnum,index,lines,Colors,lvals,
922 927 col_scheme))))
923 928
924 929 # Get (safely) a string form of the exception info
925 930 try:
926 931 etype_str,evalue_str = map(str,(etype,evalue))
927 932 except:
928 933 # User exception is improperly defined.
929 934 etype,evalue = str,sys.exc_info()[:2]
930 935 etype_str,evalue_str = map(str,(etype,evalue))
931 936 # ... and format it
932 937 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
933 938 ColorsNormal, py3compat.cast_unicode(evalue_str))]
934 939 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
935 940 try:
936 941 names = [w for w in dir(evalue) if isinstance(w, basestring)]
937 942 except:
938 943 # Every now and then, an object with funny inernals blows up
939 944 # when dir() is called on it. We do the best we can to report
940 945 # the problem and continue
941 946 _m = '%sException reporting error (object with broken dir())%s:'
942 947 exception.append(_m % (Colors.excName,ColorsNormal))
943 948 etype_str,evalue_str = map(str,sys.exc_info()[:2])
944 949 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
945 950 ColorsNormal, py3compat.cast_unicode(evalue_str)))
946 951 names = []
947 952 for name in names:
948 953 value = text_repr(getattr(evalue, name))
949 954 exception.append('\n%s%s = %s' % (indent, name, value))
950 955
951 956 # vds: >>
952 957 if records:
953 958 filepath, lnum = records[-1][1:3]
954 959 #print "file:", str(file), "linenb", str(lnum) # dbg
955 960 filepath = os.path.abspath(filepath)
956 961 ipinst = ipapi.get()
957 962 if ipinst is not None:
958 963 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
959 964 # vds: <<
960 965
961 966 # return all our info assembled as a single string
962 967 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
963 968 return [head] + frames + [''.join(exception[0])]
964 969
965 970 def debugger(self,force=False):
966 971 """Call up the pdb debugger if desired, always clean up the tb
967 972 reference.
968 973
969 974 Keywords:
970 975
971 976 - force(False): by default, this routine checks the instance call_pdb
972 977 flag and does not actually invoke the debugger if the flag is false.
973 978 The 'force' option forces the debugger to activate even if the flag
974 979 is false.
975 980
976 981 If the call_pdb flag is set, the pdb interactive debugger is
977 982 invoked. In all cases, the self.tb reference to the current traceback
978 983 is deleted to prevent lingering references which hamper memory
979 984 management.
980 985
981 986 Note that each call to pdb() does an 'import readline', so if your app
982 987 requires a special setup for the readline completers, you'll have to
983 988 fix that by hand after invoking the exception handler."""
984 989
985 990 if force or self.call_pdb:
986 991 if self.pdb is None:
987 992 self.pdb = debugger.Pdb(
988 993 self.color_scheme_table.active_scheme_name)
989 994 # the system displayhook may have changed, restore the original
990 995 # for pdb
991 996 display_trap = DisplayTrap(hook=sys.__displayhook__)
992 997 with display_trap:
993 998 self.pdb.reset()
994 999 # Find the right frame so we don't pop up inside ipython itself
995 1000 if hasattr(self,'tb') and self.tb is not None:
996 1001 etb = self.tb
997 1002 else:
998 1003 etb = self.tb = sys.last_traceback
999 1004 while self.tb is not None and self.tb.tb_next is not None:
1000 1005 self.tb = self.tb.tb_next
1001 1006 if etb and etb.tb_next:
1002 1007 etb = etb.tb_next
1003 1008 self.pdb.botframe = etb.tb_frame
1004 1009 self.pdb.interaction(self.tb.tb_frame, self.tb)
1005 1010
1006 1011 if hasattr(self,'tb'):
1007 1012 del self.tb
1008 1013
1009 1014 def handler(self, info=None):
1010 1015 (etype, evalue, etb) = info or sys.exc_info()
1011 1016 self.tb = etb
1012 1017 ostream = self.ostream
1013 1018 ostream.flush()
1014 1019 ostream.write(self.text(etype, evalue, etb))
1015 1020 ostream.write('\n')
1016 1021 ostream.flush()
1017 1022
1018 1023 # Changed so an instance can just be called as VerboseTB_inst() and print
1019 1024 # out the right info on its own.
1020 1025 def __call__(self, etype=None, evalue=None, etb=None):
1021 1026 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1022 1027 if etb is None:
1023 1028 self.handler()
1024 1029 else:
1025 1030 self.handler((etype, evalue, etb))
1026 1031 try:
1027 1032 self.debugger()
1028 1033 except KeyboardInterrupt:
1029 1034 print "\nKeyboardInterrupt"
1030 1035
1031 1036 #----------------------------------------------------------------------------
1032 1037 class FormattedTB(VerboseTB, ListTB):
1033 1038 """Subclass ListTB but allow calling with a traceback.
1034 1039
1035 1040 It can thus be used as a sys.excepthook for Python > 2.1.
1036 1041
1037 1042 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1038 1043
1039 1044 Allows a tb_offset to be specified. This is useful for situations where
1040 1045 one needs to remove a number of topmost frames from the traceback (such as
1041 1046 occurs with python programs that themselves execute other python code,
1042 1047 like Python shells). """
1043 1048
1044 1049 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1045 1050 ostream=None,
1046 1051 tb_offset=0, long_header=False, include_vars=False,
1047 1052 check_cache=None):
1048 1053
1049 1054 # NEVER change the order of this list. Put new modes at the end:
1050 1055 self.valid_modes = ['Plain','Context','Verbose']
1051 1056 self.verbose_modes = self.valid_modes[1:3]
1052 1057
1053 1058 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1054 1059 ostream=ostream, tb_offset=tb_offset,
1055 1060 long_header=long_header, include_vars=include_vars,
1056 1061 check_cache=check_cache)
1057 1062
1058 1063 # Different types of tracebacks are joined with different separators to
1059 1064 # form a single string. They are taken from this dict
1060 1065 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1061 1066 # set_mode also sets the tb_join_char attribute
1062 1067 self.set_mode(mode)
1063 1068
1064 1069 def _extract_tb(self,tb):
1065 1070 if tb:
1066 1071 return traceback.extract_tb(tb)
1067 1072 else:
1068 1073 return None
1069 1074
1070 1075 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1071 1076 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1072 1077 mode = self.mode
1073 1078 if mode in self.verbose_modes:
1074 1079 # Verbose modes need a full traceback
1075 1080 return VerboseTB.structured_traceback(
1076 1081 self, etype, value, tb, tb_offset, context
1077 1082 )
1078 1083 else:
1079 1084 # We must check the source cache because otherwise we can print
1080 1085 # out-of-date source code.
1081 1086 self.check_cache()
1082 1087 # Now we can extract and format the exception
1083 1088 elist = self._extract_tb(tb)
1084 1089 return ListTB.structured_traceback(
1085 1090 self, etype, value, elist, tb_offset, context
1086 1091 )
1087 1092
1088 1093 def stb2text(self, stb):
1089 1094 """Convert a structured traceback (a list) to a string."""
1090 1095 return self.tb_join_char.join(stb)
1091 1096
1092 1097
1093 1098 def set_mode(self,mode=None):
1094 1099 """Switch to the desired mode.
1095 1100
1096 1101 If mode is not specified, cycles through the available modes."""
1097 1102
1098 1103 if not mode:
1099 1104 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1100 1105 len(self.valid_modes)
1101 1106 self.mode = self.valid_modes[new_idx]
1102 1107 elif mode not in self.valid_modes:
1103 1108 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1104 1109 'Valid modes: '+str(self.valid_modes))
1105 1110 else:
1106 1111 self.mode = mode
1107 1112 # include variable details only in 'Verbose' mode
1108 1113 self.include_vars = (self.mode == self.valid_modes[2])
1109 1114 # Set the join character for generating text tracebacks
1110 1115 self.tb_join_char = self._join_chars[self.mode]
1111 1116
1112 1117 # some convenient shorcuts
1113 1118 def plain(self):
1114 1119 self.set_mode(self.valid_modes[0])
1115 1120
1116 1121 def context(self):
1117 1122 self.set_mode(self.valid_modes[1])
1118 1123
1119 1124 def verbose(self):
1120 1125 self.set_mode(self.valid_modes[2])
1121 1126
1122 1127 #----------------------------------------------------------------------------
1123 1128 class AutoFormattedTB(FormattedTB):
1124 1129 """A traceback printer which can be called on the fly.
1125 1130
1126 1131 It will find out about exceptions by itself.
1127 1132
1128 1133 A brief example:
1129 1134
1130 1135 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1131 1136 try:
1132 1137 ...
1133 1138 except:
1134 1139 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1135 1140 """
1136 1141
1137 1142 def __call__(self,etype=None,evalue=None,etb=None,
1138 1143 out=None,tb_offset=None):
1139 1144 """Print out a formatted exception traceback.
1140 1145
1141 1146 Optional arguments:
1142 1147 - out: an open file-like object to direct output to.
1143 1148
1144 1149 - tb_offset: the number of frames to skip over in the stack, on a
1145 1150 per-call basis (this overrides temporarily the instance's tb_offset
1146 1151 given at initialization time. """
1147 1152
1148 1153
1149 1154 if out is None:
1150 1155 out = self.ostream
1151 1156 out.flush()
1152 1157 out.write(self.text(etype, evalue, etb, tb_offset))
1153 1158 out.write('\n')
1154 1159 out.flush()
1155 1160 # FIXME: we should remove the auto pdb behavior from here and leave
1156 1161 # that to the clients.
1157 1162 try:
1158 1163 self.debugger()
1159 1164 except KeyboardInterrupt:
1160 1165 print "\nKeyboardInterrupt"
1161 1166
1162 1167 def structured_traceback(self, etype=None, value=None, tb=None,
1163 1168 tb_offset=None, context=5):
1164 1169 if etype is None:
1165 1170 etype,value,tb = sys.exc_info()
1166 1171 self.tb = tb
1167 1172 return FormattedTB.structured_traceback(
1168 1173 self, etype, value, tb, tb_offset, context)
1169 1174
1170 1175 #---------------------------------------------------------------------------
1171 1176
1172 1177 # A simple class to preserve Nathan's original functionality.
1173 1178 class ColorTB(FormattedTB):
1174 1179 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1175 1180 def __init__(self,color_scheme='Linux',call_pdb=0):
1176 1181 FormattedTB.__init__(self,color_scheme=color_scheme,
1177 1182 call_pdb=call_pdb)
1178 1183
1179 1184
1180 1185 class SyntaxTB(ListTB):
1181 1186 """Extension which holds some state: the last exception value"""
1182 1187
1183 1188 def __init__(self,color_scheme = 'NoColor'):
1184 1189 ListTB.__init__(self,color_scheme)
1185 1190 self.last_syntax_error = None
1186 1191
1187 1192 def __call__(self, etype, value, elist):
1188 1193 self.last_syntax_error = value
1189 1194 ListTB.__call__(self,etype,value,elist)
1190 1195
1191 1196 def clear_err_state(self):
1192 1197 """Return the current error state and clear it"""
1193 1198 e = self.last_syntax_error
1194 1199 self.last_syntax_error = None
1195 1200 return e
1196 1201
1197 1202 def stb2text(self, stb):
1198 1203 """Convert a structured traceback (a list) to a string."""
1199 1204 return ''.join(stb)
1200 1205
1201 1206
1202 1207 #----------------------------------------------------------------------------
1203 1208 # module testing (minimal)
1204 1209 if __name__ == "__main__":
1205 1210 def spam(c, d_e):
1206 1211 (d, e) = d_e
1207 1212 x = c + d
1208 1213 y = c * d
1209 1214 foo(x, y)
1210 1215
1211 1216 def foo(a, b, bar=1):
1212 1217 eggs(a, b + bar)
1213 1218
1214 1219 def eggs(f, g, z=globals()):
1215 1220 h = f + g
1216 1221 i = f - g
1217 1222 return h / i
1218 1223
1219 1224 print ''
1220 1225 print '*** Before ***'
1221 1226 try:
1222 1227 print spam(1, (2, 3))
1223 1228 except:
1224 1229 traceback.print_exc()
1225 1230 print ''
1226 1231
1227 1232 handler = ColorTB()
1228 1233 print '*** ColorTB ***'
1229 1234 try:
1230 1235 print spam(1, (2, 3))
1231 1236 except:
1232 1237 handler(*sys.exc_info())
1233 1238 print ''
1234 1239
1235 1240 handler = VerboseTB()
1236 1241 print '*** VerboseTB ***'
1237 1242 try:
1238 1243 print spam(1, (2, 3))
1239 1244 except:
1240 1245 handler(*sys.exc_info())
1241 1246 print ''
1242 1247
@@ -1,578 +1,583 b''
1 from __future__ import unicode_literals
2
3
4 1 """Module for interactive demos using IPython.
5 2
6 3 This module implements a few classes for running Python scripts interactively
7 4 in IPython for demonstrations. With very simple markup (a few tags in
8 5 comments), you can control points where the script stops executing and returns
9 6 control to IPython.
10 7
11 8
12 9 Provided classes
13 ================
10 ----------------
14 11
15 12 The classes are (see their docstrings for further details):
16 13
17 14 - Demo: pure python demos
18 15
19 16 - IPythonDemo: demos with input to be processed by IPython as if it had been
20 17 typed interactively (so magics work, as well as any other special syntax you
21 18 may have added via input prefilters).
22 19
23 20 - LineDemo: single-line version of the Demo class. These demos are executed
24 21 one line at a time, and require no markup.
25 22
26 23 - IPythonLineDemo: IPython version of the LineDemo class (the demo is
27 24 executed a line at a time, but processed via IPython).
28 25
29 26 - ClearMixin: mixin to make Demo classes with less visual clutter. It
30 27 declares an empty marquee and a pre_cmd that clears the screen before each
31 28 block (see Subclassing below).
32 29
33 30 - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
34 31 classes.
35 32
33 Inheritance diagram:
34
35 .. inheritance-diagram:: IPython.lib.demo
36 :parts: 3
36 37
37 38 Subclassing
38 ===========
39 -----------
39 40
40 41 The classes here all include a few methods meant to make customization by
41 42 subclassing more convenient. Their docstrings below have some more details:
42 43
43 44 - marquee(): generates a marquee to provide visible on-screen markers at each
44 45 block start and end.
45 46
46 47 - pre_cmd(): run right before the execution of each block.
47 48
48 49 - post_cmd(): run right after the execution of each block. If the block
49 50 raises an exception, this is NOT called.
50 51
51 52
52 53 Operation
53 =========
54 ---------
54 55
55 56 The file is run in its own empty namespace (though you can pass it a string of
56 57 arguments as if in a command line environment, and it will see those as
57 58 sys.argv). But at each stop, the global IPython namespace is updated with the
58 59 current internal demo namespace, so you can work interactively with the data
59 60 accumulated so far.
60 61
61 62 By default, each block of code is printed (with syntax highlighting) before
62 63 executing it and you have to confirm execution. This is intended to show the
63 64 code to an audience first so you can discuss it, and only proceed with
64 65 execution once you agree. There are a few tags which allow you to modify this
65 66 behavior.
66 67
67 68 The supported tags are:
68 69
69 70 # <demo> stop
70 71
71 72 Defines block boundaries, the points where IPython stops execution of the
72 73 file and returns to the interactive prompt.
73 74
74 75 You can optionally mark the stop tag with extra dashes before and after the
75 76 word 'stop', to help visually distinguish the blocks in a text editor:
76 77
77 78 # <demo> --- stop ---
78 79
79 80
80 81 # <demo> silent
81 82
82 83 Make a block execute silently (and hence automatically). Typically used in
83 84 cases where you have some boilerplate or initialization code which you need
84 85 executed but do not want to be seen in the demo.
85 86
86 87 # <demo> auto
87 88
88 89 Make a block execute automatically, but still being printed. Useful for
89 90 simple code which does not warrant discussion, since it avoids the extra
90 91 manual confirmation.
91 92
92 93 # <demo> auto_all
93 94
94 95 This tag can _only_ be in the first block, and if given it overrides the
95 96 individual auto tags to make the whole demo fully automatic (no block asks
96 97 for confirmation). It can also be given at creation time (or the attribute
97 98 set later) to override what's in the file.
98 99
99 100 While _any_ python file can be run as a Demo instance, if there are no stop
100 101 tags the whole file will run in a single block (no different that calling
101 102 first %pycat and then %run). The minimal markup to make this useful is to
102 103 place a set of stop tags; the other tags are only there to let you fine-tune
103 104 the execution.
104 105
105 106 This is probably best explained with the simple example file below. You can
106 107 copy this into a file named ex_demo.py, and try running it via:
107 108
108 109 from IPython.demo import Demo
109 110 d = Demo('ex_demo.py')
110 111 d() <--- Call the d object (omit the parens if you have autocall set to 2).
111 112
112 113 Each time you call the demo object, it runs the next block. The demo object
113 114 has a few useful methods for navigation, like again(), edit(), jump(), seek()
114 115 and back(). It can be reset for a new run via reset() or reloaded from disk
115 116 (in case you've edited the source) via reload(). See their docstrings below.
116 117
117 118 Note: To make this simpler to explore, a file called "demo-exercizer.py" has
118 119 been added to the "docs/examples/core" directory. Just cd to this directory in
119 120 an IPython session, and type::
120 121
121 122 %run demo-exercizer.py
122 123
123 124 and then follow the directions.
124 125
125 126 Example
126 =======
127 -------
127 128
128 129 The following is a very simple example of a valid demo file.
129 130
131 ::
132
130 133 #################### EXAMPLE DEMO <ex_demo.py> ###############################
131 134 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
132 135
133 136 print 'Hello, welcome to an interactive IPython demo.'
134 137
135 138 # The mark below defines a block boundary, which is a point where IPython will
136 139 # stop execution and return to the interactive prompt. The dashes are actually
137 140 # optional and used only as a visual aid to clearly separate blocks while
138 141 # editing the demo code.
139 142 # <demo> stop
140 143
141 144 x = 1
142 145 y = 2
143 146
144 147 # <demo> stop
145 148
146 149 # the mark below makes this block as silent
147 150 # <demo> silent
148 151
149 152 print 'This is a silent block, which gets executed but not printed.'
150 153
151 154 # <demo> stop
152 155 # <demo> auto
153 156 print 'This is an automatic block.'
154 157 print 'It is executed without asking for confirmation, but printed.'
155 158 z = x+y
156 159
157 160 print 'z=',x
158 161
159 162 # <demo> stop
160 163 # This is just another normal block.
161 164 print 'z is now:', z
162 165
163 166 print 'bye!'
164 167 ################### END EXAMPLE DEMO <ex_demo.py> ############################
165 168 """
166 169
170 from __future__ import unicode_literals
171
167 172 #*****************************************************************************
168 173 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
169 174 #
170 175 # Distributed under the terms of the BSD License. The full license is in
171 176 # the file COPYING, distributed as part of this software.
172 177 #
173 178 #*****************************************************************************
174 179 from __future__ import print_function
175 180
176 181 import os
177 182 import re
178 183 import shlex
179 184 import sys
180 185
181 186 from IPython.utils.PyColorize import Parser
182 187 from IPython.utils import io
183 188 from IPython.utils.io import file_read, file_readlines
184 189 from IPython.utils.text import marquee
185 190 from IPython.utils import openpy
186 191 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
187 192
188 193 class DemoError(Exception): pass
189 194
190 195 def re_mark(mark):
191 196 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
192 197
193 198 class Demo(object):
194 199
195 200 re_stop = re_mark('-*\s?stop\s?-*')
196 201 re_silent = re_mark('silent')
197 202 re_auto = re_mark('auto')
198 203 re_auto_all = re_mark('auto_all')
199 204
200 205 def __init__(self,src,title='',arg_str='',auto_all=None):
201 206 """Make a new demo object. To run the demo, simply call the object.
202 207
203 208 See the module docstring for full details and an example (you can use
204 209 IPython.Demo? in IPython to see it).
205 210
206 211 Inputs:
207 212
208 213 - src is either a file, or file-like object, or a
209 214 string that can be resolved to a filename.
210 215
211 216 Optional inputs:
212 217
213 218 - title: a string to use as the demo name. Of most use when the demo
214 219 you are making comes from an object that has no filename, or if you
215 220 want an alternate denotation distinct from the filename.
216 221
217 222 - arg_str(''): a string of arguments, internally converted to a list
218 223 just like sys.argv, so the demo script can see a similar
219 224 environment.
220 225
221 226 - auto_all(None): global flag to run all blocks automatically without
222 227 confirmation. This attribute overrides the block-level tags and
223 228 applies to the whole demo. It is an attribute of the object, and
224 229 can be changed at runtime simply by reassigning it to a boolean
225 230 value.
226 231 """
227 232 if hasattr(src, "read"):
228 233 # It seems to be a file or a file-like object
229 234 self.fname = "from a file-like object"
230 235 if title == '':
231 236 self.title = "from a file-like object"
232 237 else:
233 238 self.title = title
234 239 else:
235 240 # Assume it's a string or something that can be converted to one
236 241 self.fname = src
237 242 if title == '':
238 243 (filepath, filename) = os.path.split(src)
239 244 self.title = filename
240 245 else:
241 246 self.title = title
242 247 self.sys_argv = [src] + shlex.split(arg_str)
243 248 self.auto_all = auto_all
244 249 self.src = src
245 250
246 251 # get a few things from ipython. While it's a bit ugly design-wise,
247 252 # it ensures that things like color scheme and the like are always in
248 253 # sync with the ipython mode being used. This class is only meant to
249 254 # be used inside ipython anyways, so it's OK.
250 255 ip = get_ipython() # this is in builtins whenever IPython is running
251 256 self.ip_ns = ip.user_ns
252 257 self.ip_colorize = ip.pycolorize
253 258 self.ip_showtb = ip.showtraceback
254 259 self.ip_run_cell = ip.run_cell
255 260 self.shell = ip
256 261
257 262 # load user data and initialize data structures
258 263 self.reload()
259 264
260 265 def fload(self):
261 266 """Load file object."""
262 267 # read data and parse into blocks
263 268 if hasattr(self, 'fobj') and self.fobj is not None:
264 269 self.fobj.close()
265 270 if hasattr(self.src, "read"):
266 271 # It seems to be a file or a file-like object
267 272 self.fobj = self.src
268 273 else:
269 274 # Assume it's a string or something that can be converted to one
270 275 self.fobj = openpy.open(self.fname)
271 276
272 277 def reload(self):
273 278 """Reload source from disk and initialize state."""
274 279 self.fload()
275 280
276 281 self.src = "".join(openpy.strip_encoding_cookie(self.fobj))
277 282 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
278 283 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
279 284 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
280 285
281 286 # if auto_all is not given (def. None), we read it from the file
282 287 if self.auto_all is None:
283 288 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
284 289 else:
285 290 self.auto_all = bool(self.auto_all)
286 291
287 292 # Clean the sources from all markup so it doesn't get displayed when
288 293 # running the demo
289 294 src_blocks = []
290 295 auto_strip = lambda s: self.re_auto.sub('',s)
291 296 for i,b in enumerate(src_b):
292 297 if self._auto[i]:
293 298 src_blocks.append(auto_strip(b))
294 299 else:
295 300 src_blocks.append(b)
296 301 # remove the auto_all marker
297 302 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
298 303
299 304 self.nblocks = len(src_blocks)
300 305 self.src_blocks = src_blocks
301 306
302 307 # also build syntax-highlighted source
303 308 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
304 309
305 310 # ensure clean namespace and seek offset
306 311 self.reset()
307 312
308 313 def reset(self):
309 314 """Reset the namespace and seek pointer to restart the demo"""
310 315 self.user_ns = {}
311 316 self.finished = False
312 317 self.block_index = 0
313 318
314 319 def _validate_index(self,index):
315 320 if index<0 or index>=self.nblocks:
316 321 raise ValueError('invalid block index %s' % index)
317 322
318 323 def _get_index(self,index):
319 324 """Get the current block index, validating and checking status.
320 325
321 326 Returns None if the demo is finished"""
322 327
323 328 if index is None:
324 329 if self.finished:
325 330 print('Demo finished. Use <demo_name>.reset() if you want to rerun it.', file=io.stdout)
326 331 return None
327 332 index = self.block_index
328 333 else:
329 334 self._validate_index(index)
330 335 return index
331 336
332 337 def seek(self,index):
333 338 """Move the current seek pointer to the given block.
334 339
335 340 You can use negative indices to seek from the end, with identical
336 341 semantics to those of Python lists."""
337 342 if index<0:
338 343 index = self.nblocks + index
339 344 self._validate_index(index)
340 345 self.block_index = index
341 346 self.finished = False
342 347
343 348 def back(self,num=1):
344 349 """Move the seek pointer back num blocks (default is 1)."""
345 350 self.seek(self.block_index-num)
346 351
347 352 def jump(self,num=1):
348 353 """Jump a given number of blocks relative to the current one.
349 354
350 355 The offset can be positive or negative, defaults to 1."""
351 356 self.seek(self.block_index+num)
352 357
353 358 def again(self):
354 359 """Move the seek pointer back one block and re-execute."""
355 360 self.back(1)
356 361 self()
357 362
358 363 def edit(self,index=None):
359 364 """Edit a block.
360 365
361 366 If no number is given, use the last block executed.
362 367
363 368 This edits the in-memory copy of the demo, it does NOT modify the
364 369 original source file. If you want to do that, simply open the file in
365 370 an editor and use reload() when you make changes to the file. This
366 371 method is meant to let you change a block during a demonstration for
367 372 explanatory purposes, without damaging your original script."""
368 373
369 374 index = self._get_index(index)
370 375 if index is None:
371 376 return
372 377 # decrease the index by one (unless we're at the very beginning), so
373 378 # that the default demo.edit() call opens up the sblock we've last run
374 379 if index>0:
375 380 index -= 1
376 381
377 382 filename = self.shell.mktempfile(self.src_blocks[index])
378 383 self.shell.hooks.editor(filename,1)
379 384 new_block = file_read(filename)
380 385 # update the source and colored block
381 386 self.src_blocks[index] = new_block
382 387 self.src_blocks_colored[index] = self.ip_colorize(new_block)
383 388 self.block_index = index
384 389 # call to run with the newly edited index
385 390 self()
386 391
387 392 def show(self,index=None):
388 393 """Show a single block on screen"""
389 394
390 395 index = self._get_index(index)
391 396 if index is None:
392 397 return
393 398
394 399 print(self.marquee('<%s> block # %s (%s remaining)' %
395 400 (self.title,index,self.nblocks-index-1)), file=io.stdout)
396 401 print((self.src_blocks_colored[index]), file=io.stdout)
397 402 sys.stdout.flush()
398 403
399 404 def show_all(self):
400 405 """Show entire demo on screen, block by block"""
401 406
402 407 fname = self.title
403 408 title = self.title
404 409 nblocks = self.nblocks
405 410 silent = self._silent
406 411 marquee = self.marquee
407 412 for index,block in enumerate(self.src_blocks_colored):
408 413 if silent[index]:
409 414 print(marquee('<%s> SILENT block # %s (%s remaining)' %
410 415 (title,index,nblocks-index-1)), file=io.stdout)
411 416 else:
412 417 print(marquee('<%s> block # %s (%s remaining)' %
413 418 (title,index,nblocks-index-1)), file=io.stdout)
414 419 print(block, end=' ', file=io.stdout)
415 420 sys.stdout.flush()
416 421
417 422 def run_cell(self,source):
418 423 """Execute a string with one or more lines of code"""
419 424
420 425 exec source in self.user_ns
421 426
422 427 def __call__(self,index=None):
423 428 """run a block of the demo.
424 429
425 430 If index is given, it should be an integer >=1 and <= nblocks. This
426 431 means that the calling convention is one off from typical Python
427 432 lists. The reason for the inconsistency is that the demo always
428 433 prints 'Block n/N, and N is the total, so it would be very odd to use
429 434 zero-indexing here."""
430 435
431 436 index = self._get_index(index)
432 437 if index is None:
433 438 return
434 439 try:
435 440 marquee = self.marquee
436 441 next_block = self.src_blocks[index]
437 442 self.block_index += 1
438 443 if self._silent[index]:
439 444 print(marquee('Executing silent block # %s (%s remaining)' %
440 445 (index,self.nblocks-index-1)), file=io.stdout)
441 446 else:
442 447 self.pre_cmd()
443 448 self.show(index)
444 449 if self.auto_all or self._auto[index]:
445 450 print(marquee('output:'), file=io.stdout)
446 451 else:
447 452 print(marquee('Press <q> to quit, <Enter> to execute...'), end=' ', file=io.stdout)
448 453 ans = raw_input().strip()
449 454 if ans:
450 455 print(marquee('Block NOT executed'), file=io.stdout)
451 456 return
452 457 try:
453 458 save_argv = sys.argv
454 459 sys.argv = self.sys_argv
455 460 self.run_cell(next_block)
456 461 self.post_cmd()
457 462 finally:
458 463 sys.argv = save_argv
459 464
460 465 except:
461 466 self.ip_showtb(filename=self.fname)
462 467 else:
463 468 self.ip_ns.update(self.user_ns)
464 469
465 470 if self.block_index == self.nblocks:
466 471 mq1 = self.marquee('END OF DEMO')
467 472 if mq1:
468 473 # avoid spurious print >>io.stdout,s if empty marquees are used
469 474 print(file=io.stdout)
470 475 print(mq1, file=io.stdout)
471 476 print(self.marquee('Use <demo_name>.reset() if you want to rerun it.'), file=io.stdout)
472 477 self.finished = True
473 478
474 479 # These methods are meant to be overridden by subclasses who may wish to
475 480 # customize the behavior of of their demos.
476 481 def marquee(self,txt='',width=78,mark='*'):
477 482 """Return the input string centered in a 'marquee'."""
478 483 return marquee(txt,width,mark)
479 484
480 485 def pre_cmd(self):
481 486 """Method called before executing each block."""
482 487 pass
483 488
484 489 def post_cmd(self):
485 490 """Method called after executing each block."""
486 491 pass
487 492
488 493
489 494 class IPythonDemo(Demo):
490 495 """Class for interactive demos with IPython's input processing applied.
491 496
492 497 This subclasses Demo, but instead of executing each block by the Python
493 498 interpreter (via exec), it actually calls IPython on it, so that any input
494 499 filters which may be in place are applied to the input block.
495 500
496 501 If you have an interactive environment which exposes special input
497 502 processing, you can use this class instead to write demo scripts which
498 503 operate exactly as if you had typed them interactively. The default Demo
499 504 class requires the input to be valid, pure Python code.
500 505 """
501 506
502 507 def run_cell(self,source):
503 508 """Execute a string with one or more lines of code"""
504 509
505 510 self.shell.run_cell(source)
506 511
507 512 class LineDemo(Demo):
508 513 """Demo where each line is executed as a separate block.
509 514
510 515 The input script should be valid Python code.
511 516
512 517 This class doesn't require any markup at all, and it's meant for simple
513 518 scripts (with no nesting or any kind of indentation) which consist of
514 519 multiple lines of input to be executed, one at a time, as if they had been
515 520 typed in the interactive prompt.
516 521
517 522 Note: the input can not have *any* indentation, which means that only
518 523 single-lines of input are accepted, not even function definitions are
519 524 valid."""
520 525
521 526 def reload(self):
522 527 """Reload source from disk and initialize state."""
523 528 # read data and parse into blocks
524 529 self.fload()
525 530 lines = self.fobj.readlines()
526 531 src_b = [l for l in lines if l.strip()]
527 532 nblocks = len(src_b)
528 533 self.src = ''.join(lines)
529 534 self._silent = [False]*nblocks
530 535 self._auto = [True]*nblocks
531 536 self.auto_all = True
532 537 self.nblocks = nblocks
533 538 self.src_blocks = src_b
534 539
535 540 # also build syntax-highlighted source
536 541 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
537 542
538 543 # ensure clean namespace and seek offset
539 544 self.reset()
540 545
541 546
542 547 class IPythonLineDemo(IPythonDemo,LineDemo):
543 548 """Variant of the LineDemo class whose input is processed by IPython."""
544 549 pass
545 550
546 551
547 552 class ClearMixin(object):
548 553 """Use this mixin to make Demo classes with less visual clutter.
549 554
550 555 Demos using this mixin will clear the screen before every block and use
551 556 blank marquees.
552 557
553 558 Note that in order for the methods defined here to actually override those
554 559 of the classes it's mixed with, it must go /first/ in the inheritance
555 560 tree. For example:
556 561
557 562 class ClearIPDemo(ClearMixin,IPythonDemo): pass
558 563
559 564 will provide an IPythonDemo class with the mixin's features.
560 565 """
561 566
562 567 def marquee(self,txt='',width=78,mark='*'):
563 568 """Blank marquee that returns '' no matter what the input."""
564 569 return ''
565 570
566 571 def pre_cmd(self):
567 572 """Method called before executing each block.
568 573
569 574 This one simply clears the screen."""
570 575 from IPython.utils.terminal import term_clear
571 576 term_clear()
572 577
573 578 class ClearDemo(ClearMixin,Demo):
574 579 pass
575 580
576 581
577 582 class ClearIPDemo(ClearMixin,IPythonDemo):
578 583 pass
@@ -1,443 +1,441 b''
1 1 #!/usr/bin/env python
2 2 """Module for interactively running scripts.
3 3
4 4 This module implements classes for interactively running scripts written for
5 5 any system with a prompt which can be matched by a regexp suitable for
6 6 pexpect. It can be used to run as if they had been typed up interactively, an
7 7 arbitrary series of commands for the target system.
8 8
9 9 The module includes classes ready for IPython (with the default prompts),
10 10 plain Python and SAGE, but making a new one is trivial. To see how to use it,
11 11 simply run the module as a script:
12 12
13 13 ./irunner.py --help
14 14
15 15
16 16 This is an extension of Ken Schutte <kschutte-AT-csail.mit.edu>'s script
17 17 contributed on the ipython-user list:
18 18
19 19 http://mail.scipy.org/pipermail/ipython-user/2006-May/003539.html
20 20
21
22 NOTES:
21 Notes
22 -----
23 23
24 24 - This module requires pexpect, available in most linux distros, or which can
25 be downloaded from
26
27 http://pexpect.sourceforge.net
25 be downloaded from http://pexpect.sourceforge.net
28 26
29 27 - Because pexpect only works under Unix or Windows-Cygwin, this has the same
30 28 limitations. This means that it will NOT work under native windows Python.
31 29 """
32 30 from __future__ import print_function
33 31
34 32 # Stdlib imports
35 33 import optparse
36 34 import os
37 35 import sys
38 36
39 37 # Third-party modules: we carry a copy of pexpect to reduce the need for
40 38 # external dependencies, but our import checks for a system version first.
41 39 from IPython.external import pexpect
42 40 from IPython.utils import py3compat
43 41
44 42 # Global usage strings, to avoid indentation issues when typing it below.
45 43 USAGE = """
46 44 Interactive script runner, type: %s
47 45
48 46 runner [opts] script_name
49 47 """
50 48
51 49 def pexpect_monkeypatch():
52 50 """Patch pexpect to prevent unhandled exceptions at VM teardown.
53 51
54 52 Calling this function will monkeypatch the pexpect.spawn class and modify
55 53 its __del__ method to make it more robust in the face of failures that can
56 54 occur if it is called when the Python VM is shutting down.
57 55
58 56 Since Python may fire __del__ methods arbitrarily late, it's possible for
59 57 them to execute during the teardown of the Python VM itself. At this
60 58 point, various builtin modules have been reset to None. Thus, the call to
61 59 self.close() will trigger an exception because it tries to call os.close(),
62 60 and os is now None.
63 61 """
64 62
65 63 if pexpect.__version__[:3] >= '2.2':
66 64 # No need to patch, fix is already the upstream version.
67 65 return
68 66
69 67 def __del__(self):
70 68 """This makes sure that no system resources are left open.
71 69 Python only garbage collects Python objects. OS file descriptors
72 70 are not Python objects, so they must be handled explicitly.
73 71 If the child file descriptor was opened outside of this class
74 72 (passed to the constructor) then this does not close it.
75 73 """
76 74 if not self.closed:
77 75 try:
78 76 self.close()
79 77 except AttributeError:
80 78 pass
81 79
82 80 pexpect.spawn.__del__ = __del__
83 81
84 82 pexpect_monkeypatch()
85 83
86 84 # The generic runner class
87 85 class InteractiveRunner(object):
88 86 """Class to run a sequence of commands through an interactive program."""
89 87
90 88 def __init__(self,program,prompts,args=None,out=sys.stdout,echo=True):
91 89 """Construct a runner.
92 90
93 91 Inputs:
94 92
95 93 - program: command to execute the given program.
96 94
97 95 - prompts: a list of patterns to match as valid prompts, in the
98 96 format used by pexpect. This basically means that it can be either
99 97 a string (to be compiled as a regular expression) or a list of such
100 98 (it must be a true list, as pexpect does type checks).
101 99
102 100 If more than one prompt is given, the first is treated as the main
103 101 program prompt and the others as 'continuation' prompts, like
104 102 python's. This means that blank lines in the input source are
105 103 ommitted when the first prompt is matched, but are NOT ommitted when
106 104 the continuation one matches, since this is how python signals the
107 105 end of multiline input interactively.
108 106
109 107 Optional inputs:
110 108
111 109 - args(None): optional list of strings to pass as arguments to the
112 110 child program.
113 111
114 112 - out(sys.stdout): if given, an output stream to be used when writing
115 113 output. The only requirement is that it must have a .write() method.
116 114
117 115 Public members not parameterized in the constructor:
118 116
119 117 - delaybeforesend(0): Newer versions of pexpect have a delay before
120 118 sending each new input. For our purposes here, it's typically best
121 119 to just set this to zero, but if you encounter reliability problems
122 120 or want an interactive run to pause briefly at each prompt, just
123 121 increase this value (it is measured in seconds). Note that this
124 122 variable is not honored at all by older versions of pexpect.
125 123 """
126 124
127 125 self.program = program
128 126 self.prompts = prompts
129 127 if args is None: args = []
130 128 self.args = args
131 129 self.out = out
132 130 self.echo = echo
133 131 # Other public members which we don't make as parameters, but which
134 132 # users may occasionally want to tweak
135 133 self.delaybeforesend = 0
136 134
137 135 # Create child process and hold on to it so we don't have to re-create
138 136 # for every single execution call
139 137 c = self.child = pexpect.spawn(self.program,self.args,timeout=None)
140 138 c.delaybeforesend = self.delaybeforesend
141 139 # pexpect hard-codes the terminal size as (24,80) (rows,columns).
142 140 # This causes problems because any line longer than 80 characters gets
143 141 # completely overwrapped on the printed outptut (even though
144 142 # internally the code runs fine). We reset this to 99 rows X 200
145 143 # columns (arbitrarily chosen), which should avoid problems in all
146 144 # reasonable cases.
147 145 c.setwinsize(99,200)
148 146
149 147 def close(self):
150 148 """close child process"""
151 149
152 150 self.child.close()
153 151
154 152 def run_file(self,fname,interact=False,get_output=False):
155 153 """Run the given file interactively.
156 154
157 155 Inputs:
158 156
159 157 -fname: name of the file to execute.
160 158
161 159 See the run_source docstring for the meaning of the optional
162 160 arguments."""
163 161
164 162 fobj = open(fname,'r')
165 163 try:
166 164 out = self.run_source(fobj,interact,get_output)
167 165 finally:
168 166 fobj.close()
169 167 if get_output:
170 168 return out
171 169
172 170 def run_source(self,source,interact=False,get_output=False):
173 171 """Run the given source code interactively.
174 172
175 173 Inputs:
176 174
177 175 - source: a string of code to be executed, or an open file object we
178 176 can iterate over.
179 177
180 178 Optional inputs:
181 179
182 180 - interact(False): if true, start to interact with the running
183 181 program at the end of the script. Otherwise, just exit.
184 182
185 183 - get_output(False): if true, capture the output of the child process
186 184 (filtering the input commands out) and return it as a string.
187 185
188 186 Returns:
189 187 A string containing the process output, but only if requested.
190 188 """
191 189
192 190 # if the source is a string, chop it up in lines so we can iterate
193 191 # over it just as if it were an open file.
194 192 if isinstance(source, basestring):
195 193 source = source.splitlines(True)
196 194
197 195 if self.echo:
198 196 # normalize all strings we write to use the native OS line
199 197 # separators.
200 198 linesep = os.linesep
201 199 stdwrite = self.out.write
202 200 write = lambda s: stdwrite(s.replace('\r\n',linesep))
203 201 else:
204 202 # Quiet mode, all writes are no-ops
205 203 write = lambda s: None
206 204
207 205 c = self.child
208 206 prompts = c.compile_pattern_list(self.prompts)
209 207 prompt_idx = c.expect_list(prompts)
210 208
211 209 # Flag whether the script ends normally or not, to know whether we can
212 210 # do anything further with the underlying process.
213 211 end_normal = True
214 212
215 213 # If the output was requested, store it in a list for return at the end
216 214 if get_output:
217 215 output = []
218 216 store_output = output.append
219 217
220 218 for cmd in source:
221 219 # skip blank lines for all matches to the 'main' prompt, while the
222 220 # secondary prompts do not
223 221 if prompt_idx==0 and \
224 222 (cmd.isspace() or cmd.lstrip().startswith('#')):
225 223 write(cmd)
226 224 continue
227 225
228 226 # write('AFTER: '+c.after) # dbg
229 227 write(c.after)
230 228 c.send(cmd)
231 229 try:
232 230 prompt_idx = c.expect_list(prompts)
233 231 except pexpect.EOF:
234 232 # this will happen if the child dies unexpectedly
235 233 write(c.before)
236 234 end_normal = False
237 235 break
238 236
239 237 write(c.before)
240 238
241 239 # With an echoing process, the output we get in c.before contains
242 240 # the command sent, a newline, and then the actual process output
243 241 if get_output:
244 242 store_output(c.before[len(cmd+'\n'):])
245 243 #write('CMD: <<%s>>' % cmd) # dbg
246 244 #write('OUTPUT: <<%s>>' % output[-1]) # dbg
247 245
248 246 self.out.flush()
249 247 if end_normal:
250 248 if interact:
251 249 c.send('\n')
252 250 print('<< Starting interactive mode >>', end=' ')
253 251 try:
254 252 c.interact()
255 253 except OSError:
256 254 # This is what fires when the child stops. Simply print a
257 255 # newline so the system prompt is aligned. The extra
258 256 # space is there to make sure it gets printed, otherwise
259 257 # OS buffering sometimes just suppresses it.
260 258 write(' \n')
261 259 self.out.flush()
262 260 else:
263 261 if interact:
264 262 e="Further interaction is not possible: child process is dead."
265 263 print(e, file=sys.stderr)
266 264
267 265 # Leave the child ready for more input later on, otherwise select just
268 266 # hangs on the second invocation.
269 267 if c.isalive():
270 268 c.send('\n')
271 269
272 270 # Return any requested output
273 271 if get_output:
274 272 return ''.join(output)
275 273
276 274 def main(self,argv=None):
277 275 """Run as a command-line script."""
278 276
279 277 parser = optparse.OptionParser(usage=USAGE % self.__class__.__name__)
280 278 newopt = parser.add_option
281 279 newopt('-i','--interact',action='store_true',default=False,
282 280 help='Interact with the program after the script is run.')
283 281
284 282 opts,args = parser.parse_args(argv)
285 283
286 284 if len(args) != 1:
287 285 print("You must supply exactly one file to run.", file=sys.stderr)
288 286 sys.exit(1)
289 287
290 288 self.run_file(args[0],opts.interact)
291 289
292 290 _ipython_cmd = "ipython3" if py3compat.PY3 else "ipython"
293 291
294 292 # Specific runners for particular programs
295 293 class IPythonRunner(InteractiveRunner):
296 294 """Interactive IPython runner.
297 295
298 296 This initalizes IPython in 'nocolor' mode for simplicity. This lets us
299 297 avoid having to write a regexp that matches ANSI sequences, though pexpect
300 298 does support them. If anyone contributes patches for ANSI color support,
301 299 they will be welcome.
302 300
303 301 It also sets the prompts manually, since the prompt regexps for
304 302 pexpect need to be matched to the actual prompts, so user-customized
305 303 prompts would break this.
306 304 """
307 305
308 306 def __init__(self,program = _ipython_cmd, args=None, out=sys.stdout, echo=True):
309 307 """New runner, optionally passing the ipython command to use."""
310 308 args0 = ['--colors=NoColor',
311 309 '--no-term-title',
312 310 '--no-autoindent',
313 311 # '--quick' is important, to prevent loading default config:
314 312 '--quick']
315 313 if args is None: args = args0
316 314 else: args = args0 + args
317 315 prompts = [r'In \[\d+\]: ',r' \.*: ']
318 316 InteractiveRunner.__init__(self,program,prompts,args,out,echo)
319 317
320 318
321 319 class PythonRunner(InteractiveRunner):
322 320 """Interactive Python runner."""
323 321
324 322 def __init__(self,program=sys.executable, args=None, out=sys.stdout, echo=True):
325 323 """New runner, optionally passing the python command to use."""
326 324
327 325 prompts = [r'>>> ',r'\.\.\. ']
328 326 InteractiveRunner.__init__(self,program,prompts,args,out,echo)
329 327
330 328
331 329 class SAGERunner(InteractiveRunner):
332 330 """Interactive SAGE runner.
333 331
334 332 WARNING: this runner only works if you manually adjust your SAGE
335 333 configuration so that the 'color' option in the configuration file is set to
336 334 'NoColor', because currently the prompt matching regexp does not identify
337 335 color sequences."""
338 336
339 337 def __init__(self,program='sage',args=None,out=sys.stdout,echo=True):
340 338 """New runner, optionally passing the sage command to use."""
341 339
342 340 prompts = ['sage: ',r'\s*\.\.\. ']
343 341 InteractiveRunner.__init__(self,program,prompts,args,out,echo)
344 342
345 343
346 344 class RunnerFactory(object):
347 345 """Code runner factory.
348 346
349 347 This class provides an IPython code runner, but enforces that only one
350 348 runner is ever instantiated. The runner is created based on the extension
351 349 of the first file to run, and it raises an exception if a runner is later
352 350 requested for a different extension type.
353 351
354 352 This ensures that we don't generate example files for doctest with a mix of
355 353 python and ipython syntax.
356 354 """
357 355
358 356 def __init__(self,out=sys.stdout):
359 357 """Instantiate a code runner."""
360 358
361 359 self.out = out
362 360 self.runner = None
363 361 self.runnerClass = None
364 362
365 363 def _makeRunner(self,runnerClass):
366 364 self.runnerClass = runnerClass
367 365 self.runner = runnerClass(out=self.out)
368 366 return self.runner
369 367
370 368 def __call__(self,fname):
371 369 """Return a runner for the given filename."""
372 370
373 371 if fname.endswith('.py'):
374 372 runnerClass = PythonRunner
375 373 elif fname.endswith('.ipy'):
376 374 runnerClass = IPythonRunner
377 375 else:
378 376 raise ValueError('Unknown file type for Runner: %r' % fname)
379 377
380 378 if self.runner is None:
381 379 return self._makeRunner(runnerClass)
382 380 else:
383 381 if runnerClass==self.runnerClass:
384 382 return self.runner
385 383 else:
386 384 e='A runner of type %r can not run file %r' % \
387 385 (self.runnerClass,fname)
388 386 raise ValueError(e)
389 387
390 388
391 389 # Global usage string, to avoid indentation issues if typed in a function def.
392 390 MAIN_USAGE = """
393 391 %prog [options] file_to_run
394 392
395 393 This is an interface to the various interactive runners available in this
396 394 module. If you want to pass specific options to one of the runners, you need
397 395 to first terminate the main options with a '--', and then provide the runner's
398 396 options. For example:
399 397
400 398 irunner.py --python -- --help
401 399
402 400 will pass --help to the python runner. Similarly,
403 401
404 402 irunner.py --ipython -- --interact script.ipy
405 403
406 404 will run the script.ipy file under the IPython runner, and then will start to
407 405 interact with IPython at the end of the script (instead of exiting).
408 406
409 407 The already implemented runners are listed below; adding one for a new program
410 408 is a trivial task, see the source for examples.
411 409 """
412 410
413 411 def main():
414 412 """Run as a command-line script."""
415 413
416 414 parser = optparse.OptionParser(usage=MAIN_USAGE)
417 415 newopt = parser.add_option
418 416 newopt('--ipython',action='store_const',dest='mode',const='ipython',
419 417 help='IPython interactive runner (default).')
420 418 newopt('--python',action='store_const',dest='mode',const='python',
421 419 help='Python interactive runner.')
422 420 newopt('--sage',action='store_const',dest='mode',const='sage',
423 421 help='SAGE interactive runner.')
424 422
425 423 opts,args = parser.parse_args()
426 424 runners = dict(ipython=IPythonRunner,
427 425 python=PythonRunner,
428 426 sage=SAGERunner)
429 427
430 428 try:
431 429 ext = os.path.splitext(args[0])[-1]
432 430 except IndexError:
433 431 ext = ''
434 432 modes = {'.ipy':'ipython',
435 433 '.py':'python',
436 434 '.sage':'sage'}
437 435 mode = modes.get(ext,"ipython")
438 436 if opts.mode:
439 437 mode = opts.mode
440 438 runners[mode]().main(args)
441 439
442 440 if __name__ == '__main__':
443 441 main()
@@ -1,734 +1,736 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 pretty
4 ~~
5
6 3 Python advanced pretty printer. This pretty printer is intended to
7 4 replace the old `pprint` python module which does not allow developers
8 5 to provide their own pretty print callbacks.
9 6
10 7 This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`.
11 8
12 9
13 10 Example Usage
14 =============
11 -------------
15 12
16 13 To directly print the representation of an object use `pprint`::
17 14
18 15 from pretty import pprint
19 16 pprint(complex_object)
20 17
21 18 To get a string of the output use `pretty`::
22 19
23 20 from pretty import pretty
24 21 string = pretty(complex_object)
25 22
26 23
27 24 Extending
28 =========
25 ---------
29 26
30 27 The pretty library allows developers to add pretty printing rules for their
31 28 own objects. This process is straightforward. All you have to do is to
32 29 add a `_repr_pretty_` method to your object and call the methods on the
33 30 pretty printer passed::
34 31
35 32 class MyObject(object):
36 33
37 34 def _repr_pretty_(self, p, cycle):
38 35 ...
39 36
40 37 Depending on the python version you want to support you have two
41 38 possibilities. The following list shows the python 2.5 version and the
42 39 compatibility one.
43 40
44 41
45 42 Here the example implementation of a `_repr_pretty_` method for a list
46 43 subclass for python 2.5 and higher (python 2.5 requires the with statement
47 44 __future__ import)::
48 45
49 46 class MyList(list):
50 47
51 48 def _repr_pretty_(self, p, cycle):
52 49 if cycle:
53 50 p.text('MyList(...)')
54 51 else:
55 52 with p.group(8, 'MyList([', '])'):
56 53 for idx, item in enumerate(self):
57 54 if idx:
58 55 p.text(',')
59 56 p.breakable()
60 57 p.pretty(item)
61 58
62 59 The `cycle` parameter is `True` if pretty detected a cycle. You *have* to
63 60 react to that or the result is an infinite loop. `p.text()` just adds
64 61 non breaking text to the output, `p.breakable()` either adds a whitespace
65 62 or breaks here. If you pass it an argument it's used instead of the
66 63 default space. `p.pretty` prettyprints another object using the pretty print
67 64 method.
68 65
69 66 The first parameter to the `group` function specifies the extra indentation
70 67 of the next line. In this example the next item will either be not
71 68 breaked (if the items are short enough) or aligned with the right edge of
72 69 the opening bracked of `MyList`.
73 70
74 71 If you want to support python 2.4 and lower you can use this code::
75 72
76 73 class MyList(list):
77 74
78 75 def _repr_pretty_(self, p, cycle):
79 76 if cycle:
80 77 p.text('MyList(...)')
81 78 else:
82 79 p.begin_group(8, 'MyList([')
83 80 for idx, item in enumerate(self):
84 81 if idx:
85 82 p.text(',')
86 83 p.breakable()
87 84 p.pretty(item)
88 85 p.end_group(8, '])')
89 86
90 87 If you just want to indent something you can use the group function
91 88 without open / close parameters. Under python 2.5 you can also use this
92 89 code::
93 90
94 91 with p.indent(2):
95 92 ...
96 93
97 94 Or under python2.4 you might want to modify ``p.indentation`` by hand but
98 95 this is rather ugly.
99 96
97 Inheritance diagram:
98
99 .. inheritance-diagram:: IPython.lib.pretty
100 :parts: 3
101
100 102 :copyright: 2007 by Armin Ronacher.
101 103 Portions (c) 2009 by Robert Kern.
102 104 :license: BSD License.
103 105 """
104 106 from __future__ import with_statement
105 107 from contextlib import contextmanager
106 108 import sys
107 109 import types
108 110 import re
109 111 import datetime
110 112 from StringIO import StringIO
111 113 from collections import deque
112 114
113 115
114 116 __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
115 117 'for_type', 'for_type_by_name']
116 118
117 119
118 120 _re_pattern_type = type(re.compile(''))
119 121
120 122
121 123 def pretty(obj, verbose=False, max_width=79, newline='\n'):
122 124 """
123 125 Pretty print the object's representation.
124 126 """
125 127 stream = StringIO()
126 128 printer = RepresentationPrinter(stream, verbose, max_width, newline)
127 129 printer.pretty(obj)
128 130 printer.flush()
129 131 return stream.getvalue()
130 132
131 133
132 134 def pprint(obj, verbose=False, max_width=79, newline='\n'):
133 135 """
134 136 Like `pretty` but print to stdout.
135 137 """
136 138 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline)
137 139 printer.pretty(obj)
138 140 printer.flush()
139 141 sys.stdout.write(newline)
140 142 sys.stdout.flush()
141 143
142 144 class _PrettyPrinterBase(object):
143 145
144 146 @contextmanager
145 147 def indent(self, indent):
146 148 """with statement support for indenting/dedenting."""
147 149 self.indentation += indent
148 150 try:
149 151 yield
150 152 finally:
151 153 self.indentation -= indent
152 154
153 155 @contextmanager
154 156 def group(self, indent=0, open='', close=''):
155 157 """like begin_group / end_group but for the with statement."""
156 158 self.begin_group(indent, open)
157 159 try:
158 160 yield
159 161 finally:
160 162 self.end_group(indent, close)
161 163
162 164 class PrettyPrinter(_PrettyPrinterBase):
163 165 """
164 166 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
165 167 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
166 168 this printer knows nothing about the default pprinters or the `_repr_pretty_`
167 169 callback method.
168 170 """
169 171
170 172 def __init__(self, output, max_width=79, newline='\n'):
171 173 self.output = output
172 174 self.max_width = max_width
173 175 self.newline = newline
174 176 self.output_width = 0
175 177 self.buffer_width = 0
176 178 self.buffer = deque()
177 179
178 180 root_group = Group(0)
179 181 self.group_stack = [root_group]
180 182 self.group_queue = GroupQueue(root_group)
181 183 self.indentation = 0
182 184
183 185 def _break_outer_groups(self):
184 186 while self.max_width < self.output_width + self.buffer_width:
185 187 group = self.group_queue.deq()
186 188 if not group:
187 189 return
188 190 while group.breakables:
189 191 x = self.buffer.popleft()
190 192 self.output_width = x.output(self.output, self.output_width)
191 193 self.buffer_width -= x.width
192 194 while self.buffer and isinstance(self.buffer[0], Text):
193 195 x = self.buffer.popleft()
194 196 self.output_width = x.output(self.output, self.output_width)
195 197 self.buffer_width -= x.width
196 198
197 199 def text(self, obj):
198 200 """Add literal text to the output."""
199 201 width = len(obj)
200 202 if self.buffer:
201 203 text = self.buffer[-1]
202 204 if not isinstance(text, Text):
203 205 text = Text()
204 206 self.buffer.append(text)
205 207 text.add(obj, width)
206 208 self.buffer_width += width
207 209 self._break_outer_groups()
208 210 else:
209 211 self.output.write(obj)
210 212 self.output_width += width
211 213
212 214 def breakable(self, sep=' '):
213 215 """
214 216 Add a breakable separator to the output. This does not mean that it
215 217 will automatically break here. If no breaking on this position takes
216 218 place the `sep` is inserted which default to one space.
217 219 """
218 220 width = len(sep)
219 221 group = self.group_stack[-1]
220 222 if group.want_break:
221 223 self.flush()
222 224 self.output.write(self.newline)
223 225 self.output.write(' ' * self.indentation)
224 226 self.output_width = self.indentation
225 227 self.buffer_width = 0
226 228 else:
227 229 self.buffer.append(Breakable(sep, width, self))
228 230 self.buffer_width += width
229 231 self._break_outer_groups()
230 232
231 233
232 234 def begin_group(self, indent=0, open=''):
233 235 """
234 236 Begin a group. If you want support for python < 2.5 which doesn't has
235 237 the with statement this is the preferred way:
236 238
237 239 p.begin_group(1, '{')
238 240 ...
239 241 p.end_group(1, '}')
240 242
241 243 The python 2.5 expression would be this:
242 244
243 245 with p.group(1, '{', '}'):
244 246 ...
245 247
246 248 The first parameter specifies the indentation for the next line (usually
247 249 the width of the opening text), the second the opening text. All
248 250 parameters are optional.
249 251 """
250 252 if open:
251 253 self.text(open)
252 254 group = Group(self.group_stack[-1].depth + 1)
253 255 self.group_stack.append(group)
254 256 self.group_queue.enq(group)
255 257 self.indentation += indent
256 258
257 259 def end_group(self, dedent=0, close=''):
258 260 """End a group. See `begin_group` for more details."""
259 261 self.indentation -= dedent
260 262 group = self.group_stack.pop()
261 263 if not group.breakables:
262 264 self.group_queue.remove(group)
263 265 if close:
264 266 self.text(close)
265 267
266 268 def flush(self):
267 269 """Flush data that is left in the buffer."""
268 270 for data in self.buffer:
269 271 self.output_width += data.output(self.output, self.output_width)
270 272 self.buffer.clear()
271 273 self.buffer_width = 0
272 274
273 275
274 276 def _get_mro(obj_class):
275 277 """ Get a reasonable method resolution order of a class and its superclasses
276 278 for both old-style and new-style classes.
277 279 """
278 280 if not hasattr(obj_class, '__mro__'):
279 281 # Old-style class. Mix in object to make a fake new-style class.
280 282 try:
281 283 obj_class = type(obj_class.__name__, (obj_class, object), {})
282 284 except TypeError:
283 285 # Old-style extension type that does not descend from object.
284 286 # FIXME: try to construct a more thorough MRO.
285 287 mro = [obj_class]
286 288 else:
287 289 mro = obj_class.__mro__[1:-1]
288 290 else:
289 291 mro = obj_class.__mro__
290 292 return mro
291 293
292 294
293 295 class RepresentationPrinter(PrettyPrinter):
294 296 """
295 297 Special pretty printer that has a `pretty` method that calls the pretty
296 298 printer for a python object.
297 299
298 300 This class stores processing data on `self` so you must *never* use
299 301 this class in a threaded environment. Always lock it or reinstanciate
300 302 it.
301 303
302 304 Instances also have a verbose flag callbacks can access to control their
303 305 output. For example the default instance repr prints all attributes and
304 306 methods that are not prefixed by an underscore if the printer is in
305 307 verbose mode.
306 308 """
307 309
308 310 def __init__(self, output, verbose=False, max_width=79, newline='\n',
309 311 singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None):
310 312
311 313 PrettyPrinter.__init__(self, output, max_width, newline)
312 314 self.verbose = verbose
313 315 self.stack = []
314 316 if singleton_pprinters is None:
315 317 singleton_pprinters = _singleton_pprinters.copy()
316 318 self.singleton_pprinters = singleton_pprinters
317 319 if type_pprinters is None:
318 320 type_pprinters = _type_pprinters.copy()
319 321 self.type_pprinters = type_pprinters
320 322 if deferred_pprinters is None:
321 323 deferred_pprinters = _deferred_type_pprinters.copy()
322 324 self.deferred_pprinters = deferred_pprinters
323 325
324 326 def pretty(self, obj):
325 327 """Pretty print the given object."""
326 328 obj_id = id(obj)
327 329 cycle = obj_id in self.stack
328 330 self.stack.append(obj_id)
329 331 self.begin_group()
330 332 try:
331 333 obj_class = getattr(obj, '__class__', None) or type(obj)
332 334 # First try to find registered singleton printers for the type.
333 335 try:
334 336 printer = self.singleton_pprinters[obj_id]
335 337 except (TypeError, KeyError):
336 338 pass
337 339 else:
338 340 return printer(obj, self, cycle)
339 341 # Next walk the mro and check for either:
340 342 # 1) a registered printer
341 343 # 2) a _repr_pretty_ method
342 344 for cls in _get_mro(obj_class):
343 345 if cls in self.type_pprinters:
344 346 # printer registered in self.type_pprinters
345 347 return self.type_pprinters[cls](obj, self, cycle)
346 348 else:
347 349 # deferred printer
348 350 printer = self._in_deferred_types(cls)
349 351 if printer is not None:
350 352 return printer(obj, self, cycle)
351 353 else:
352 354 # Finally look for special method names.
353 355 # Some objects automatically create any requested
354 356 # attribute. Try to ignore most of them by checking for
355 357 # callability.
356 358 if '_repr_pretty_' in cls.__dict__:
357 359 meth = cls._repr_pretty_
358 360 if callable(meth):
359 361 return meth(obj, self, cycle)
360 362 return _default_pprint(obj, self, cycle)
361 363 finally:
362 364 self.end_group()
363 365 self.stack.pop()
364 366
365 367 def _in_deferred_types(self, cls):
366 368 """
367 369 Check if the given class is specified in the deferred type registry.
368 370
369 371 Returns the printer from the registry if it exists, and None if the
370 372 class is not in the registry. Successful matches will be moved to the
371 373 regular type registry for future use.
372 374 """
373 375 mod = getattr(cls, '__module__', None)
374 376 name = getattr(cls, '__name__', None)
375 377 key = (mod, name)
376 378 printer = None
377 379 if key in self.deferred_pprinters:
378 380 # Move the printer over to the regular registry.
379 381 printer = self.deferred_pprinters.pop(key)
380 382 self.type_pprinters[cls] = printer
381 383 return printer
382 384
383 385
384 386 class Printable(object):
385 387
386 388 def output(self, stream, output_width):
387 389 return output_width
388 390
389 391
390 392 class Text(Printable):
391 393
392 394 def __init__(self):
393 395 self.objs = []
394 396 self.width = 0
395 397
396 398 def output(self, stream, output_width):
397 399 for obj in self.objs:
398 400 stream.write(obj)
399 401 return output_width + self.width
400 402
401 403 def add(self, obj, width):
402 404 self.objs.append(obj)
403 405 self.width += width
404 406
405 407
406 408 class Breakable(Printable):
407 409
408 410 def __init__(self, seq, width, pretty):
409 411 self.obj = seq
410 412 self.width = width
411 413 self.pretty = pretty
412 414 self.indentation = pretty.indentation
413 415 self.group = pretty.group_stack[-1]
414 416 self.group.breakables.append(self)
415 417
416 418 def output(self, stream, output_width):
417 419 self.group.breakables.popleft()
418 420 if self.group.want_break:
419 421 stream.write(self.pretty.newline)
420 422 stream.write(' ' * self.indentation)
421 423 return self.indentation
422 424 if not self.group.breakables:
423 425 self.pretty.group_queue.remove(self.group)
424 426 stream.write(self.obj)
425 427 return output_width + self.width
426 428
427 429
428 430 class Group(Printable):
429 431
430 432 def __init__(self, depth):
431 433 self.depth = depth
432 434 self.breakables = deque()
433 435 self.want_break = False
434 436
435 437
436 438 class GroupQueue(object):
437 439
438 440 def __init__(self, *groups):
439 441 self.queue = []
440 442 for group in groups:
441 443 self.enq(group)
442 444
443 445 def enq(self, group):
444 446 depth = group.depth
445 447 while depth > len(self.queue) - 1:
446 448 self.queue.append([])
447 449 self.queue[depth].append(group)
448 450
449 451 def deq(self):
450 452 for stack in self.queue:
451 453 for idx, group in enumerate(reversed(stack)):
452 454 if group.breakables:
453 455 del stack[idx]
454 456 group.want_break = True
455 457 return group
456 458 for group in stack:
457 459 group.want_break = True
458 460 del stack[:]
459 461
460 462 def remove(self, group):
461 463 try:
462 464 self.queue[group.depth].remove(group)
463 465 except ValueError:
464 466 pass
465 467
466 468 try:
467 469 _baseclass_reprs = (object.__repr__, types.InstanceType.__repr__)
468 470 except AttributeError: # Python 3
469 471 _baseclass_reprs = (object.__repr__,)
470 472
471 473
472 474 def _default_pprint(obj, p, cycle):
473 475 """
474 476 The default print function. Used if an object does not provide one and
475 477 it's none of the builtin objects.
476 478 """
477 479 klass = getattr(obj, '__class__', None) or type(obj)
478 480 if getattr(klass, '__repr__', None) not in _baseclass_reprs:
479 481 # A user-provided repr.
480 482 p.text(repr(obj))
481 483 return
482 484 p.begin_group(1, '<')
483 485 p.pretty(klass)
484 486 p.text(' at 0x%x' % id(obj))
485 487 if cycle:
486 488 p.text(' ...')
487 489 elif p.verbose:
488 490 first = True
489 491 for key in dir(obj):
490 492 if not key.startswith('_'):
491 493 try:
492 494 value = getattr(obj, key)
493 495 except AttributeError:
494 496 continue
495 497 if isinstance(value, types.MethodType):
496 498 continue
497 499 if not first:
498 500 p.text(',')
499 501 p.breakable()
500 502 p.text(key)
501 503 p.text('=')
502 504 step = len(key) + 1
503 505 p.indentation += step
504 506 p.pretty(value)
505 507 p.indentation -= step
506 508 first = False
507 509 p.end_group(1, '>')
508 510
509 511
510 512 def _seq_pprinter_factory(start, end, basetype):
511 513 """
512 514 Factory that returns a pprint function useful for sequences. Used by
513 515 the default pprint for tuples, dicts, lists, sets and frozensets.
514 516 """
515 517 def inner(obj, p, cycle):
516 518 typ = type(obj)
517 519 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
518 520 # If the subclass provides its own repr, use it instead.
519 521 return p.text(typ.__repr__(obj))
520 522
521 523 if cycle:
522 524 return p.text(start + '...' + end)
523 525 step = len(start)
524 526 p.begin_group(step, start)
525 527 for idx, x in enumerate(obj):
526 528 if idx:
527 529 p.text(',')
528 530 p.breakable()
529 531 p.pretty(x)
530 532 if len(obj) == 1 and type(obj) is tuple:
531 533 # Special case for 1-item tuples.
532 534 p.text(',')
533 535 p.end_group(step, end)
534 536 return inner
535 537
536 538
537 539 def _dict_pprinter_factory(start, end, basetype=None):
538 540 """
539 541 Factory that returns a pprint function used by the default pprint of
540 542 dicts and dict proxies.
541 543 """
542 544 def inner(obj, p, cycle):
543 545 typ = type(obj)
544 546 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
545 547 # If the subclass provides its own repr, use it instead.
546 548 return p.text(typ.__repr__(obj))
547 549
548 550 if cycle:
549 551 return p.text('{...}')
550 552 p.begin_group(1, start)
551 553 keys = obj.keys()
552 554 try:
553 555 keys.sort()
554 556 except Exception as e:
555 557 # Sometimes the keys don't sort.
556 558 pass
557 559 for idx, key in enumerate(keys):
558 560 if idx:
559 561 p.text(',')
560 562 p.breakable()
561 563 p.pretty(key)
562 564 p.text(': ')
563 565 p.pretty(obj[key])
564 566 p.end_group(1, end)
565 567 return inner
566 568
567 569
568 570 def _super_pprint(obj, p, cycle):
569 571 """The pprint for the super type."""
570 572 p.begin_group(8, '<super: ')
571 573 p.pretty(obj.__self_class__)
572 574 p.text(',')
573 575 p.breakable()
574 576 p.pretty(obj.__self__)
575 577 p.end_group(8, '>')
576 578
577 579
578 580 def _re_pattern_pprint(obj, p, cycle):
579 581 """The pprint function for regular expression patterns."""
580 582 p.text('re.compile(')
581 583 pattern = repr(obj.pattern)
582 584 if pattern[:1] in 'uU':
583 585 pattern = pattern[1:]
584 586 prefix = 'ur'
585 587 else:
586 588 prefix = 'r'
587 589 pattern = prefix + pattern.replace('\\\\', '\\')
588 590 p.text(pattern)
589 591 if obj.flags:
590 592 p.text(',')
591 593 p.breakable()
592 594 done_one = False
593 595 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
594 596 'UNICODE', 'VERBOSE', 'DEBUG'):
595 597 if obj.flags & getattr(re, flag):
596 598 if done_one:
597 599 p.text('|')
598 600 p.text('re.' + flag)
599 601 done_one = True
600 602 p.text(')')
601 603
602 604
603 605 def _type_pprint(obj, p, cycle):
604 606 """The pprint for classes and types."""
605 607 if obj.__module__ in ('__builtin__', 'exceptions'):
606 608 name = obj.__name__
607 609 else:
608 610 name = obj.__module__ + '.' + obj.__name__
609 611 p.text(name)
610 612
611 613
612 614 def _repr_pprint(obj, p, cycle):
613 615 """A pprint that just redirects to the normal repr function."""
614 616 p.text(repr(obj))
615 617
616 618
617 619 def _function_pprint(obj, p, cycle):
618 620 """Base pprint for all functions and builtin functions."""
619 621 if obj.__module__ in ('__builtin__', 'exceptions') or not obj.__module__:
620 622 name = obj.__name__
621 623 else:
622 624 name = obj.__module__ + '.' + obj.__name__
623 625 p.text('<function %s>' % name)
624 626
625 627
626 628 def _exception_pprint(obj, p, cycle):
627 629 """Base pprint for all exceptions."""
628 630 if obj.__class__.__module__ in ('exceptions', 'builtins'):
629 631 name = obj.__class__.__name__
630 632 else:
631 633 name = '%s.%s' % (
632 634 obj.__class__.__module__,
633 635 obj.__class__.__name__
634 636 )
635 637 step = len(name) + 1
636 638 p.begin_group(step, name + '(')
637 639 for idx, arg in enumerate(getattr(obj, 'args', ())):
638 640 if idx:
639 641 p.text(',')
640 642 p.breakable()
641 643 p.pretty(arg)
642 644 p.end_group(step, ')')
643 645
644 646
645 647 #: the exception base
646 648 try:
647 649 _exception_base = BaseException
648 650 except NameError:
649 651 _exception_base = Exception
650 652
651 653
652 654 #: printers for builtin types
653 655 _type_pprinters = {
654 656 int: _repr_pprint,
655 657 long: _repr_pprint,
656 658 float: _repr_pprint,
657 659 str: _repr_pprint,
658 660 unicode: _repr_pprint,
659 661 tuple: _seq_pprinter_factory('(', ')', tuple),
660 662 list: _seq_pprinter_factory('[', ']', list),
661 663 dict: _dict_pprinter_factory('{', '}', dict),
662 664
663 665 set: _seq_pprinter_factory('set([', '])', set),
664 666 frozenset: _seq_pprinter_factory('frozenset([', '])', frozenset),
665 667 super: _super_pprint,
666 668 _re_pattern_type: _re_pattern_pprint,
667 669 type: _type_pprint,
668 670 types.FunctionType: _function_pprint,
669 671 types.BuiltinFunctionType: _function_pprint,
670 672 types.SliceType: _repr_pprint,
671 673 types.MethodType: _repr_pprint,
672 674
673 675 datetime.datetime: _repr_pprint,
674 676 datetime.timedelta: _repr_pprint,
675 677 _exception_base: _exception_pprint
676 678 }
677 679
678 680 try:
679 681 _type_pprinters[types.DictProxyType] = _dict_pprinter_factory('<dictproxy {', '}>')
680 682 _type_pprinters[types.ClassType] = _type_pprint
681 683 except AttributeError: # Python 3
682 684 pass
683 685
684 686 try:
685 687 _type_pprinters[xrange] = _repr_pprint
686 688 except NameError:
687 689 _type_pprinters[range] = _repr_pprint
688 690
689 691 #: printers for types specified by name
690 692 _deferred_type_pprinters = {
691 693 }
692 694
693 695 def for_type(typ, func):
694 696 """
695 697 Add a pretty printer for a given type.
696 698 """
697 699 oldfunc = _type_pprinters.get(typ, None)
698 700 if func is not None:
699 701 # To support easy restoration of old pprinters, we need to ignore Nones.
700 702 _type_pprinters[typ] = func
701 703 return oldfunc
702 704
703 705 def for_type_by_name(type_module, type_name, func):
704 706 """
705 707 Add a pretty printer for a type specified by the module and name of a type
706 708 rather than the type object itself.
707 709 """
708 710 key = (type_module, type_name)
709 711 oldfunc = _deferred_type_pprinters.get(key, None)
710 712 if func is not None:
711 713 # To support easy restoration of old pprinters, we need to ignore Nones.
712 714 _deferred_type_pprinters[key] = func
713 715 return oldfunc
714 716
715 717
716 718 #: printers for the default singletons
717 719 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
718 720 NotImplemented]), _repr_pprint)
719 721
720 722
721 723 if __name__ == '__main__':
722 724 from random import randrange
723 725 class Foo(object):
724 726 def __init__(self):
725 727 self.foo = 1
726 728 self.bar = re.compile(r'\s+')
727 729 self.blub = dict.fromkeys(range(30), randrange(1, 40))
728 730 self.hehe = 23424.234234
729 731 self.list = ["blub", "blah", self]
730 732
731 733 def get_foo(self):
732 734 print "foo"
733 735
734 736 pprint(Foo(), verbose=True)
@@ -1,341 +1,346 b''
1 1 # encoding: utf-8
2 2
3 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 10 Authors:
6 11
7 12 * Brian Granger
8 13 * Min RK
9 14 """
10 15 from __future__ import print_function
11 16
12 17 import sys
13 18 import traceback
14 19
15 20 __docformat__ = "restructuredtext en"
16 21
17 22 # Tell nose to skip this module
18 23 __test__ = {}
19 24
20 25 #-------------------------------------------------------------------------------
21 26 # Copyright (C) 2008-2011 The IPython Development Team
22 27 #
23 28 # Distributed under the terms of the BSD License. The full license is in
24 29 # the file COPYING, distributed as part of this software.
25 30 #-------------------------------------------------------------------------------
26 31
27 32 #-------------------------------------------------------------------------------
28 33 # Error classes
29 34 #-------------------------------------------------------------------------------
30 35 class IPythonError(Exception):
31 36 """Base exception that all of our exceptions inherit from.
32 37
33 38 This can be raised by code that doesn't have any more specific
34 39 information."""
35 40
36 41 pass
37 42
38 43 # Exceptions associated with the controller objects
39 44 class ControllerError(IPythonError): pass
40 45
41 46 class ControllerCreationError(ControllerError): pass
42 47
43 48
44 49 # Exceptions associated with the Engines
45 50 class EngineError(IPythonError): pass
46 51
47 52 class EngineCreationError(EngineError): pass
48 53
49 54 class KernelError(IPythonError):
50 55 pass
51 56
52 57 class NotDefined(KernelError):
53 58 def __init__(self, name):
54 59 self.name = name
55 60 self.args = (name,)
56 61
57 62 def __repr__(self):
58 63 return '<NotDefined: %s>' % self.name
59 64
60 65 __str__ = __repr__
61 66
62 67
63 68 class QueueCleared(KernelError):
64 69 pass
65 70
66 71
67 72 class IdInUse(KernelError):
68 73 pass
69 74
70 75
71 76 class ProtocolError(KernelError):
72 77 pass
73 78
74 79
75 80 class ConnectionError(KernelError):
76 81 pass
77 82
78 83
79 84 class InvalidEngineID(KernelError):
80 85 pass
81 86
82 87
83 88 class NoEnginesRegistered(KernelError):
84 89 pass
85 90
86 91
87 92 class InvalidClientID(KernelError):
88 93 pass
89 94
90 95
91 96 class InvalidDeferredID(KernelError):
92 97 pass
93 98
94 99
95 100 class SerializationError(KernelError):
96 101 pass
97 102
98 103
99 104 class MessageSizeError(KernelError):
100 105 pass
101 106
102 107
103 108 class PBMessageSizeError(MessageSizeError):
104 109 pass
105 110
106 111
107 112 class ResultNotCompleted(KernelError):
108 113 pass
109 114
110 115
111 116 class ResultAlreadyRetrieved(KernelError):
112 117 pass
113 118
114 119 class ClientError(KernelError):
115 120 pass
116 121
117 122
118 123 class TaskAborted(KernelError):
119 124 pass
120 125
121 126
122 127 class TaskTimeout(KernelError):
123 128 pass
124 129
125 130
126 131 class NotAPendingResult(KernelError):
127 132 pass
128 133
129 134
130 135 class UnpickleableException(KernelError):
131 136 pass
132 137
133 138
134 139 class AbortedPendingDeferredError(KernelError):
135 140 pass
136 141
137 142
138 143 class InvalidProperty(KernelError):
139 144 pass
140 145
141 146
142 147 class MissingBlockArgument(KernelError):
143 148 pass
144 149
145 150
146 151 class StopLocalExecution(KernelError):
147 152 pass
148 153
149 154
150 155 class SecurityError(KernelError):
151 156 pass
152 157
153 158
154 159 class FileTimeoutError(KernelError):
155 160 pass
156 161
157 162 class TimeoutError(KernelError):
158 163 pass
159 164
160 165 class UnmetDependency(KernelError):
161 166 pass
162 167
163 168 class ImpossibleDependency(UnmetDependency):
164 169 pass
165 170
166 171 class DependencyTimeout(ImpossibleDependency):
167 172 pass
168 173
169 174 class InvalidDependency(ImpossibleDependency):
170 175 pass
171 176
172 177 class RemoteError(KernelError):
173 178 """Error raised elsewhere"""
174 179 ename=None
175 180 evalue=None
176 181 traceback=None
177 182 engine_info=None
178 183
179 184 def __init__(self, ename, evalue, traceback, engine_info=None):
180 185 self.ename=ename
181 186 self.evalue=evalue
182 187 self.traceback=traceback
183 188 self.engine_info=engine_info or {}
184 189 self.args=(ename, evalue)
185 190
186 191 def __repr__(self):
187 192 engineid = self.engine_info.get('engine_id', ' ')
188 193 return "<Remote[%s]:%s(%s)>"%(engineid, self.ename, self.evalue)
189 194
190 195 def __str__(self):
191 196 return "%s(%s)" % (self.ename, self.evalue)
192 197
193 198 def render_traceback(self):
194 199 """render traceback to a list of lines"""
195 200 return (self.traceback or "No traceback available").splitlines()
196 201
197 202 def _render_traceback_(self):
198 203 """Special method for custom tracebacks within IPython.
199 204
200 205 This will be called by IPython instead of displaying the local traceback.
201 206
202 207 It should return a traceback rendered as a list of lines.
203 208 """
204 209 return self.render_traceback()
205 210
206 211 def print_traceback(self, excid=None):
207 212 """print my traceback"""
208 213 print('\n'.join(self.render_traceback()))
209 214
210 215
211 216
212 217
213 218 class TaskRejectError(KernelError):
214 219 """Exception to raise when a task should be rejected by an engine.
215 220
216 221 This exception can be used to allow a task running on an engine to test
217 222 if the engine (or the user's namespace on the engine) has the needed
218 223 task dependencies. If not, the task should raise this exception. For
219 224 the task to be retried on another engine, the task should be created
220 225 with the `retries` argument > 1.
221 226
222 227 The advantage of this approach over our older properties system is that
223 228 tasks have full access to the user's namespace on the engines and the
224 229 properties don't have to be managed or tested by the controller.
225 230 """
226 231
227 232
228 233 class CompositeError(RemoteError):
229 234 """Error for representing possibly multiple errors on engines"""
230 235 def __init__(self, message, elist):
231 236 Exception.__init__(self, *(message, elist))
232 237 # Don't use pack_exception because it will conflict with the .message
233 238 # attribute that is being deprecated in 2.6 and beyond.
234 239 self.msg = message
235 240 self.elist = elist
236 241 self.args = [ e[0] for e in elist ]
237 242
238 243 def _get_engine_str(self, ei):
239 244 if not ei:
240 245 return '[Engine Exception]'
241 246 else:
242 247 return '[%s:%s]: ' % (ei['engine_id'], ei['method'])
243 248
244 249 def _get_traceback(self, ev):
245 250 try:
246 251 tb = ev._ipython_traceback_text
247 252 except AttributeError:
248 253 return 'No traceback available'
249 254 else:
250 255 return tb
251 256
252 257 def __str__(self):
253 258 s = str(self.msg)
254 259 for en, ev, etb, ei in self.elist:
255 260 engine_str = self._get_engine_str(ei)
256 261 s = s + '\n' + engine_str + en + ': ' + str(ev)
257 262 return s
258 263
259 264 def __repr__(self):
260 265 return "CompositeError(%i)"%len(self.elist)
261 266
262 267 def render_traceback(self, excid=None):
263 268 """render one or all of my tracebacks to a list of lines"""
264 269 lines = []
265 270 if excid is None:
266 271 for (en,ev,etb,ei) in self.elist:
267 272 lines.append(self._get_engine_str(ei))
268 273 lines.extend((etb or 'No traceback available').splitlines())
269 274 lines.append('')
270 275 else:
271 276 try:
272 277 en,ev,etb,ei = self.elist[excid]
273 278 except:
274 279 raise IndexError("an exception with index %i does not exist"%excid)
275 280 else:
276 281 lines.append(self._get_engine_str(ei))
277 282 lines.extend((etb or 'No traceback available').splitlines())
278 283
279 284 return lines
280 285
281 286 def print_traceback(self, excid=None):
282 287 print('\n'.join(self.render_traceback(excid)))
283 288
284 289 def raise_exception(self, excid=0):
285 290 try:
286 291 en,ev,etb,ei = self.elist[excid]
287 292 except:
288 293 raise IndexError("an exception with index %i does not exist"%excid)
289 294 else:
290 295 raise RemoteError(en, ev, etb, ei)
291 296
292 297
293 298 def collect_exceptions(rdict_or_list, method='unspecified'):
294 299 """check a result dict for errors, and raise CompositeError if any exist.
295 300 Passthrough otherwise."""
296 301 elist = []
297 302 if isinstance(rdict_or_list, dict):
298 303 rlist = rdict_or_list.values()
299 304 else:
300 305 rlist = rdict_or_list
301 306 for r in rlist:
302 307 if isinstance(r, RemoteError):
303 308 en, ev, etb, ei = r.ename, r.evalue, r.traceback, r.engine_info
304 309 # Sometimes we could have CompositeError in our list. Just take
305 310 # the errors out of them and put them in our new list. This
306 311 # has the effect of flattening lists of CompositeErrors into one
307 312 # CompositeError
308 313 if en=='CompositeError':
309 314 for e in ev.elist:
310 315 elist.append(e)
311 316 else:
312 317 elist.append((en, ev, etb, ei))
313 318 if len(elist)==0:
314 319 return rdict_or_list
315 320 else:
316 321 msg = "one or more exceptions from call to method: %s" % (method)
317 322 # This silliness is needed so the debugger has access to the exception
318 323 # instance (e in this case)
319 324 try:
320 325 raise CompositeError(msg, elist)
321 326 except CompositeError as e:
322 327 raise e
323 328
324 329 def wrap_exception(engine_info={}):
325 330 etype, evalue, tb = sys.exc_info()
326 331 stb = traceback.format_exception(etype, evalue, tb)
327 332 exc_content = {
328 333 'status' : 'error',
329 334 'traceback' : stb,
330 335 'ename' : unicode(etype.__name__),
331 336 'evalue' : unicode(evalue),
332 337 'engine_info' : engine_info
333 338 }
334 339 return exc_content
335 340
336 341 def unwrap_exception(content):
337 342 err = RemoteError(content['ename'], content['evalue'],
338 343 ''.join(content['traceback']),
339 344 content.get('engine_info', {}))
340 345 return err
341 346
@@ -1,845 +1,850 b''
1 1 # encoding: utf-8
2 2 """
3 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 12 # Copyright (C) 2008-2011 The IPython Development Team
8 13 #
9 14 # Distributed under the terms of the BSD License. The full license is in
10 15 # the file COPYING, distributed as part of this software.
11 16 #-----------------------------------------------------------------------------
12 17
13 18 #-----------------------------------------------------------------------------
14 19 # Imports
15 20 #-----------------------------------------------------------------------------
16 21
17 22 import __main__
18 23
19 24 import os
20 25 import re
21 26 import shutil
22 27 import sys
23 28 import textwrap
24 29 from string import Formatter
25 30
26 31 from IPython.external.path import path
27 32 from IPython.testing.skipdoctest import skip_doctest_py3, skip_doctest
28 33 from IPython.utils import py3compat
29 34 from IPython.utils.io import nlprint
30 35 from IPython.utils.data import flatten
31 36
32 37 #-----------------------------------------------------------------------------
33 38 # Code
34 39 #-----------------------------------------------------------------------------
35 40
36 41 def unquote_ends(istr):
37 42 """Remove a single pair of quotes from the endpoints of a string."""
38 43
39 44 if not istr:
40 45 return istr
41 46 if (istr[0]=="'" and istr[-1]=="'") or \
42 47 (istr[0]=='"' and istr[-1]=='"'):
43 48 return istr[1:-1]
44 49 else:
45 50 return istr
46 51
47 52
48 53 class LSString(str):
49 54 """String derivative with a special access attributes.
50 55
51 56 These are normal strings, but with the special attributes:
52 57
53 58 .l (or .list) : value as list (split on newlines).
54 59 .n (or .nlstr): original value (the string itself).
55 60 .s (or .spstr): value as whitespace-separated string.
56 61 .p (or .paths): list of path objects
57 62
58 63 Any values which require transformations are computed only once and
59 64 cached.
60 65
61 66 Such strings are very useful to efficiently interact with the shell, which
62 67 typically only understands whitespace-separated options for commands."""
63 68
64 69 def get_list(self):
65 70 try:
66 71 return self.__list
67 72 except AttributeError:
68 73 self.__list = self.split('\n')
69 74 return self.__list
70 75
71 76 l = list = property(get_list)
72 77
73 78 def get_spstr(self):
74 79 try:
75 80 return self.__spstr
76 81 except AttributeError:
77 82 self.__spstr = self.replace('\n',' ')
78 83 return self.__spstr
79 84
80 85 s = spstr = property(get_spstr)
81 86
82 87 def get_nlstr(self):
83 88 return self
84 89
85 90 n = nlstr = property(get_nlstr)
86 91
87 92 def get_paths(self):
88 93 try:
89 94 return self.__paths
90 95 except AttributeError:
91 96 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
92 97 return self.__paths
93 98
94 99 p = paths = property(get_paths)
95 100
96 101 # FIXME: We need to reimplement type specific displayhook and then add this
97 102 # back as a custom printer. This should also be moved outside utils into the
98 103 # core.
99 104
100 105 # def print_lsstring(arg):
101 106 # """ Prettier (non-repr-like) and more informative printer for LSString """
102 107 # print "LSString (.p, .n, .l, .s available). Value:"
103 108 # print arg
104 109 #
105 110 #
106 111 # print_lsstring = result_display.when_type(LSString)(print_lsstring)
107 112
108 113
109 114 class SList(list):
110 115 """List derivative with a special access attributes.
111 116
112 117 These are normal lists, but with the special attributes:
113 118
114 119 .l (or .list) : value as list (the list itself).
115 120 .n (or .nlstr): value as a string, joined on newlines.
116 121 .s (or .spstr): value as a string, joined on spaces.
117 122 .p (or .paths): list of path objects
118 123
119 124 Any values which require transformations are computed only once and
120 125 cached."""
121 126
122 127 def get_list(self):
123 128 return self
124 129
125 130 l = list = property(get_list)
126 131
127 132 def get_spstr(self):
128 133 try:
129 134 return self.__spstr
130 135 except AttributeError:
131 136 self.__spstr = ' '.join(self)
132 137 return self.__spstr
133 138
134 139 s = spstr = property(get_spstr)
135 140
136 141 def get_nlstr(self):
137 142 try:
138 143 return self.__nlstr
139 144 except AttributeError:
140 145 self.__nlstr = '\n'.join(self)
141 146 return self.__nlstr
142 147
143 148 n = nlstr = property(get_nlstr)
144 149
145 150 def get_paths(self):
146 151 try:
147 152 return self.__paths
148 153 except AttributeError:
149 154 self.__paths = [path(p) for p in self if os.path.exists(p)]
150 155 return self.__paths
151 156
152 157 p = paths = property(get_paths)
153 158
154 159 def grep(self, pattern, prune = False, field = None):
155 160 """ Return all strings matching 'pattern' (a regex or callable)
156 161
157 162 This is case-insensitive. If prune is true, return all items
158 163 NOT matching the pattern.
159 164
160 165 If field is specified, the match must occur in the specified
161 166 whitespace-separated field.
162 167
163 168 Examples::
164 169
165 170 a.grep( lambda x: x.startswith('C') )
166 171 a.grep('Cha.*log', prune=1)
167 172 a.grep('chm', field=-1)
168 173 """
169 174
170 175 def match_target(s):
171 176 if field is None:
172 177 return s
173 178 parts = s.split()
174 179 try:
175 180 tgt = parts[field]
176 181 return tgt
177 182 except IndexError:
178 183 return ""
179 184
180 185 if isinstance(pattern, basestring):
181 186 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
182 187 else:
183 188 pred = pattern
184 189 if not prune:
185 190 return SList([el for el in self if pred(match_target(el))])
186 191 else:
187 192 return SList([el for el in self if not pred(match_target(el))])
188 193
189 194 def fields(self, *fields):
190 195 """ Collect whitespace-separated fields from string list
191 196
192 197 Allows quick awk-like usage of string lists.
193 198
194 199 Example data (in var a, created by 'a = !ls -l')::
195 200 -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
196 201 drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
197 202
198 203 a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
199 204 a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
200 205 (note the joining by space).
201 206 a.fields(-1) is ['ChangeLog', 'IPython']
202 207
203 208 IndexErrors are ignored.
204 209
205 210 Without args, fields() just split()'s the strings.
206 211 """
207 212 if len(fields) == 0:
208 213 return [el.split() for el in self]
209 214
210 215 res = SList()
211 216 for el in [f.split() for f in self]:
212 217 lineparts = []
213 218
214 219 for fd in fields:
215 220 try:
216 221 lineparts.append(el[fd])
217 222 except IndexError:
218 223 pass
219 224 if lineparts:
220 225 res.append(" ".join(lineparts))
221 226
222 227 return res
223 228
224 229 def sort(self,field= None, nums = False):
225 230 """ sort by specified fields (see fields())
226 231
227 232 Example::
228 233 a.sort(1, nums = True)
229 234
230 235 Sorts a by second field, in numerical order (so that 21 > 3)
231 236
232 237 """
233 238
234 239 #decorate, sort, undecorate
235 240 if field is not None:
236 241 dsu = [[SList([line]).fields(field), line] for line in self]
237 242 else:
238 243 dsu = [[line, line] for line in self]
239 244 if nums:
240 245 for i in range(len(dsu)):
241 246 numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
242 247 try:
243 248 n = int(numstr)
244 249 except ValueError:
245 250 n = 0;
246 251 dsu[i][0] = n
247 252
248 253
249 254 dsu.sort()
250 255 return SList([t[1] for t in dsu])
251 256
252 257
253 258 # FIXME: We need to reimplement type specific displayhook and then add this
254 259 # back as a custom printer. This should also be moved outside utils into the
255 260 # core.
256 261
257 262 # def print_slist(arg):
258 263 # """ Prettier (non-repr-like) and more informative printer for SList """
259 264 # print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
260 265 # if hasattr(arg, 'hideonce') and arg.hideonce:
261 266 # arg.hideonce = False
262 267 # return
263 268 #
264 269 # nlprint(arg)
265 270 #
266 271 # print_slist = result_display.when_type(SList)(print_slist)
267 272
268 273
269 274 def esc_quotes(strng):
270 275 """Return the input string with single and double quotes escaped out"""
271 276
272 277 return strng.replace('"','\\"').replace("'","\\'")
273 278
274 279
275 280 def qw(words,flat=0,sep=None,maxsplit=-1):
276 281 """Similar to Perl's qw() operator, but with some more options.
277 282
278 283 qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
279 284
280 285 words can also be a list itself, and with flat=1, the output will be
281 286 recursively flattened.
282 287
283 288 Examples:
284 289
285 290 >>> qw('1 2')
286 291 ['1', '2']
287 292
288 293 >>> qw(['a b','1 2',['m n','p q']])
289 294 [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
290 295
291 296 >>> qw(['a b','1 2',['m n','p q']],flat=1)
292 297 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
293 298 """
294 299
295 300 if isinstance(words, basestring):
296 301 return [word.strip() for word in words.split(sep,maxsplit)
297 302 if word and not word.isspace() ]
298 303 if flat:
299 304 return flatten(map(qw,words,[1]*len(words)))
300 305 return map(qw,words)
301 306
302 307
303 308 def qwflat(words,sep=None,maxsplit=-1):
304 309 """Calls qw(words) in flat mode. It's just a convenient shorthand."""
305 310 return qw(words,1,sep,maxsplit)
306 311
307 312
308 313 def qw_lol(indata):
309 314 """qw_lol('a b') -> [['a','b']],
310 315 otherwise it's just a call to qw().
311 316
312 317 We need this to make sure the modules_some keys *always* end up as a
313 318 list of lists."""
314 319
315 320 if isinstance(indata, basestring):
316 321 return [qw(indata)]
317 322 else:
318 323 return qw(indata)
319 324
320 325
321 326 def grep(pat,list,case=1):
322 327 """Simple minded grep-like function.
323 328 grep(pat,list) returns occurrences of pat in list, None on failure.
324 329
325 330 It only does simple string matching, with no support for regexps. Use the
326 331 option case=0 for case-insensitive matching."""
327 332
328 333 # This is pretty crude. At least it should implement copying only references
329 334 # to the original data in case it's big. Now it copies the data for output.
330 335 out=[]
331 336 if case:
332 337 for term in list:
333 338 if term.find(pat)>-1: out.append(term)
334 339 else:
335 340 lpat=pat.lower()
336 341 for term in list:
337 342 if term.lower().find(lpat)>-1: out.append(term)
338 343
339 344 if len(out): return out
340 345 else: return None
341 346
342 347
343 348 def dgrep(pat,*opts):
344 349 """Return grep() on dir()+dir(__builtins__).
345 350
346 351 A very common use of grep() when working interactively."""
347 352
348 353 return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
349 354
350 355
351 356 def idgrep(pat):
352 357 """Case-insensitive dgrep()"""
353 358
354 359 return dgrep(pat,0)
355 360
356 361
357 362 def igrep(pat,list):
358 363 """Synonym for case-insensitive grep."""
359 364
360 365 return grep(pat,list,case=0)
361 366
362 367
363 368 def indent(instr,nspaces=4, ntabs=0, flatten=False):
364 369 """Indent a string a given number of spaces or tabstops.
365 370
366 371 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
367 372
368 373 Parameters
369 374 ----------
370 375
371 376 instr : basestring
372 377 The string to be indented.
373 378 nspaces : int (default: 4)
374 379 The number of spaces to be indented.
375 380 ntabs : int (default: 0)
376 381 The number of tabs to be indented.
377 382 flatten : bool (default: False)
378 383 Whether to scrub existing indentation. If True, all lines will be
379 384 aligned to the same indentation. If False, existing indentation will
380 385 be strictly increased.
381 386
382 387 Returns
383 388 -------
384 389
385 390 str|unicode : string indented by ntabs and nspaces.
386 391
387 392 """
388 393 if instr is None:
389 394 return
390 395 ind = '\t'*ntabs+' '*nspaces
391 396 if flatten:
392 397 pat = re.compile(r'^\s*', re.MULTILINE)
393 398 else:
394 399 pat = re.compile(r'^', re.MULTILINE)
395 400 outstr = re.sub(pat, ind, instr)
396 401 if outstr.endswith(os.linesep+ind):
397 402 return outstr[:-len(ind)]
398 403 else:
399 404 return outstr
400 405
401 406 def native_line_ends(filename,backup=1):
402 407 """Convert (in-place) a file to line-ends native to the current OS.
403 408
404 409 If the optional backup argument is given as false, no backup of the
405 410 original file is left. """
406 411
407 412 backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
408 413
409 414 bak_filename = filename + backup_suffixes[os.name]
410 415
411 416 original = open(filename).read()
412 417 shutil.copy2(filename,bak_filename)
413 418 try:
414 419 new = open(filename,'wb')
415 420 new.write(os.linesep.join(original.splitlines()))
416 421 new.write(os.linesep) # ALWAYS put an eol at the end of the file
417 422 new.close()
418 423 except:
419 424 os.rename(bak_filename,filename)
420 425 if not backup:
421 426 try:
422 427 os.remove(bak_filename)
423 428 except:
424 429 pass
425 430
426 431
427 432 def list_strings(arg):
428 433 """Always return a list of strings, given a string or list of strings
429 434 as input.
430 435
431 436 :Examples:
432 437
433 438 In [7]: list_strings('A single string')
434 439 Out[7]: ['A single string']
435 440
436 441 In [8]: list_strings(['A single string in a list'])
437 442 Out[8]: ['A single string in a list']
438 443
439 444 In [9]: list_strings(['A','list','of','strings'])
440 445 Out[9]: ['A', 'list', 'of', 'strings']
441 446 """
442 447
443 448 if isinstance(arg,basestring): return [arg]
444 449 else: return arg
445 450
446 451
447 452 def marquee(txt='',width=78,mark='*'):
448 453 """Return the input string centered in a 'marquee'.
449 454
450 455 :Examples:
451 456
452 457 In [16]: marquee('A test',40)
453 458 Out[16]: '**************** A test ****************'
454 459
455 460 In [17]: marquee('A test',40,'-')
456 461 Out[17]: '---------------- A test ----------------'
457 462
458 463 In [18]: marquee('A test',40,' ')
459 464 Out[18]: ' A test '
460 465
461 466 """
462 467 if not txt:
463 468 return (mark*width)[:width]
464 469 nmark = (width-len(txt)-2)//len(mark)//2
465 470 if nmark < 0: nmark =0
466 471 marks = mark*nmark
467 472 return '%s %s %s' % (marks,txt,marks)
468 473
469 474
470 475 ini_spaces_re = re.compile(r'^(\s+)')
471 476
472 477 def num_ini_spaces(strng):
473 478 """Return the number of initial spaces in a string"""
474 479
475 480 ini_spaces = ini_spaces_re.match(strng)
476 481 if ini_spaces:
477 482 return ini_spaces.end()
478 483 else:
479 484 return 0
480 485
481 486
482 487 def format_screen(strng):
483 488 """Format a string for screen printing.
484 489
485 490 This removes some latex-type format codes."""
486 491 # Paragraph continue
487 492 par_re = re.compile(r'\\$',re.MULTILINE)
488 493 strng = par_re.sub('',strng)
489 494 return strng
490 495
491 496
492 497 def dedent(text):
493 498 """Equivalent of textwrap.dedent that ignores unindented first line.
494 499
495 500 This means it will still dedent strings like:
496 501 '''foo
497 502 is a bar
498 503 '''
499 504
500 505 For use in wrap_paragraphs.
501 506 """
502 507
503 508 if text.startswith('\n'):
504 509 # text starts with blank line, don't ignore the first line
505 510 return textwrap.dedent(text)
506 511
507 512 # split first line
508 513 splits = text.split('\n',1)
509 514 if len(splits) == 1:
510 515 # only one line
511 516 return textwrap.dedent(text)
512 517
513 518 first, rest = splits
514 519 # dedent everything but the first line
515 520 rest = textwrap.dedent(rest)
516 521 return '\n'.join([first, rest])
517 522
518 523
519 524 def wrap_paragraphs(text, ncols=80):
520 525 """Wrap multiple paragraphs to fit a specified width.
521 526
522 527 This is equivalent to textwrap.wrap, but with support for multiple
523 528 paragraphs, as separated by empty lines.
524 529
525 530 Returns
526 531 -------
527 532
528 533 list of complete paragraphs, wrapped to fill `ncols` columns.
529 534 """
530 535 paragraph_re = re.compile(r'\n(\s*\n)+', re.MULTILINE)
531 536 text = dedent(text).strip()
532 537 paragraphs = paragraph_re.split(text)[::2] # every other entry is space
533 538 out_ps = []
534 539 indent_re = re.compile(r'\n\s+', re.MULTILINE)
535 540 for p in paragraphs:
536 541 # presume indentation that survives dedent is meaningful formatting,
537 542 # so don't fill unless text is flush.
538 543 if indent_re.search(p) is None:
539 544 # wrap paragraph
540 545 p = textwrap.fill(p, ncols)
541 546 out_ps.append(p)
542 547 return out_ps
543 548
544 549
545 550 def long_substr(data):
546 551 """Return the longest common substring in a list of strings.
547 552
548 553 Credit: http://stackoverflow.com/questions/2892931/longest-common-substring-from-more-than-two-strings-python
549 554 """
550 555 substr = ''
551 556 if len(data) > 1 and len(data[0]) > 0:
552 557 for i in range(len(data[0])):
553 558 for j in range(len(data[0])-i+1):
554 559 if j > len(substr) and all(data[0][i:i+j] in x for x in data):
555 560 substr = data[0][i:i+j]
556 561 elif len(data) == 1:
557 562 substr = data[0]
558 563 return substr
559 564
560 565
561 566 def strip_email_quotes(text):
562 567 """Strip leading email quotation characters ('>').
563 568
564 569 Removes any combination of leading '>' interspersed with whitespace that
565 570 appears *identically* in all lines of the input text.
566 571
567 572 Parameters
568 573 ----------
569 574 text : str
570 575
571 576 Examples
572 577 --------
573 578
574 579 Simple uses::
575 580
576 581 In [2]: strip_email_quotes('> > text')
577 582 Out[2]: 'text'
578 583
579 584 In [3]: strip_email_quotes('> > text\\n> > more')
580 585 Out[3]: 'text\\nmore'
581 586
582 587 Note how only the common prefix that appears in all lines is stripped::
583 588
584 589 In [4]: strip_email_quotes('> > text\\n> > more\\n> more...')
585 590 Out[4]: '> text\\n> more\\nmore...'
586 591
587 592 So if any line has no quote marks ('>') , then none are stripped from any
588 593 of them ::
589 594
590 595 In [5]: strip_email_quotes('> > text\\n> > more\\nlast different')
591 596 Out[5]: '> > text\\n> > more\\nlast different'
592 597 """
593 598 lines = text.splitlines()
594 599 matches = set()
595 600 for line in lines:
596 601 prefix = re.match(r'^(\s*>[ >]*)', line)
597 602 if prefix:
598 603 matches.add(prefix.group(1))
599 604 else:
600 605 break
601 606 else:
602 607 prefix = long_substr(list(matches))
603 608 if prefix:
604 609 strip = len(prefix)
605 610 text = '\n'.join([ ln[strip:] for ln in lines])
606 611 return text
607 612
608 613
609 614 class EvalFormatter(Formatter):
610 615 """A String Formatter that allows evaluation of simple expressions.
611 616
612 617 Note that this version interprets a : as specifying a format string (as per
613 618 standard string formatting), so if slicing is required, you must explicitly
614 619 create a slice.
615 620
616 621 This is to be used in templating cases, such as the parallel batch
617 622 script templates, where simple arithmetic on arguments is useful.
618 623
619 624 Examples
620 625 --------
621 626
622 627 In [1]: f = EvalFormatter()
623 628 In [2]: f.format('{n//4}', n=8)
624 629 Out [2]: '2'
625 630
626 631 In [3]: f.format("{greeting[slice(2,4)]}", greeting="Hello")
627 632 Out [3]: 'll'
628 633 """
629 634 def get_field(self, name, args, kwargs):
630 635 v = eval(name, kwargs)
631 636 return v, name
632 637
633 638
634 639 @skip_doctest_py3
635 640 class FullEvalFormatter(Formatter):
636 641 """A String Formatter that allows evaluation of simple expressions.
637 642
638 643 Any time a format key is not found in the kwargs,
639 644 it will be tried as an expression in the kwargs namespace.
640 645
641 646 Note that this version allows slicing using [1:2], so you cannot specify
642 647 a format string. Use :class:`EvalFormatter` to permit format strings.
643 648
644 649 Examples
645 650 --------
646 651
647 652 In [1]: f = FullEvalFormatter()
648 653 In [2]: f.format('{n//4}', n=8)
649 654 Out[2]: u'2'
650 655
651 656 In [3]: f.format('{list(range(5))[2:4]}')
652 657 Out[3]: u'[2, 3]'
653 658
654 659 In [4]: f.format('{3*2}')
655 660 Out[4]: u'6'
656 661 """
657 662 # copied from Formatter._vformat with minor changes to allow eval
658 663 # and replace the format_spec code with slicing
659 664 def _vformat(self, format_string, args, kwargs, used_args, recursion_depth):
660 665 if recursion_depth < 0:
661 666 raise ValueError('Max string recursion exceeded')
662 667 result = []
663 668 for literal_text, field_name, format_spec, conversion in \
664 669 self.parse(format_string):
665 670
666 671 # output the literal text
667 672 if literal_text:
668 673 result.append(literal_text)
669 674
670 675 # if there's a field, output it
671 676 if field_name is not None:
672 677 # this is some markup, find the object and do
673 678 # the formatting
674 679
675 680 if format_spec:
676 681 # override format spec, to allow slicing:
677 682 field_name = ':'.join([field_name, format_spec])
678 683
679 684 # eval the contents of the field for the object
680 685 # to be formatted
681 686 obj = eval(field_name, kwargs)
682 687
683 688 # do any conversion on the resulting object
684 689 obj = self.convert_field(obj, conversion)
685 690
686 691 # format the object and append to the result
687 692 result.append(self.format_field(obj, ''))
688 693
689 694 return u''.join(py3compat.cast_unicode(s) for s in result)
690 695
691 696
692 697 @skip_doctest_py3
693 698 class DollarFormatter(FullEvalFormatter):
694 699 """Formatter allowing Itpl style $foo replacement, for names and attribute
695 700 access only. Standard {foo} replacement also works, and allows full
696 701 evaluation of its arguments.
697 702
698 703 Examples
699 704 --------
700 705 In [1]: f = DollarFormatter()
701 706 In [2]: f.format('{n//4}', n=8)
702 707 Out[2]: u'2'
703 708
704 709 In [3]: f.format('23 * 76 is $result', result=23*76)
705 710 Out[3]: u'23 * 76 is 1748'
706 711
707 712 In [4]: f.format('$a or {b}', a=1, b=2)
708 713 Out[4]: u'1 or 2'
709 714 """
710 715 _dollar_pattern = re.compile("(.*?)\$(\$?[\w\.]+)")
711 716 def parse(self, fmt_string):
712 717 for literal_txt, field_name, format_spec, conversion \
713 718 in Formatter.parse(self, fmt_string):
714 719
715 720 # Find $foo patterns in the literal text.
716 721 continue_from = 0
717 722 txt = ""
718 723 for m in self._dollar_pattern.finditer(literal_txt):
719 724 new_txt, new_field = m.group(1,2)
720 725 # $$foo --> $foo
721 726 if new_field.startswith("$"):
722 727 txt += new_txt + new_field
723 728 else:
724 729 yield (txt + new_txt, new_field, "", None)
725 730 txt = ""
726 731 continue_from = m.end()
727 732
728 733 # Re-yield the {foo} style pattern
729 734 yield (txt + literal_txt[continue_from:], field_name, format_spec, conversion)
730 735
731 736 #-----------------------------------------------------------------------------
732 737 # Utils to columnize a list of string
733 738 #-----------------------------------------------------------------------------
734 739
735 740 def _chunks(l, n):
736 741 """Yield successive n-sized chunks from l."""
737 742 for i in xrange(0, len(l), n):
738 743 yield l[i:i+n]
739 744
740 745
741 746 def _find_optimal(rlist , separator_size=2 , displaywidth=80):
742 747 """Calculate optimal info to columnize a list of string"""
743 748 for nrow in range(1, len(rlist)+1) :
744 749 chk = map(max,_chunks(rlist, nrow))
745 750 sumlength = sum(chk)
746 751 ncols = len(chk)
747 752 if sumlength+separator_size*(ncols-1) <= displaywidth :
748 753 break;
749 754 return {'columns_numbers' : ncols,
750 755 'optimal_separator_width':(displaywidth - sumlength)/(ncols-1) if (ncols -1) else 0,
751 756 'rows_numbers' : nrow,
752 757 'columns_width' : chk
753 758 }
754 759
755 760
756 761 def _get_or_default(mylist, i, default=None):
757 762 """return list item number, or default if don't exist"""
758 763 if i >= len(mylist):
759 764 return default
760 765 else :
761 766 return mylist[i]
762 767
763 768
764 769 @skip_doctest
765 770 def compute_item_matrix(items, empty=None, *args, **kwargs) :
766 771 """Returns a nested list, and info to columnize items
767 772
768 773 Parameters :
769 774 ------------
770 775
771 776 items :
772 777 list of strings to columize
773 778 empty : (default None)
774 779 default value to fill list if needed
775 780 separator_size : int (default=2)
776 781 How much caracters will be used as a separation between each columns.
777 782 displaywidth : int (default=80)
778 783 The width of the area onto wich the columns should enter
779 784
780 785 Returns :
781 786 ---------
782 787
783 788 Returns a tuple of (strings_matrix, dict_info)
784 789
785 790 strings_matrix :
786 791
787 792 nested list of string, the outer most list contains as many list as
788 793 rows, the innermost lists have each as many element as colums. If the
789 794 total number of elements in `items` does not equal the product of
790 795 rows*columns, the last element of some lists are filled with `None`.
791 796
792 797 dict_info :
793 798 some info to make columnize easier:
794 799
795 800 columns_numbers : number of columns
796 801 rows_numbers : number of rows
797 802 columns_width : list of with of each columns
798 803 optimal_separator_width : best separator width between columns
799 804
800 805 Exemple :
801 806 ---------
802 807
803 808 In [1]: l = ['aaa','b','cc','d','eeeee','f','g','h','i','j','k','l']
804 809 ...: compute_item_matrix(l,displaywidth=12)
805 810 Out[1]:
806 811 ([['aaa', 'f', 'k'],
807 812 ['b', 'g', 'l'],
808 813 ['cc', 'h', None],
809 814 ['d', 'i', None],
810 815 ['eeeee', 'j', None]],
811 816 {'columns_numbers': 3,
812 817 'columns_width': [5, 1, 1],
813 818 'optimal_separator_width': 2,
814 819 'rows_numbers': 5})
815 820
816 821 """
817 822 info = _find_optimal(map(len, items), *args, **kwargs)
818 823 nrow, ncol = info['rows_numbers'], info['columns_numbers']
819 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 827 def columnize(items, separator=' ', displaywidth=80):
823 828 """ Transform a list of strings into a single string with columns.
824 829
825 830 Parameters
826 831 ----------
827 832 items : sequence of strings
828 833 The strings to process.
829 834
830 835 separator : str, optional [default is two spaces]
831 836 The string that separates columns.
832 837
833 838 displaywidth : int, optional [default is 80]
834 839 Width of the display in number of characters.
835 840
836 841 Returns
837 842 -------
838 843 The formatted string.
839 844 """
840 845 if not items :
841 846 return '\n'
842 847 matrix, info = compute_item_matrix(items, separator_size=len(separator), displaywidth=displaywidth)
843 848 fmatrix = [filter(None, x) for x in matrix]
844 849 sjoin = lambda x : separator.join([ y.ljust(w, ' ') for y, w in zip(x, info['columns_width'])])
845 850 return '\n'.join(map(sjoin, fmatrix))+'\n'
@@ -1,1434 +1,1439 b''
1 1 # encoding: utf-8
2 2 """
3 3 A lightweight Traits like module.
4 4
5 5 This is designed to provide a lightweight, simple, pure Python version of
6 6 many of the capabilities of enthought.traits. This includes:
7 7
8 8 * Validation
9 9 * Type specification with defaults
10 10 * Static and dynamic notification
11 11 * Basic predefined types
12 12 * An API that is similar to enthought.traits
13 13
14 14 We don't support:
15 15
16 16 * Delegation
17 17 * Automatic GUI generation
18 18 * A full set of trait types. Most importantly, we don't provide container
19 19 traits (list, dict, tuple) that can trigger notifications if their
20 20 contents change.
21 21 * API compatibility with enthought.traits
22 22
23 23 There are also some important difference in our design:
24 24
25 25 * enthought.traits does not validate default values. We do.
26 26
27 27 We choose to create this module because we need these capabilities, but
28 28 we need them to be pure Python so they work in all Python implementations,
29 29 including Jython and IronPython.
30 30
31 Inheritance diagram:
32
33 .. inheritance-diagram:: IPython.utils.traitlets
34 :parts: 3
35
31 36 Authors:
32 37
33 38 * Brian Granger
34 39 * Enthought, Inc. Some of the code in this file comes from enthought.traits
35 40 and is licensed under the BSD license. Also, many of the ideas also come
36 41 from enthought.traits even though our implementation is very different.
37 42 """
38 43
39 44 #-----------------------------------------------------------------------------
40 45 # Copyright (C) 2008-2011 The IPython Development Team
41 46 #
42 47 # Distributed under the terms of the BSD License. The full license is in
43 48 # the file COPYING, distributed as part of this software.
44 49 #-----------------------------------------------------------------------------
45 50
46 51 #-----------------------------------------------------------------------------
47 52 # Imports
48 53 #-----------------------------------------------------------------------------
49 54
50 55
51 56 import inspect
52 57 import re
53 58 import sys
54 59 import types
55 60 from types import FunctionType
56 61 try:
57 62 from types import ClassType, InstanceType
58 63 ClassTypes = (ClassType, type)
59 64 except:
60 65 ClassTypes = (type,)
61 66
62 67 from .importstring import import_item
63 68 from IPython.utils import py3compat
64 69
65 70 SequenceTypes = (list, tuple, set, frozenset)
66 71
67 72 #-----------------------------------------------------------------------------
68 73 # Basic classes
69 74 #-----------------------------------------------------------------------------
70 75
71 76
72 77 class NoDefaultSpecified ( object ): pass
73 78 NoDefaultSpecified = NoDefaultSpecified()
74 79
75 80
76 81 class Undefined ( object ): pass
77 82 Undefined = Undefined()
78 83
79 84 class TraitError(Exception):
80 85 pass
81 86
82 87 #-----------------------------------------------------------------------------
83 88 # Utilities
84 89 #-----------------------------------------------------------------------------
85 90
86 91
87 92 def class_of ( object ):
88 93 """ Returns a string containing the class name of an object with the
89 94 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
90 95 'a PlotValue').
91 96 """
92 97 if isinstance( object, basestring ):
93 98 return add_article( object )
94 99
95 100 return add_article( object.__class__.__name__ )
96 101
97 102
98 103 def add_article ( name ):
99 104 """ Returns a string containing the correct indefinite article ('a' or 'an')
100 105 prefixed to the specified string.
101 106 """
102 107 if name[:1].lower() in 'aeiou':
103 108 return 'an ' + name
104 109
105 110 return 'a ' + name
106 111
107 112
108 113 def repr_type(obj):
109 114 """ Return a string representation of a value and its type for readable
110 115 error messages.
111 116 """
112 117 the_type = type(obj)
113 118 if (not py3compat.PY3) and the_type is InstanceType:
114 119 # Old-style class.
115 120 the_type = obj.__class__
116 121 msg = '%r %r' % (obj, the_type)
117 122 return msg
118 123
119 124
120 125 def is_trait(t):
121 126 """ Returns whether the given value is an instance or subclass of TraitType.
122 127 """
123 128 return (isinstance(t, TraitType) or
124 129 (isinstance(t, type) and issubclass(t, TraitType)))
125 130
126 131
127 132 def parse_notifier_name(name):
128 133 """Convert the name argument to a list of names.
129 134
130 135 Examples
131 136 --------
132 137
133 138 >>> parse_notifier_name('a')
134 139 ['a']
135 140 >>> parse_notifier_name(['a','b'])
136 141 ['a', 'b']
137 142 >>> parse_notifier_name(None)
138 143 ['anytrait']
139 144 """
140 145 if isinstance(name, str):
141 146 return [name]
142 147 elif name is None:
143 148 return ['anytrait']
144 149 elif isinstance(name, (list, tuple)):
145 150 for n in name:
146 151 assert isinstance(n, str), "names must be strings"
147 152 return name
148 153
149 154
150 155 class _SimpleTest:
151 156 def __init__ ( self, value ): self.value = value
152 157 def __call__ ( self, test ):
153 158 return test == self.value
154 159 def __repr__(self):
155 160 return "<SimpleTest(%r)" % self.value
156 161 def __str__(self):
157 162 return self.__repr__()
158 163
159 164
160 165 def getmembers(object, predicate=None):
161 166 """A safe version of inspect.getmembers that handles missing attributes.
162 167
163 168 This is useful when there are descriptor based attributes that for
164 169 some reason raise AttributeError even though they exist. This happens
165 170 in zope.inteface with the __provides__ attribute.
166 171 """
167 172 results = []
168 173 for key in dir(object):
169 174 try:
170 175 value = getattr(object, key)
171 176 except AttributeError:
172 177 pass
173 178 else:
174 179 if not predicate or predicate(value):
175 180 results.append((key, value))
176 181 results.sort()
177 182 return results
178 183
179 184
180 185 #-----------------------------------------------------------------------------
181 186 # Base TraitType for all traits
182 187 #-----------------------------------------------------------------------------
183 188
184 189
185 190 class TraitType(object):
186 191 """A base class for all trait descriptors.
187 192
188 193 Notes
189 194 -----
190 195 Our implementation of traits is based on Python's descriptor
191 196 prototol. This class is the base class for all such descriptors. The
192 197 only magic we use is a custom metaclass for the main :class:`HasTraits`
193 198 class that does the following:
194 199
195 200 1. Sets the :attr:`name` attribute of every :class:`TraitType`
196 201 instance in the class dict to the name of the attribute.
197 202 2. Sets the :attr:`this_class` attribute of every :class:`TraitType`
198 203 instance in the class dict to the *class* that declared the trait.
199 204 This is used by the :class:`This` trait to allow subclasses to
200 205 accept superclasses for :class:`This` values.
201 206 """
202 207
203 208
204 209 metadata = {}
205 210 default_value = Undefined
206 211 info_text = 'any value'
207 212
208 213 def __init__(self, default_value=NoDefaultSpecified, **metadata):
209 214 """Create a TraitType.
210 215 """
211 216 if default_value is not NoDefaultSpecified:
212 217 self.default_value = default_value
213 218
214 219 if len(metadata) > 0:
215 220 if len(self.metadata) > 0:
216 221 self._metadata = self.metadata.copy()
217 222 self._metadata.update(metadata)
218 223 else:
219 224 self._metadata = metadata
220 225 else:
221 226 self._metadata = self.metadata
222 227
223 228 self.init()
224 229
225 230 def init(self):
226 231 pass
227 232
228 233 def get_default_value(self):
229 234 """Create a new instance of the default value."""
230 235 return self.default_value
231 236
232 237 def instance_init(self, obj):
233 238 """This is called by :meth:`HasTraits.__new__` to finish init'ing.
234 239
235 240 Some stages of initialization must be delayed until the parent
236 241 :class:`HasTraits` instance has been created. This method is
237 242 called in :meth:`HasTraits.__new__` after the instance has been
238 243 created.
239 244
240 245 This method trigger the creation and validation of default values
241 246 and also things like the resolution of str given class names in
242 247 :class:`Type` and :class`Instance`.
243 248
244 249 Parameters
245 250 ----------
246 251 obj : :class:`HasTraits` instance
247 252 The parent :class:`HasTraits` instance that has just been
248 253 created.
249 254 """
250 255 self.set_default_value(obj)
251 256
252 257 def set_default_value(self, obj):
253 258 """Set the default value on a per instance basis.
254 259
255 260 This method is called by :meth:`instance_init` to create and
256 261 validate the default value. The creation and validation of
257 262 default values must be delayed until the parent :class:`HasTraits`
258 263 class has been instantiated.
259 264 """
260 265 # Check for a deferred initializer defined in the same class as the
261 266 # trait declaration or above.
262 267 mro = type(obj).mro()
263 268 meth_name = '_%s_default' % self.name
264 269 for cls in mro[:mro.index(self.this_class)+1]:
265 270 if meth_name in cls.__dict__:
266 271 break
267 272 else:
268 273 # We didn't find one. Do static initialization.
269 274 dv = self.get_default_value()
270 275 newdv = self._validate(obj, dv)
271 276 obj._trait_values[self.name] = newdv
272 277 return
273 278 # Complete the dynamic initialization.
274 279 obj._trait_dyn_inits[self.name] = cls.__dict__[meth_name]
275 280
276 281 def __get__(self, obj, cls=None):
277 282 """Get the value of the trait by self.name for the instance.
278 283
279 284 Default values are instantiated when :meth:`HasTraits.__new__`
280 285 is called. Thus by the time this method gets called either the
281 286 default value or a user defined value (they called :meth:`__set__`)
282 287 is in the :class:`HasTraits` instance.
283 288 """
284 289 if obj is None:
285 290 return self
286 291 else:
287 292 try:
288 293 value = obj._trait_values[self.name]
289 294 except KeyError:
290 295 # Check for a dynamic initializer.
291 296 if self.name in obj._trait_dyn_inits:
292 297 value = obj._trait_dyn_inits[self.name](obj)
293 298 # FIXME: Do we really validate here?
294 299 value = self._validate(obj, value)
295 300 obj._trait_values[self.name] = value
296 301 return value
297 302 else:
298 303 raise TraitError('Unexpected error in TraitType: '
299 304 'both default value and dynamic initializer are '
300 305 'absent.')
301 306 except Exception:
302 307 # HasTraits should call set_default_value to populate
303 308 # this. So this should never be reached.
304 309 raise TraitError('Unexpected error in TraitType: '
305 310 'default value not set properly')
306 311 else:
307 312 return value
308 313
309 314 def __set__(self, obj, value):
310 315 new_value = self._validate(obj, value)
311 316 old_value = self.__get__(obj)
312 317 obj._trait_values[self.name] = new_value
313 318 if old_value != new_value:
314 319 obj._notify_trait(self.name, old_value, new_value)
315 320
316 321 def _validate(self, obj, value):
317 322 if hasattr(self, 'validate'):
318 323 return self.validate(obj, value)
319 324 elif hasattr(self, 'is_valid_for'):
320 325 valid = self.is_valid_for(value)
321 326 if valid:
322 327 return value
323 328 else:
324 329 raise TraitError('invalid value for type: %r' % value)
325 330 elif hasattr(self, 'value_for'):
326 331 return self.value_for(value)
327 332 else:
328 333 return value
329 334
330 335 def info(self):
331 336 return self.info_text
332 337
333 338 def error(self, obj, value):
334 339 if obj is not None:
335 340 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
336 341 % (self.name, class_of(obj),
337 342 self.info(), repr_type(value))
338 343 else:
339 344 e = "The '%s' trait must be %s, but a value of %r was specified." \
340 345 % (self.name, self.info(), repr_type(value))
341 346 raise TraitError(e)
342 347
343 348 def get_metadata(self, key):
344 349 return getattr(self, '_metadata', {}).get(key, None)
345 350
346 351 def set_metadata(self, key, value):
347 352 getattr(self, '_metadata', {})[key] = value
348 353
349 354
350 355 #-----------------------------------------------------------------------------
351 356 # The HasTraits implementation
352 357 #-----------------------------------------------------------------------------
353 358
354 359
355 360 class MetaHasTraits(type):
356 361 """A metaclass for HasTraits.
357 362
358 363 This metaclass makes sure that any TraitType class attributes are
359 364 instantiated and sets their name attribute.
360 365 """
361 366
362 367 def __new__(mcls, name, bases, classdict):
363 368 """Create the HasTraits class.
364 369
365 370 This instantiates all TraitTypes in the class dict and sets their
366 371 :attr:`name` attribute.
367 372 """
368 373 # print "MetaHasTraitlets (mcls, name): ", mcls, name
369 374 # print "MetaHasTraitlets (bases): ", bases
370 375 # print "MetaHasTraitlets (classdict): ", classdict
371 376 for k,v in classdict.iteritems():
372 377 if isinstance(v, TraitType):
373 378 v.name = k
374 379 elif inspect.isclass(v):
375 380 if issubclass(v, TraitType):
376 381 vinst = v()
377 382 vinst.name = k
378 383 classdict[k] = vinst
379 384 return super(MetaHasTraits, mcls).__new__(mcls, name, bases, classdict)
380 385
381 386 def __init__(cls, name, bases, classdict):
382 387 """Finish initializing the HasTraits class.
383 388
384 389 This sets the :attr:`this_class` attribute of each TraitType in the
385 390 class dict to the newly created class ``cls``.
386 391 """
387 392 for k, v in classdict.iteritems():
388 393 if isinstance(v, TraitType):
389 394 v.this_class = cls
390 395 super(MetaHasTraits, cls).__init__(name, bases, classdict)
391 396
392 397 class HasTraits(object):
393 398
394 399 __metaclass__ = MetaHasTraits
395 400
396 401 def __new__(cls, **kw):
397 402 # This is needed because in Python 2.6 object.__new__ only accepts
398 403 # the cls argument.
399 404 new_meth = super(HasTraits, cls).__new__
400 405 if new_meth is object.__new__:
401 406 inst = new_meth(cls)
402 407 else:
403 408 inst = new_meth(cls, **kw)
404 409 inst._trait_values = {}
405 410 inst._trait_notifiers = {}
406 411 inst._trait_dyn_inits = {}
407 412 # Here we tell all the TraitType instances to set their default
408 413 # values on the instance.
409 414 for key in dir(cls):
410 415 # Some descriptors raise AttributeError like zope.interface's
411 416 # __provides__ attributes even though they exist. This causes
412 417 # AttributeErrors even though they are listed in dir(cls).
413 418 try:
414 419 value = getattr(cls, key)
415 420 except AttributeError:
416 421 pass
417 422 else:
418 423 if isinstance(value, TraitType):
419 424 value.instance_init(inst)
420 425
421 426 return inst
422 427
423 428 def __init__(self, **kw):
424 429 # Allow trait values to be set using keyword arguments.
425 430 # We need to use setattr for this to trigger validation and
426 431 # notifications.
427 432 for key, value in kw.iteritems():
428 433 setattr(self, key, value)
429 434
430 435 def _notify_trait(self, name, old_value, new_value):
431 436
432 437 # First dynamic ones
433 438 callables = self._trait_notifiers.get(name,[])
434 439 more_callables = self._trait_notifiers.get('anytrait',[])
435 440 callables.extend(more_callables)
436 441
437 442 # Now static ones
438 443 try:
439 444 cb = getattr(self, '_%s_changed' % name)
440 445 except:
441 446 pass
442 447 else:
443 448 callables.append(cb)
444 449
445 450 # Call them all now
446 451 for c in callables:
447 452 # Traits catches and logs errors here. I allow them to raise
448 453 if callable(c):
449 454 argspec = inspect.getargspec(c)
450 455 nargs = len(argspec[0])
451 456 # Bound methods have an additional 'self' argument
452 457 # I don't know how to treat unbound methods, but they
453 458 # can't really be used for callbacks.
454 459 if isinstance(c, types.MethodType):
455 460 offset = -1
456 461 else:
457 462 offset = 0
458 463 if nargs + offset == 0:
459 464 c()
460 465 elif nargs + offset == 1:
461 466 c(name)
462 467 elif nargs + offset == 2:
463 468 c(name, new_value)
464 469 elif nargs + offset == 3:
465 470 c(name, old_value, new_value)
466 471 else:
467 472 raise TraitError('a trait changed callback '
468 473 'must have 0-3 arguments.')
469 474 else:
470 475 raise TraitError('a trait changed callback '
471 476 'must be callable.')
472 477
473 478
474 479 def _add_notifiers(self, handler, name):
475 480 if name not in self._trait_notifiers:
476 481 nlist = []
477 482 self._trait_notifiers[name] = nlist
478 483 else:
479 484 nlist = self._trait_notifiers[name]
480 485 if handler not in nlist:
481 486 nlist.append(handler)
482 487
483 488 def _remove_notifiers(self, handler, name):
484 489 if name in self._trait_notifiers:
485 490 nlist = self._trait_notifiers[name]
486 491 try:
487 492 index = nlist.index(handler)
488 493 except ValueError:
489 494 pass
490 495 else:
491 496 del nlist[index]
492 497
493 498 def on_trait_change(self, handler, name=None, remove=False):
494 499 """Setup a handler to be called when a trait changes.
495 500
496 501 This is used to setup dynamic notifications of trait changes.
497 502
498 503 Static handlers can be created by creating methods on a HasTraits
499 504 subclass with the naming convention '_[traitname]_changed'. Thus,
500 505 to create static handler for the trait 'a', create the method
501 506 _a_changed(self, name, old, new) (fewer arguments can be used, see
502 507 below).
503 508
504 509 Parameters
505 510 ----------
506 511 handler : callable
507 512 A callable that is called when a trait changes. Its
508 513 signature can be handler(), handler(name), handler(name, new)
509 514 or handler(name, old, new).
510 515 name : list, str, None
511 516 If None, the handler will apply to all traits. If a list
512 517 of str, handler will apply to all names in the list. If a
513 518 str, the handler will apply just to that name.
514 519 remove : bool
515 520 If False (the default), then install the handler. If True
516 521 then unintall it.
517 522 """
518 523 if remove:
519 524 names = parse_notifier_name(name)
520 525 for n in names:
521 526 self._remove_notifiers(handler, n)
522 527 else:
523 528 names = parse_notifier_name(name)
524 529 for n in names:
525 530 self._add_notifiers(handler, n)
526 531
527 532 @classmethod
528 533 def class_trait_names(cls, **metadata):
529 534 """Get a list of all the names of this classes traits.
530 535
531 536 This method is just like the :meth:`trait_names` method, but is unbound.
532 537 """
533 538 return cls.class_traits(**metadata).keys()
534 539
535 540 @classmethod
536 541 def class_traits(cls, **metadata):
537 542 """Get a list of all the traits of this class.
538 543
539 544 This method is just like the :meth:`traits` method, but is unbound.
540 545
541 546 The TraitTypes returned don't know anything about the values
542 547 that the various HasTrait's instances are holding.
543 548
544 549 This follows the same algorithm as traits does and does not allow
545 550 for any simple way of specifying merely that a metadata name
546 551 exists, but has any value. This is because get_metadata returns
547 552 None if a metadata key doesn't exist.
548 553 """
549 554 traits = dict([memb for memb in getmembers(cls) if \
550 555 isinstance(memb[1], TraitType)])
551 556
552 557 if len(metadata) == 0:
553 558 return traits
554 559
555 560 for meta_name, meta_eval in metadata.items():
556 561 if type(meta_eval) is not FunctionType:
557 562 metadata[meta_name] = _SimpleTest(meta_eval)
558 563
559 564 result = {}
560 565 for name, trait in traits.items():
561 566 for meta_name, meta_eval in metadata.items():
562 567 if not meta_eval(trait.get_metadata(meta_name)):
563 568 break
564 569 else:
565 570 result[name] = trait
566 571
567 572 return result
568 573
569 574 def trait_names(self, **metadata):
570 575 """Get a list of all the names of this classes traits."""
571 576 return self.traits(**metadata).keys()
572 577
573 578 def traits(self, **metadata):
574 579 """Get a list of all the traits of this class.
575 580
576 581 The TraitTypes returned don't know anything about the values
577 582 that the various HasTrait's instances are holding.
578 583
579 584 This follows the same algorithm as traits does and does not allow
580 585 for any simple way of specifying merely that a metadata name
581 586 exists, but has any value. This is because get_metadata returns
582 587 None if a metadata key doesn't exist.
583 588 """
584 589 traits = dict([memb for memb in getmembers(self.__class__) if \
585 590 isinstance(memb[1], TraitType)])
586 591
587 592 if len(metadata) == 0:
588 593 return traits
589 594
590 595 for meta_name, meta_eval in metadata.items():
591 596 if type(meta_eval) is not FunctionType:
592 597 metadata[meta_name] = _SimpleTest(meta_eval)
593 598
594 599 result = {}
595 600 for name, trait in traits.items():
596 601 for meta_name, meta_eval in metadata.items():
597 602 if not meta_eval(trait.get_metadata(meta_name)):
598 603 break
599 604 else:
600 605 result[name] = trait
601 606
602 607 return result
603 608
604 609 def trait_metadata(self, traitname, key):
605 610 """Get metadata values for trait by key."""
606 611 try:
607 612 trait = getattr(self.__class__, traitname)
608 613 except AttributeError:
609 614 raise TraitError("Class %s does not have a trait named %s" %
610 615 (self.__class__.__name__, traitname))
611 616 else:
612 617 return trait.get_metadata(key)
613 618
614 619 #-----------------------------------------------------------------------------
615 620 # Actual TraitTypes implementations/subclasses
616 621 #-----------------------------------------------------------------------------
617 622
618 623 #-----------------------------------------------------------------------------
619 624 # TraitTypes subclasses for handling classes and instances of classes
620 625 #-----------------------------------------------------------------------------
621 626
622 627
623 628 class ClassBasedTraitType(TraitType):
624 629 """A trait with error reporting for Type, Instance and This."""
625 630
626 631 def error(self, obj, value):
627 632 kind = type(value)
628 633 if (not py3compat.PY3) and kind is InstanceType:
629 634 msg = 'class %s' % value.__class__.__name__
630 635 else:
631 636 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
632 637
633 638 if obj is not None:
634 639 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
635 640 % (self.name, class_of(obj),
636 641 self.info(), msg)
637 642 else:
638 643 e = "The '%s' trait must be %s, but a value of %r was specified." \
639 644 % (self.name, self.info(), msg)
640 645
641 646 raise TraitError(e)
642 647
643 648
644 649 class Type(ClassBasedTraitType):
645 650 """A trait whose value must be a subclass of a specified class."""
646 651
647 652 def __init__ (self, default_value=None, klass=None, allow_none=True, **metadata ):
648 653 """Construct a Type trait
649 654
650 655 A Type trait specifies that its values must be subclasses of
651 656 a particular class.
652 657
653 658 If only ``default_value`` is given, it is used for the ``klass`` as
654 659 well.
655 660
656 661 Parameters
657 662 ----------
658 663 default_value : class, str or None
659 664 The default value must be a subclass of klass. If an str,
660 665 the str must be a fully specified class name, like 'foo.bar.Bah'.
661 666 The string is resolved into real class, when the parent
662 667 :class:`HasTraits` class is instantiated.
663 668 klass : class, str, None
664 669 Values of this trait must be a subclass of klass. The klass
665 670 may be specified in a string like: 'foo.bar.MyClass'.
666 671 The string is resolved into real class, when the parent
667 672 :class:`HasTraits` class is instantiated.
668 673 allow_none : boolean
669 674 Indicates whether None is allowed as an assignable value. Even if
670 675 ``False``, the default value may be ``None``.
671 676 """
672 677 if default_value is None:
673 678 if klass is None:
674 679 klass = object
675 680 elif klass is None:
676 681 klass = default_value
677 682
678 683 if not (inspect.isclass(klass) or isinstance(klass, basestring)):
679 684 raise TraitError("A Type trait must specify a class.")
680 685
681 686 self.klass = klass
682 687 self._allow_none = allow_none
683 688
684 689 super(Type, self).__init__(default_value, **metadata)
685 690
686 691 def validate(self, obj, value):
687 692 """Validates that the value is a valid object instance."""
688 693 try:
689 694 if issubclass(value, self.klass):
690 695 return value
691 696 except:
692 697 if (value is None) and (self._allow_none):
693 698 return value
694 699
695 700 self.error(obj, value)
696 701
697 702 def info(self):
698 703 """ Returns a description of the trait."""
699 704 if isinstance(self.klass, basestring):
700 705 klass = self.klass
701 706 else:
702 707 klass = self.klass.__name__
703 708 result = 'a subclass of ' + klass
704 709 if self._allow_none:
705 710 return result + ' or None'
706 711 return result
707 712
708 713 def instance_init(self, obj):
709 714 self._resolve_classes()
710 715 super(Type, self).instance_init(obj)
711 716
712 717 def _resolve_classes(self):
713 718 if isinstance(self.klass, basestring):
714 719 self.klass = import_item(self.klass)
715 720 if isinstance(self.default_value, basestring):
716 721 self.default_value = import_item(self.default_value)
717 722
718 723 def get_default_value(self):
719 724 return self.default_value
720 725
721 726
722 727 class DefaultValueGenerator(object):
723 728 """A class for generating new default value instances."""
724 729
725 730 def __init__(self, *args, **kw):
726 731 self.args = args
727 732 self.kw = kw
728 733
729 734 def generate(self, klass):
730 735 return klass(*self.args, **self.kw)
731 736
732 737
733 738 class Instance(ClassBasedTraitType):
734 739 """A trait whose value must be an instance of a specified class.
735 740
736 741 The value can also be an instance of a subclass of the specified class.
737 742 """
738 743
739 744 def __init__(self, klass=None, args=None, kw=None,
740 745 allow_none=True, **metadata ):
741 746 """Construct an Instance trait.
742 747
743 748 This trait allows values that are instances of a particular
744 749 class or its sublclasses. Our implementation is quite different
745 750 from that of enthough.traits as we don't allow instances to be used
746 751 for klass and we handle the ``args`` and ``kw`` arguments differently.
747 752
748 753 Parameters
749 754 ----------
750 755 klass : class, str
751 756 The class that forms the basis for the trait. Class names
752 757 can also be specified as strings, like 'foo.bar.Bar'.
753 758 args : tuple
754 759 Positional arguments for generating the default value.
755 760 kw : dict
756 761 Keyword arguments for generating the default value.
757 762 allow_none : bool
758 763 Indicates whether None is allowed as a value.
759 764
760 765 Default Value
761 766 -------------
762 767 If both ``args`` and ``kw`` are None, then the default value is None.
763 768 If ``args`` is a tuple and ``kw`` is a dict, then the default is
764 769 created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
765 770 not (but not both), None is replace by ``()`` or ``{}``.
766 771 """
767 772
768 773 self._allow_none = allow_none
769 774
770 775 if (klass is None) or (not (inspect.isclass(klass) or isinstance(klass, basestring))):
771 776 raise TraitError('The klass argument must be a class'
772 777 ' you gave: %r' % klass)
773 778 self.klass = klass
774 779
775 780 # self.klass is a class, so handle default_value
776 781 if args is None and kw is None:
777 782 default_value = None
778 783 else:
779 784 if args is None:
780 785 # kw is not None
781 786 args = ()
782 787 elif kw is None:
783 788 # args is not None
784 789 kw = {}
785 790
786 791 if not isinstance(kw, dict):
787 792 raise TraitError("The 'kw' argument must be a dict or None.")
788 793 if not isinstance(args, tuple):
789 794 raise TraitError("The 'args' argument must be a tuple or None.")
790 795
791 796 default_value = DefaultValueGenerator(*args, **kw)
792 797
793 798 super(Instance, self).__init__(default_value, **metadata)
794 799
795 800 def validate(self, obj, value):
796 801 if value is None:
797 802 if self._allow_none:
798 803 return value
799 804 self.error(obj, value)
800 805
801 806 if isinstance(value, self.klass):
802 807 return value
803 808 else:
804 809 self.error(obj, value)
805 810
806 811 def info(self):
807 812 if isinstance(self.klass, basestring):
808 813 klass = self.klass
809 814 else:
810 815 klass = self.klass.__name__
811 816 result = class_of(klass)
812 817 if self._allow_none:
813 818 return result + ' or None'
814 819
815 820 return result
816 821
817 822 def instance_init(self, obj):
818 823 self._resolve_classes()
819 824 super(Instance, self).instance_init(obj)
820 825
821 826 def _resolve_classes(self):
822 827 if isinstance(self.klass, basestring):
823 828 self.klass = import_item(self.klass)
824 829
825 830 def get_default_value(self):
826 831 """Instantiate a default value instance.
827 832
828 833 This is called when the containing HasTraits classes'
829 834 :meth:`__new__` method is called to ensure that a unique instance
830 835 is created for each HasTraits instance.
831 836 """
832 837 dv = self.default_value
833 838 if isinstance(dv, DefaultValueGenerator):
834 839 return dv.generate(self.klass)
835 840 else:
836 841 return dv
837 842
838 843
839 844 class This(ClassBasedTraitType):
840 845 """A trait for instances of the class containing this trait.
841 846
842 847 Because how how and when class bodies are executed, the ``This``
843 848 trait can only have a default value of None. This, and because we
844 849 always validate default values, ``allow_none`` is *always* true.
845 850 """
846 851
847 852 info_text = 'an instance of the same type as the receiver or None'
848 853
849 854 def __init__(self, **metadata):
850 855 super(This, self).__init__(None, **metadata)
851 856
852 857 def validate(self, obj, value):
853 858 # What if value is a superclass of obj.__class__? This is
854 859 # complicated if it was the superclass that defined the This
855 860 # trait.
856 861 if isinstance(value, self.this_class) or (value is None):
857 862 return value
858 863 else:
859 864 self.error(obj, value)
860 865
861 866
862 867 #-----------------------------------------------------------------------------
863 868 # Basic TraitTypes implementations/subclasses
864 869 #-----------------------------------------------------------------------------
865 870
866 871
867 872 class Any(TraitType):
868 873 default_value = None
869 874 info_text = 'any value'
870 875
871 876
872 877 class Int(TraitType):
873 878 """An int trait."""
874 879
875 880 default_value = 0
876 881 info_text = 'an int'
877 882
878 883 def validate(self, obj, value):
879 884 if isinstance(value, int):
880 885 return value
881 886 self.error(obj, value)
882 887
883 888 class CInt(Int):
884 889 """A casting version of the int trait."""
885 890
886 891 def validate(self, obj, value):
887 892 try:
888 893 return int(value)
889 894 except:
890 895 self.error(obj, value)
891 896
892 897 if py3compat.PY3:
893 898 Long, CLong = Int, CInt
894 899 Integer = Int
895 900 else:
896 901 class Long(TraitType):
897 902 """A long integer trait."""
898 903
899 904 default_value = 0L
900 905 info_text = 'a long'
901 906
902 907 def validate(self, obj, value):
903 908 if isinstance(value, long):
904 909 return value
905 910 if isinstance(value, int):
906 911 return long(value)
907 912 self.error(obj, value)
908 913
909 914
910 915 class CLong(Long):
911 916 """A casting version of the long integer trait."""
912 917
913 918 def validate(self, obj, value):
914 919 try:
915 920 return long(value)
916 921 except:
917 922 self.error(obj, value)
918 923
919 924 class Integer(TraitType):
920 925 """An integer trait.
921 926
922 927 Longs that are unnecessary (<= sys.maxint) are cast to ints."""
923 928
924 929 default_value = 0
925 930 info_text = 'an integer'
926 931
927 932 def validate(self, obj, value):
928 933 if isinstance(value, int):
929 934 return value
930 935 if isinstance(value, long):
931 936 # downcast longs that fit in int:
932 937 # note that int(n > sys.maxint) returns a long, so
933 938 # we don't need a condition on this cast
934 939 return int(value)
935 940 if sys.platform == "cli":
936 941 from System import Int64
937 942 if isinstance(value, Int64):
938 943 return int(value)
939 944 self.error(obj, value)
940 945
941 946
942 947 class Float(TraitType):
943 948 """A float trait."""
944 949
945 950 default_value = 0.0
946 951 info_text = 'a float'
947 952
948 953 def validate(self, obj, value):
949 954 if isinstance(value, float):
950 955 return value
951 956 if isinstance(value, int):
952 957 return float(value)
953 958 self.error(obj, value)
954 959
955 960
956 961 class CFloat(Float):
957 962 """A casting version of the float trait."""
958 963
959 964 def validate(self, obj, value):
960 965 try:
961 966 return float(value)
962 967 except:
963 968 self.error(obj, value)
964 969
965 970 class Complex(TraitType):
966 971 """A trait for complex numbers."""
967 972
968 973 default_value = 0.0 + 0.0j
969 974 info_text = 'a complex number'
970 975
971 976 def validate(self, obj, value):
972 977 if isinstance(value, complex):
973 978 return value
974 979 if isinstance(value, (float, int)):
975 980 return complex(value)
976 981 self.error(obj, value)
977 982
978 983
979 984 class CComplex(Complex):
980 985 """A casting version of the complex number trait."""
981 986
982 987 def validate (self, obj, value):
983 988 try:
984 989 return complex(value)
985 990 except:
986 991 self.error(obj, value)
987 992
988 993 # We should always be explicit about whether we're using bytes or unicode, both
989 994 # for Python 3 conversion and for reliable unicode behaviour on Python 2. So
990 995 # we don't have a Str type.
991 996 class Bytes(TraitType):
992 997 """A trait for byte strings."""
993 998
994 999 default_value = b''
995 1000 info_text = 'a string'
996 1001
997 1002 def validate(self, obj, value):
998 1003 if isinstance(value, bytes):
999 1004 return value
1000 1005 self.error(obj, value)
1001 1006
1002 1007
1003 1008 class CBytes(Bytes):
1004 1009 """A casting version of the byte string trait."""
1005 1010
1006 1011 def validate(self, obj, value):
1007 1012 try:
1008 1013 return bytes(value)
1009 1014 except:
1010 1015 self.error(obj, value)
1011 1016
1012 1017
1013 1018 class Unicode(TraitType):
1014 1019 """A trait for unicode strings."""
1015 1020
1016 1021 default_value = u''
1017 1022 info_text = 'a unicode string'
1018 1023
1019 1024 def validate(self, obj, value):
1020 1025 if isinstance(value, unicode):
1021 1026 return value
1022 1027 if isinstance(value, bytes):
1023 1028 return unicode(value)
1024 1029 self.error(obj, value)
1025 1030
1026 1031
1027 1032 class CUnicode(Unicode):
1028 1033 """A casting version of the unicode trait."""
1029 1034
1030 1035 def validate(self, obj, value):
1031 1036 try:
1032 1037 return unicode(value)
1033 1038 except:
1034 1039 self.error(obj, value)
1035 1040
1036 1041
1037 1042 class ObjectName(TraitType):
1038 1043 """A string holding a valid object name in this version of Python.
1039 1044
1040 1045 This does not check that the name exists in any scope."""
1041 1046 info_text = "a valid object identifier in Python"
1042 1047
1043 1048 if py3compat.PY3:
1044 1049 # Python 3:
1045 1050 coerce_str = staticmethod(lambda _,s: s)
1046 1051
1047 1052 else:
1048 1053 # Python 2:
1049 1054 def coerce_str(self, obj, value):
1050 1055 "In Python 2, coerce ascii-only unicode to str"
1051 1056 if isinstance(value, unicode):
1052 1057 try:
1053 1058 return str(value)
1054 1059 except UnicodeEncodeError:
1055 1060 self.error(obj, value)
1056 1061 return value
1057 1062
1058 1063 def validate(self, obj, value):
1059 1064 value = self.coerce_str(obj, value)
1060 1065
1061 1066 if isinstance(value, str) and py3compat.isidentifier(value):
1062 1067 return value
1063 1068 self.error(obj, value)
1064 1069
1065 1070 class DottedObjectName(ObjectName):
1066 1071 """A string holding a valid dotted object name in Python, such as A.b3._c"""
1067 1072 def validate(self, obj, value):
1068 1073 value = self.coerce_str(obj, value)
1069 1074
1070 1075 if isinstance(value, str) and py3compat.isidentifier(value, dotted=True):
1071 1076 return value
1072 1077 self.error(obj, value)
1073 1078
1074 1079
1075 1080 class Bool(TraitType):
1076 1081 """A boolean (True, False) trait."""
1077 1082
1078 1083 default_value = False
1079 1084 info_text = 'a boolean'
1080 1085
1081 1086 def validate(self, obj, value):
1082 1087 if isinstance(value, bool):
1083 1088 return value
1084 1089 self.error(obj, value)
1085 1090
1086 1091
1087 1092 class CBool(Bool):
1088 1093 """A casting version of the boolean trait."""
1089 1094
1090 1095 def validate(self, obj, value):
1091 1096 try:
1092 1097 return bool(value)
1093 1098 except:
1094 1099 self.error(obj, value)
1095 1100
1096 1101
1097 1102 class Enum(TraitType):
1098 1103 """An enum that whose value must be in a given sequence."""
1099 1104
1100 1105 def __init__(self, values, default_value=None, allow_none=True, **metadata):
1101 1106 self.values = values
1102 1107 self._allow_none = allow_none
1103 1108 super(Enum, self).__init__(default_value, **metadata)
1104 1109
1105 1110 def validate(self, obj, value):
1106 1111 if value is None:
1107 1112 if self._allow_none:
1108 1113 return value
1109 1114
1110 1115 if value in self.values:
1111 1116 return value
1112 1117 self.error(obj, value)
1113 1118
1114 1119 def info(self):
1115 1120 """ Returns a description of the trait."""
1116 1121 result = 'any of ' + repr(self.values)
1117 1122 if self._allow_none:
1118 1123 return result + ' or None'
1119 1124 return result
1120 1125
1121 1126 class CaselessStrEnum(Enum):
1122 1127 """An enum of strings that are caseless in validate."""
1123 1128
1124 1129 def validate(self, obj, value):
1125 1130 if value is None:
1126 1131 if self._allow_none:
1127 1132 return value
1128 1133
1129 1134 if not isinstance(value, basestring):
1130 1135 self.error(obj, value)
1131 1136
1132 1137 for v in self.values:
1133 1138 if v.lower() == value.lower():
1134 1139 return v
1135 1140 self.error(obj, value)
1136 1141
1137 1142 class Container(Instance):
1138 1143 """An instance of a container (list, set, etc.)
1139 1144
1140 1145 To be subclassed by overriding klass.
1141 1146 """
1142 1147 klass = None
1143 1148 _valid_defaults = SequenceTypes
1144 1149 _trait = None
1145 1150
1146 1151 def __init__(self, trait=None, default_value=None, allow_none=True,
1147 1152 **metadata):
1148 1153 """Create a container trait type from a list, set, or tuple.
1149 1154
1150 1155 The default value is created by doing ``List(default_value)``,
1151 1156 which creates a copy of the ``default_value``.
1152 1157
1153 1158 ``trait`` can be specified, which restricts the type of elements
1154 1159 in the container to that TraitType.
1155 1160
1156 1161 If only one arg is given and it is not a Trait, it is taken as
1157 1162 ``default_value``:
1158 1163
1159 1164 ``c = List([1,2,3])``
1160 1165
1161 1166 Parameters
1162 1167 ----------
1163 1168
1164 1169 trait : TraitType [ optional ]
1165 1170 the type for restricting the contents of the Container. If unspecified,
1166 1171 types are not checked.
1167 1172
1168 1173 default_value : SequenceType [ optional ]
1169 1174 The default value for the Trait. Must be list/tuple/set, and
1170 1175 will be cast to the container type.
1171 1176
1172 1177 allow_none : Bool [ default True ]
1173 1178 Whether to allow the value to be None
1174 1179
1175 1180 **metadata : any
1176 1181 further keys for extensions to the Trait (e.g. config)
1177 1182
1178 1183 """
1179 1184 # allow List([values]):
1180 1185 if default_value is None and not is_trait(trait):
1181 1186 default_value = trait
1182 1187 trait = None
1183 1188
1184 1189 if default_value is None:
1185 1190 args = ()
1186 1191 elif isinstance(default_value, self._valid_defaults):
1187 1192 args = (default_value,)
1188 1193 else:
1189 1194 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1190 1195
1191 1196 if is_trait(trait):
1192 1197 self._trait = trait() if isinstance(trait, type) else trait
1193 1198 self._trait.name = 'element'
1194 1199 elif trait is not None:
1195 1200 raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
1196 1201
1197 1202 super(Container,self).__init__(klass=self.klass, args=args,
1198 1203 allow_none=allow_none, **metadata)
1199 1204
1200 1205 def element_error(self, obj, element, validator):
1201 1206 e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
1202 1207 % (self.name, class_of(obj), validator.info(), repr_type(element))
1203 1208 raise TraitError(e)
1204 1209
1205 1210 def validate(self, obj, value):
1206 1211 value = super(Container, self).validate(obj, value)
1207 1212 if value is None:
1208 1213 return value
1209 1214
1210 1215 value = self.validate_elements(obj, value)
1211 1216
1212 1217 return value
1213 1218
1214 1219 def validate_elements(self, obj, value):
1215 1220 validated = []
1216 1221 if self._trait is None or isinstance(self._trait, Any):
1217 1222 return value
1218 1223 for v in value:
1219 1224 try:
1220 1225 v = self._trait.validate(obj, v)
1221 1226 except TraitError:
1222 1227 self.element_error(obj, v, self._trait)
1223 1228 else:
1224 1229 validated.append(v)
1225 1230 return self.klass(validated)
1226 1231
1227 1232
1228 1233 class List(Container):
1229 1234 """An instance of a Python list."""
1230 1235 klass = list
1231 1236
1232 1237 def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxsize,
1233 1238 allow_none=True, **metadata):
1234 1239 """Create a List trait type from a list, set, or tuple.
1235 1240
1236 1241 The default value is created by doing ``List(default_value)``,
1237 1242 which creates a copy of the ``default_value``.
1238 1243
1239 1244 ``trait`` can be specified, which restricts the type of elements
1240 1245 in the container to that TraitType.
1241 1246
1242 1247 If only one arg is given and it is not a Trait, it is taken as
1243 1248 ``default_value``:
1244 1249
1245 1250 ``c = List([1,2,3])``
1246 1251
1247 1252 Parameters
1248 1253 ----------
1249 1254
1250 1255 trait : TraitType [ optional ]
1251 1256 the type for restricting the contents of the Container. If unspecified,
1252 1257 types are not checked.
1253 1258
1254 1259 default_value : SequenceType [ optional ]
1255 1260 The default value for the Trait. Must be list/tuple/set, and
1256 1261 will be cast to the container type.
1257 1262
1258 1263 minlen : Int [ default 0 ]
1259 1264 The minimum length of the input list
1260 1265
1261 1266 maxlen : Int [ default sys.maxsize ]
1262 1267 The maximum length of the input list
1263 1268
1264 1269 allow_none : Bool [ default True ]
1265 1270 Whether to allow the value to be None
1266 1271
1267 1272 **metadata : any
1268 1273 further keys for extensions to the Trait (e.g. config)
1269 1274
1270 1275 """
1271 1276 self._minlen = minlen
1272 1277 self._maxlen = maxlen
1273 1278 super(List, self).__init__(trait=trait, default_value=default_value,
1274 1279 allow_none=allow_none, **metadata)
1275 1280
1276 1281 def length_error(self, obj, value):
1277 1282 e = "The '%s' trait of %s instance must be of length %i <= L <= %i, but a value of %s was specified." \
1278 1283 % (self.name, class_of(obj), self._minlen, self._maxlen, value)
1279 1284 raise TraitError(e)
1280 1285
1281 1286 def validate_elements(self, obj, value):
1282 1287 length = len(value)
1283 1288 if length < self._minlen or length > self._maxlen:
1284 1289 self.length_error(obj, value)
1285 1290
1286 1291 return super(List, self).validate_elements(obj, value)
1287 1292
1288 1293
1289 1294 class Set(Container):
1290 1295 """An instance of a Python set."""
1291 1296 klass = set
1292 1297
1293 1298 class Tuple(Container):
1294 1299 """An instance of a Python tuple."""
1295 1300 klass = tuple
1296 1301
1297 1302 def __init__(self, *traits, **metadata):
1298 1303 """Tuple(*traits, default_value=None, allow_none=True, **medatata)
1299 1304
1300 1305 Create a tuple from a list, set, or tuple.
1301 1306
1302 1307 Create a fixed-type tuple with Traits:
1303 1308
1304 1309 ``t = Tuple(Int, Str, CStr)``
1305 1310
1306 1311 would be length 3, with Int,Str,CStr for each element.
1307 1312
1308 1313 If only one arg is given and it is not a Trait, it is taken as
1309 1314 default_value:
1310 1315
1311 1316 ``t = Tuple((1,2,3))``
1312 1317
1313 1318 Otherwise, ``default_value`` *must* be specified by keyword.
1314 1319
1315 1320 Parameters
1316 1321 ----------
1317 1322
1318 1323 *traits : TraitTypes [ optional ]
1319 1324 the tsype for restricting the contents of the Tuple. If unspecified,
1320 1325 types are not checked. If specified, then each positional argument
1321 1326 corresponds to an element of the tuple. Tuples defined with traits
1322 1327 are of fixed length.
1323 1328
1324 1329 default_value : SequenceType [ optional ]
1325 1330 The default value for the Tuple. Must be list/tuple/set, and
1326 1331 will be cast to a tuple. If `traits` are specified, the
1327 1332 `default_value` must conform to the shape and type they specify.
1328 1333
1329 1334 allow_none : Bool [ default True ]
1330 1335 Whether to allow the value to be None
1331 1336
1332 1337 **metadata : any
1333 1338 further keys for extensions to the Trait (e.g. config)
1334 1339
1335 1340 """
1336 1341 default_value = metadata.pop('default_value', None)
1337 1342 allow_none = metadata.pop('allow_none', True)
1338 1343
1339 1344 # allow Tuple((values,)):
1340 1345 if len(traits) == 1 and default_value is None and not is_trait(traits[0]):
1341 1346 default_value = traits[0]
1342 1347 traits = ()
1343 1348
1344 1349 if default_value is None:
1345 1350 args = ()
1346 1351 elif isinstance(default_value, self._valid_defaults):
1347 1352 args = (default_value,)
1348 1353 else:
1349 1354 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1350 1355
1351 1356 self._traits = []
1352 1357 for trait in traits:
1353 1358 t = trait() if isinstance(trait, type) else trait
1354 1359 t.name = 'element'
1355 1360 self._traits.append(t)
1356 1361
1357 1362 if self._traits and default_value is None:
1358 1363 # don't allow default to be an empty container if length is specified
1359 1364 args = None
1360 1365 super(Container,self).__init__(klass=self.klass, args=args,
1361 1366 allow_none=allow_none, **metadata)
1362 1367
1363 1368 def validate_elements(self, obj, value):
1364 1369 if not self._traits:
1365 1370 # nothing to validate
1366 1371 return value
1367 1372 if len(value) != len(self._traits):
1368 1373 e = "The '%s' trait of %s instance requires %i elements, but a value of %s was specified." \
1369 1374 % (self.name, class_of(obj), len(self._traits), repr_type(value))
1370 1375 raise TraitError(e)
1371 1376
1372 1377 validated = []
1373 1378 for t,v in zip(self._traits, value):
1374 1379 try:
1375 1380 v = t.validate(obj, v)
1376 1381 except TraitError:
1377 1382 self.element_error(obj, v, t)
1378 1383 else:
1379 1384 validated.append(v)
1380 1385 return tuple(validated)
1381 1386
1382 1387
1383 1388 class Dict(Instance):
1384 1389 """An instance of a Python dict."""
1385 1390
1386 1391 def __init__(self, default_value=None, allow_none=True, **metadata):
1387 1392 """Create a dict trait type from a dict.
1388 1393
1389 1394 The default value is created by doing ``dict(default_value)``,
1390 1395 which creates a copy of the ``default_value``.
1391 1396 """
1392 1397 if default_value is None:
1393 1398 args = ((),)
1394 1399 elif isinstance(default_value, dict):
1395 1400 args = (default_value,)
1396 1401 elif isinstance(default_value, SequenceTypes):
1397 1402 args = (default_value,)
1398 1403 else:
1399 1404 raise TypeError('default value of Dict was %s' % default_value)
1400 1405
1401 1406 super(Dict,self).__init__(klass=dict, args=args,
1402 1407 allow_none=allow_none, **metadata)
1403 1408
1404 1409 class TCPAddress(TraitType):
1405 1410 """A trait for an (ip, port) tuple.
1406 1411
1407 1412 This allows for both IPv4 IP addresses as well as hostnames.
1408 1413 """
1409 1414
1410 1415 default_value = ('127.0.0.1', 0)
1411 1416 info_text = 'an (ip, port) tuple'
1412 1417
1413 1418 def validate(self, obj, value):
1414 1419 if isinstance(value, tuple):
1415 1420 if len(value) == 2:
1416 1421 if isinstance(value[0], basestring) and isinstance(value[1], int):
1417 1422 port = value[1]
1418 1423 if port >= 0 and port <= 65535:
1419 1424 return value
1420 1425 self.error(obj, value)
1421 1426
1422 1427 class CRegExp(TraitType):
1423 1428 """A casting compiled regular expression trait.
1424 1429
1425 1430 Accepts both strings and compiled regular expressions. The resulting
1426 1431 attribute will be a compiled regular expression."""
1427 1432
1428 1433 info_text = 'a regular expression'
1429 1434
1430 1435 def validate(self, obj, value):
1431 1436 try:
1432 1437 return re.compile(value)
1433 1438 except:
1434 1439 self.error(obj, value)
@@ -1,417 +1,412 b''
1 1 """Attempt to generate templates for module reference with Sphinx
2 2
3 3 XXX - we exclude extension modules
4 4
5 5 To include extension modules, first identify them as valid in the
6 6 ``_uri2path`` method, then handle them in the ``_parse_module`` script.
7 7
8 8 We get functions and classes by parsing the text of .py files.
9 9 Alternatively we could import the modules for discovery, and we'd have
10 10 to do that for extension modules. This would involve changing the
11 11 ``_parse_module`` method to work via import and introspection, and
12 12 might involve changing ``discover_modules`` (which determines which
13 13 files are modules, and therefore which module URIs will be passed to
14 14 ``_parse_module``).
15 15
16 16 NOTE: this is a modified version of a script originally shipped with the
17 17 PyMVPA project, which we've adapted for NIPY use. PyMVPA is an MIT-licensed
18 18 project."""
19 19
20 20 # Stdlib imports
21 21 import ast
22 22 import os
23 23 import re
24 24
25 25 class Obj(object):
26 26 '''Namespace to hold arbitrary information.'''
27 27 def __init__(self, **kwargs):
28 28 for k, v in kwargs.items():
29 29 setattr(self, k, v)
30 30
31 31 # Functions and classes
32 32 class ApiDocWriter(object):
33 33 ''' Class for automatic detection and parsing of API docs
34 34 to Sphinx-parsable reST format'''
35 35
36 36 # only separating first two levels
37 37 rst_section_levels = ['*', '=', '-', '~', '^']
38 38
39 39 def __init__(self,
40 40 package_name,
41 41 rst_extension='.rst',
42 42 package_skip_patterns=None,
43 43 module_skip_patterns=None,
44 44 ):
45 45 ''' Initialize package for parsing
46 46
47 47 Parameters
48 48 ----------
49 49 package_name : string
50 50 Name of the top-level package. *package_name* must be the
51 51 name of an importable package
52 52 rst_extension : string, optional
53 53 Extension for reST files, default '.rst'
54 54 package_skip_patterns : None or sequence of {strings, regexps}
55 55 Sequence of strings giving URIs of packages to be excluded
56 56 Operates on the package path, starting at (including) the
57 57 first dot in the package path, after *package_name* - so,
58 58 if *package_name* is ``sphinx``, then ``sphinx.util`` will
59 59 result in ``.util`` being passed for earching by these
60 60 regexps. If is None, gives default. Default is:
61 61 ['\.tests$']
62 62 module_skip_patterns : None or sequence
63 63 Sequence of strings giving URIs of modules to be excluded
64 64 Operates on the module name including preceding URI path,
65 65 back to the first dot after *package_name*. For example
66 66 ``sphinx.util.console`` results in the string to search of
67 67 ``.util.console``
68 68 If is None, gives default. Default is:
69 69 ['\.setup$', '\._']
70 70 '''
71 71 if package_skip_patterns is None:
72 72 package_skip_patterns = ['\\.tests$']
73 73 if module_skip_patterns is None:
74 74 module_skip_patterns = ['\\.setup$', '\\._']
75 75 self.package_name = package_name
76 76 self.rst_extension = rst_extension
77 77 self.package_skip_patterns = package_skip_patterns
78 78 self.module_skip_patterns = module_skip_patterns
79 79
80 80 def get_package_name(self):
81 81 return self._package_name
82 82
83 83 def set_package_name(self, package_name):
84 84 ''' Set package_name
85 85
86 86 >>> docwriter = ApiDocWriter('sphinx')
87 87 >>> import sphinx
88 88 >>> docwriter.root_path == sphinx.__path__[0]
89 89 True
90 90 >>> docwriter.package_name = 'docutils'
91 91 >>> import docutils
92 92 >>> docwriter.root_path == docutils.__path__[0]
93 93 True
94 94 '''
95 95 # It's also possible to imagine caching the module parsing here
96 96 self._package_name = package_name
97 97 self.root_module = __import__(package_name)
98 98 self.root_path = self.root_module.__path__[0]
99 99 self.written_modules = None
100 100
101 101 package_name = property(get_package_name, set_package_name, None,
102 102 'get/set package_name')
103 103
104 104 def _uri2path(self, uri):
105 105 ''' Convert uri to absolute filepath
106 106
107 107 Parameters
108 108 ----------
109 109 uri : string
110 110 URI of python module to return path for
111 111
112 112 Returns
113 113 -------
114 114 path : None or string
115 115 Returns None if there is no valid path for this URI
116 116 Otherwise returns absolute file system path for URI
117 117
118 118 Examples
119 119 --------
120 120 >>> docwriter = ApiDocWriter('sphinx')
121 121 >>> import sphinx
122 122 >>> modpath = sphinx.__path__[0]
123 123 >>> res = docwriter._uri2path('sphinx.builder')
124 124 >>> res == os.path.join(modpath, 'builder.py')
125 125 True
126 126 >>> res = docwriter._uri2path('sphinx')
127 127 >>> res == os.path.join(modpath, '__init__.py')
128 128 True
129 129 >>> docwriter._uri2path('sphinx.does_not_exist')
130 130
131 131 '''
132 132 if uri == self.package_name:
133 133 return os.path.join(self.root_path, '__init__.py')
134 134 path = uri.replace('.', os.path.sep)
135 135 path = path.replace(self.package_name + os.path.sep, '')
136 136 path = os.path.join(self.root_path, path)
137 137 # XXX maybe check for extensions as well?
138 138 if os.path.exists(path + '.py'): # file
139 139 path += '.py'
140 140 elif os.path.exists(os.path.join(path, '__init__.py')):
141 141 path = os.path.join(path, '__init__.py')
142 142 else:
143 143 return None
144 144 return path
145 145
146 146 def _path2uri(self, dirpath):
147 147 ''' Convert directory path to uri '''
148 148 relpath = dirpath.replace(self.root_path, self.package_name)
149 149 if relpath.startswith(os.path.sep):
150 150 relpath = relpath[1:]
151 151 return relpath.replace(os.path.sep, '.')
152 152
153 153 def _parse_module(self, uri):
154 154 ''' Parse module defined in *uri* '''
155 155 filename = self._uri2path(uri)
156 156 if filename is None:
157 157 # nothing that we could handle here.
158 158 return ([],[])
159 159 with open(filename, 'rb') as f:
160 160 mod = ast.parse(f.read())
161 161 return self._find_functions_classes(mod)
162 162
163 163 @staticmethod
164 164 def _find_functions_classes(mod):
165 165 """Extract top-level functions and classes from a module AST.
166 166
167 167 Skips objects with an @undoc decorator, or a name starting with '_'.
168 168 """
169 169 def has_undoc_decorator(node):
170 170 return any(isinstance(d, ast.Name) and d.id == 'undoc' \
171 171 for d in node.decorator_list)
172 172
173 173 functions, classes = [], []
174 174 for node in mod.body:
175 175 if isinstance(node, ast.FunctionDef) and \
176 176 not node.name.startswith('_') and \
177 177 not has_undoc_decorator(node):
178 178 functions.append(node.name)
179 179 elif isinstance(node, ast.ClassDef) and \
180 180 not node.name.startswith('_') and \
181 181 not has_undoc_decorator(node):
182 182 cls = Obj(name=node.name)
183 183 cls.has_init = any(isinstance(n, ast.FunctionDef) and \
184 184 n.name=='__init__' for n in node.body)
185 185 classes.append(cls)
186 186
187 187 return functions, classes
188 188
189 189 def generate_api_doc(self, uri):
190 190 '''Make autodoc documentation template string for a module
191 191
192 192 Parameters
193 193 ----------
194 194 uri : string
195 195 python location of module - e.g 'sphinx.builder'
196 196
197 197 Returns
198 198 -------
199 199 S : string
200 200 Contents of API doc
201 201 '''
202 202 # get the names of all classes and functions
203 203 functions, classes = self._parse_module(uri)
204 204 if not len(functions) and not len(classes):
205 205 print 'WARNING: Empty -',uri # dbg
206 206 return ''
207 207
208 208 # Make a shorter version of the uri that omits the package name for
209 209 # titles
210 210 uri_short = re.sub(r'^%s\.' % self.package_name,'',uri)
211 211
212 212 ad = '.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n'
213 213
214 214 # Set the chapter title to read 'Module:' for all modules except for the
215 215 # main packages
216 216 if '.' in uri:
217 217 chap_title = 'Module: :mod:`' + uri_short + '`'
218 218 else:
219 219 chap_title = ':mod:`' + uri_short + '`'
220 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 222 ad += '\n.. automodule:: ' + uri + '\n'
228 223 ad += '\n.. currentmodule:: ' + uri + '\n'
229 224 multi_class = len(classes) > 1
230 225 multi_fx = len(functions) > 1
231 226 if multi_class:
232 227 ad += '\n' + 'Classes' + '\n' + \
233 228 self.rst_section_levels[2] * 7 + '\n'
234 229 elif len(classes) and multi_fx:
235 230 ad += '\n' + 'Class' + '\n' + \
236 231 self.rst_section_levels[2] * 5 + '\n'
237 232 for c in classes:
238 233 ad += '\n:class:`' + c.name + '`\n' \
239 234 + self.rst_section_levels[multi_class + 2 ] * \
240 235 (len(c.name)+9) + '\n\n'
241 236 ad += '\n.. autoclass:: ' + c.name + '\n'
242 237 # must NOT exclude from index to keep cross-refs working
243 238 ad += ' :members:\n' \
244 239 ' :show-inheritance:\n'
245 240 if c.has_init:
246 241 ad += '\n .. automethod:: __init__\n'
247 242 if multi_fx:
248 243 ad += '\n' + 'Functions' + '\n' + \
249 244 self.rst_section_levels[2] * 9 + '\n\n'
250 245 elif len(functions) and multi_class:
251 246 ad += '\n' + 'Function' + '\n' + \
252 247 self.rst_section_levels[2] * 8 + '\n\n'
253 248 for f in functions:
254 249 # must NOT exclude from index to keep cross-refs working
255 250 ad += '\n.. autofunction:: ' + uri + '.' + f + '\n\n'
256 251 return ad
257 252
258 253 def _survives_exclude(self, matchstr, match_type):
259 254 ''' Returns True if *matchstr* does not match patterns
260 255
261 256 ``self.package_name`` removed from front of string if present
262 257
263 258 Examples
264 259 --------
265 260 >>> dw = ApiDocWriter('sphinx')
266 261 >>> dw._survives_exclude('sphinx.okpkg', 'package')
267 262 True
268 263 >>> dw.package_skip_patterns.append('^\\.badpkg$')
269 264 >>> dw._survives_exclude('sphinx.badpkg', 'package')
270 265 False
271 266 >>> dw._survives_exclude('sphinx.badpkg', 'module')
272 267 True
273 268 >>> dw._survives_exclude('sphinx.badmod', 'module')
274 269 True
275 270 >>> dw.module_skip_patterns.append('^\\.badmod$')
276 271 >>> dw._survives_exclude('sphinx.badmod', 'module')
277 272 False
278 273 '''
279 274 if match_type == 'module':
280 275 patterns = self.module_skip_patterns
281 276 elif match_type == 'package':
282 277 patterns = self.package_skip_patterns
283 278 else:
284 279 raise ValueError('Cannot interpret match type "%s"'
285 280 % match_type)
286 281 # Match to URI without package name
287 282 L = len(self.package_name)
288 283 if matchstr[:L] == self.package_name:
289 284 matchstr = matchstr[L:]
290 285 for pat in patterns:
291 286 try:
292 287 pat.search
293 288 except AttributeError:
294 289 pat = re.compile(pat)
295 290 if pat.search(matchstr):
296 291 return False
297 292 return True
298 293
299 294 def discover_modules(self):
300 295 ''' Return module sequence discovered from ``self.package_name``
301 296
302 297
303 298 Parameters
304 299 ----------
305 300 None
306 301
307 302 Returns
308 303 -------
309 304 mods : sequence
310 305 Sequence of module names within ``self.package_name``
311 306
312 307 Examples
313 308 --------
314 309 >>> dw = ApiDocWriter('sphinx')
315 310 >>> mods = dw.discover_modules()
316 311 >>> 'sphinx.util' in mods
317 312 True
318 313 >>> dw.package_skip_patterns.append('\.util$')
319 314 >>> 'sphinx.util' in dw.discover_modules()
320 315 False
321 316 >>>
322 317 '''
323 318 modules = [self.package_name]
324 319 # raw directory parsing
325 320 for dirpath, dirnames, filenames in os.walk(self.root_path):
326 321 # Check directory names for packages
327 322 root_uri = self._path2uri(os.path.join(self.root_path,
328 323 dirpath))
329 324 for dirname in dirnames[:]: # copy list - we modify inplace
330 325 package_uri = '.'.join((root_uri, dirname))
331 326 if (self._uri2path(package_uri) and
332 327 self._survives_exclude(package_uri, 'package')):
333 328 modules.append(package_uri)
334 329 else:
335 330 dirnames.remove(dirname)
336 331 # Check filenames for modules
337 332 for filename in filenames:
338 333 module_name = filename[:-3]
339 334 module_uri = '.'.join((root_uri, module_name))
340 335 if (self._uri2path(module_uri) and
341 336 self._survives_exclude(module_uri, 'module')):
342 337 modules.append(module_uri)
343 338 return sorted(modules)
344 339
345 340 def write_modules_api(self, modules,outdir):
346 341 # write the list
347 342 written_modules = []
348 343 for m in modules:
349 344 api_str = self.generate_api_doc(m)
350 345 if not api_str:
351 346 continue
352 347 # write out to file
353 348 outfile = os.path.join(outdir,
354 349 m + self.rst_extension)
355 350 fileobj = open(outfile, 'wt')
356 351 fileobj.write(api_str)
357 352 fileobj.close()
358 353 written_modules.append(m)
359 354 self.written_modules = written_modules
360 355
361 356 def write_api_docs(self, outdir):
362 357 """Generate API reST files.
363 358
364 359 Parameters
365 360 ----------
366 361 outdir : string
367 362 Directory name in which to store files
368 363 We create automatic filenames for each module
369 364
370 365 Returns
371 366 -------
372 367 None
373 368
374 369 Notes
375 370 -----
376 371 Sets self.written_modules to list of written modules
377 372 """
378 373 if not os.path.exists(outdir):
379 374 os.mkdir(outdir)
380 375 # compose list of modules
381 376 modules = self.discover_modules()
382 377 self.write_modules_api(modules,outdir)
383 378
384 379 def write_index(self, outdir, froot='gen', relative_to=None):
385 380 """Make a reST API index file from written files
386 381
387 382 Parameters
388 383 ----------
389 384 path : string
390 385 Filename to write index to
391 386 outdir : string
392 387 Directory to which to write generated index file
393 388 froot : string, optional
394 389 root (filename without extension) of filename to write to
395 390 Defaults to 'gen'. We add ``self.rst_extension``.
396 391 relative_to : string
397 392 path to which written filenames are relative. This
398 393 component of the written file path will be removed from
399 394 outdir, in the generated index. Default is None, meaning,
400 395 leave path as it is.
401 396 """
402 397 if self.written_modules is None:
403 398 raise ValueError('No modules written')
404 399 # Get full filename path
405 400 path = os.path.join(outdir, froot+self.rst_extension)
406 401 # Path written into index is relative to rootpath
407 402 if relative_to is not None:
408 403 relpath = outdir.replace(relative_to + os.path.sep, '')
409 404 else:
410 405 relpath = outdir
411 406 idx = open(path,'wt')
412 407 w = idx.write
413 408 w('.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n')
414 409 w('.. toctree::\n\n')
415 410 for f in self.written_modules:
416 411 w(' %s\n' % os.path.join(relpath,f))
417 412 idx.close()
General Comments 0
You need to be logged in to leave comments. Login now