##// END OF EJS Templates
Merge pull request #2140 from bfroehle/2to3_has_key...
Thomas Kluyver -
r7873:aed04922 merge
parent child Browse files
Show More
@@ -1,696 +1,696 b''
1 """A simple configuration system.
1 """A simple configuration system.
2
2
3 Authors
3 Authors
4 -------
4 -------
5 * Brian Granger
5 * Brian Granger
6 * Fernando Perez
6 * Fernando Perez
7 * Min RK
7 * Min RK
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2011 The IPython Development Team
11 # Copyright (C) 2008-2011 The IPython Development Team
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Imports
18 # Imports
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 import __builtin__ as builtin_mod
21 import __builtin__ as builtin_mod
22 import os
22 import os
23 import re
23 import re
24 import sys
24 import sys
25
25
26 from IPython.external import argparse
26 from IPython.external import argparse
27 from IPython.utils.path import filefind, get_ipython_dir
27 from IPython.utils.path import filefind, get_ipython_dir
28 from IPython.utils import py3compat, text, warn
28 from IPython.utils import py3compat, text, warn
29 from IPython.utils.encoding import DEFAULT_ENCODING
29 from IPython.utils.encoding import DEFAULT_ENCODING
30
30
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32 # Exceptions
32 # Exceptions
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34
34
35
35
36 class ConfigError(Exception):
36 class ConfigError(Exception):
37 pass
37 pass
38
38
39 class ConfigLoaderError(ConfigError):
39 class ConfigLoaderError(ConfigError):
40 pass
40 pass
41
41
42 class ConfigFileNotFound(ConfigError):
42 class ConfigFileNotFound(ConfigError):
43 pass
43 pass
44
44
45 class ArgumentError(ConfigLoaderError):
45 class ArgumentError(ConfigLoaderError):
46 pass
46 pass
47
47
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49 # Argparse fix
49 # Argparse fix
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51
51
52 # Unfortunately argparse by default prints help messages to stderr instead of
52 # Unfortunately argparse by default prints help messages to stderr instead of
53 # stdout. This makes it annoying to capture long help screens at the command
53 # stdout. This makes it annoying to capture long help screens at the command
54 # line, since one must know how to pipe stderr, which many users don't know how
54 # line, since one must know how to pipe stderr, which many users don't know how
55 # to do. So we override the print_help method with one that defaults to
55 # to do. So we override the print_help method with one that defaults to
56 # stdout and use our class instead.
56 # stdout and use our class instead.
57
57
58 class ArgumentParser(argparse.ArgumentParser):
58 class ArgumentParser(argparse.ArgumentParser):
59 """Simple argparse subclass that prints help to stdout by default."""
59 """Simple argparse subclass that prints help to stdout by default."""
60
60
61 def print_help(self, file=None):
61 def print_help(self, file=None):
62 if file is None:
62 if file is None:
63 file = sys.stdout
63 file = sys.stdout
64 return super(ArgumentParser, self).print_help(file)
64 return super(ArgumentParser, self).print_help(file)
65
65
66 print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__
66 print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__
67
67
68 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
69 # Config class for holding config information
69 # Config class for holding config information
70 #-----------------------------------------------------------------------------
70 #-----------------------------------------------------------------------------
71
71
72
72
73 class Config(dict):
73 class Config(dict):
74 """An attribute based dict that can do smart merges."""
74 """An attribute based dict that can do smart merges."""
75
75
76 def __init__(self, *args, **kwds):
76 def __init__(self, *args, **kwds):
77 dict.__init__(self, *args, **kwds)
77 dict.__init__(self, *args, **kwds)
78 # This sets self.__dict__ = self, but it has to be done this way
78 # This sets self.__dict__ = self, but it has to be done this way
79 # because we are also overriding __setattr__.
79 # because we are also overriding __setattr__.
80 dict.__setattr__(self, '__dict__', self)
80 dict.__setattr__(self, '__dict__', self)
81
81
82 def _merge(self, other):
82 def _merge(self, other):
83 to_update = {}
83 to_update = {}
84 for k, v in other.iteritems():
84 for k, v in other.iteritems():
85 if not self.has_key(k):
85 if k not in self:
86 to_update[k] = v
86 to_update[k] = v
87 else: # I have this key
87 else: # I have this key
88 if isinstance(v, Config):
88 if isinstance(v, Config):
89 # Recursively merge common sub Configs
89 # Recursively merge common sub Configs
90 self[k]._merge(v)
90 self[k]._merge(v)
91 else:
91 else:
92 # Plain updates for non-Configs
92 # Plain updates for non-Configs
93 to_update[k] = v
93 to_update[k] = v
94
94
95 self.update(to_update)
95 self.update(to_update)
96
96
97 def _is_section_key(self, key):
97 def _is_section_key(self, key):
98 if key[0].upper()==key[0] and not key.startswith('_'):
98 if key[0].upper()==key[0] and not key.startswith('_'):
99 return True
99 return True
100 else:
100 else:
101 return False
101 return False
102
102
103 def __contains__(self, key):
103 def __contains__(self, key):
104 if self._is_section_key(key):
104 if self._is_section_key(key):
105 return True
105 return True
106 else:
106 else:
107 return super(Config, self).__contains__(key)
107 return super(Config, self).__contains__(key)
108 # .has_key is deprecated for dictionaries.
108 # .has_key is deprecated for dictionaries.
109 has_key = __contains__
109 has_key = __contains__
110
110
111 def _has_section(self, key):
111 def _has_section(self, key):
112 if self._is_section_key(key):
112 if self._is_section_key(key):
113 if super(Config, self).__contains__(key):
113 if super(Config, self).__contains__(key):
114 return True
114 return True
115 return False
115 return False
116
116
117 def copy(self):
117 def copy(self):
118 return type(self)(dict.copy(self))
118 return type(self)(dict.copy(self))
119
119
120 def __copy__(self):
120 def __copy__(self):
121 return self.copy()
121 return self.copy()
122
122
123 def __deepcopy__(self, memo):
123 def __deepcopy__(self, memo):
124 import copy
124 import copy
125 return type(self)(copy.deepcopy(self.items()))
125 return type(self)(copy.deepcopy(self.items()))
126
126
127 def __getitem__(self, key):
127 def __getitem__(self, key):
128 # We cannot use directly self._is_section_key, because it triggers
128 # We cannot use directly self._is_section_key, because it triggers
129 # infinite recursion on top of PyPy. Instead, we manually fish the
129 # infinite recursion on top of PyPy. Instead, we manually fish the
130 # bound method.
130 # bound method.
131 is_section_key = self.__class__._is_section_key.__get__(self)
131 is_section_key = self.__class__._is_section_key.__get__(self)
132
132
133 # Because we use this for an exec namespace, we need to delegate
133 # Because we use this for an exec namespace, we need to delegate
134 # the lookup of names in __builtin__ to itself. This means
134 # the lookup of names in __builtin__ to itself. This means
135 # that you can't have section or attribute names that are
135 # that you can't have section or attribute names that are
136 # builtins.
136 # builtins.
137 try:
137 try:
138 return getattr(builtin_mod, key)
138 return getattr(builtin_mod, key)
139 except AttributeError:
139 except AttributeError:
140 pass
140 pass
141 if is_section_key(key):
141 if is_section_key(key):
142 try:
142 try:
143 return dict.__getitem__(self, key)
143 return dict.__getitem__(self, key)
144 except KeyError:
144 except KeyError:
145 c = Config()
145 c = Config()
146 dict.__setitem__(self, key, c)
146 dict.__setitem__(self, key, c)
147 return c
147 return c
148 else:
148 else:
149 return dict.__getitem__(self, key)
149 return dict.__getitem__(self, key)
150
150
151 def __setitem__(self, key, value):
151 def __setitem__(self, key, value):
152 # Don't allow names in __builtin__ to be modified.
152 # Don't allow names in __builtin__ to be modified.
153 if hasattr(builtin_mod, key):
153 if hasattr(builtin_mod, key):
154 raise ConfigError('Config variable names cannot have the same name '
154 raise ConfigError('Config variable names cannot have the same name '
155 'as a Python builtin: %s' % key)
155 'as a Python builtin: %s' % key)
156 if self._is_section_key(key):
156 if self._is_section_key(key):
157 if not isinstance(value, Config):
157 if not isinstance(value, Config):
158 raise ValueError('values whose keys begin with an uppercase '
158 raise ValueError('values whose keys begin with an uppercase '
159 'char must be Config instances: %r, %r' % (key, value))
159 'char must be Config instances: %r, %r' % (key, value))
160 else:
160 else:
161 dict.__setitem__(self, key, value)
161 dict.__setitem__(self, key, value)
162
162
163 def __getattr__(self, key):
163 def __getattr__(self, key):
164 try:
164 try:
165 return self.__getitem__(key)
165 return self.__getitem__(key)
166 except KeyError as e:
166 except KeyError as e:
167 raise AttributeError(e)
167 raise AttributeError(e)
168
168
169 def __setattr__(self, key, value):
169 def __setattr__(self, key, value):
170 try:
170 try:
171 self.__setitem__(key, value)
171 self.__setitem__(key, value)
172 except KeyError as e:
172 except KeyError as e:
173 raise AttributeError(e)
173 raise AttributeError(e)
174
174
175 def __delattr__(self, key):
175 def __delattr__(self, key):
176 try:
176 try:
177 dict.__delitem__(self, key)
177 dict.__delitem__(self, key)
178 except KeyError as e:
178 except KeyError as e:
179 raise AttributeError(e)
179 raise AttributeError(e)
180
180
181
181
182 #-----------------------------------------------------------------------------
182 #-----------------------------------------------------------------------------
183 # Config loading classes
183 # Config loading classes
184 #-----------------------------------------------------------------------------
184 #-----------------------------------------------------------------------------
185
185
186
186
187 class ConfigLoader(object):
187 class ConfigLoader(object):
188 """A object for loading configurations from just about anywhere.
188 """A object for loading configurations from just about anywhere.
189
189
190 The resulting configuration is packaged as a :class:`Struct`.
190 The resulting configuration is packaged as a :class:`Struct`.
191
191
192 Notes
192 Notes
193 -----
193 -----
194 A :class:`ConfigLoader` does one thing: load a config from a source
194 A :class:`ConfigLoader` does one thing: load a config from a source
195 (file, command line arguments) and returns the data as a :class:`Struct`.
195 (file, command line arguments) and returns the data as a :class:`Struct`.
196 There are lots of things that :class:`ConfigLoader` does not do. It does
196 There are lots of things that :class:`ConfigLoader` does not do. It does
197 not implement complex logic for finding config files. It does not handle
197 not implement complex logic for finding config files. It does not handle
198 default values or merge multiple configs. These things need to be
198 default values or merge multiple configs. These things need to be
199 handled elsewhere.
199 handled elsewhere.
200 """
200 """
201
201
202 def __init__(self):
202 def __init__(self):
203 """A base class for config loaders.
203 """A base class for config loaders.
204
204
205 Examples
205 Examples
206 --------
206 --------
207
207
208 >>> cl = ConfigLoader()
208 >>> cl = ConfigLoader()
209 >>> config = cl.load_config()
209 >>> config = cl.load_config()
210 >>> config
210 >>> config
211 {}
211 {}
212 """
212 """
213 self.clear()
213 self.clear()
214
214
215 def clear(self):
215 def clear(self):
216 self.config = Config()
216 self.config = Config()
217
217
218 def load_config(self):
218 def load_config(self):
219 """Load a config from somewhere, return a :class:`Config` instance.
219 """Load a config from somewhere, return a :class:`Config` instance.
220
220
221 Usually, this will cause self.config to be set and then returned.
221 Usually, this will cause self.config to be set and then returned.
222 However, in most cases, :meth:`ConfigLoader.clear` should be called
222 However, in most cases, :meth:`ConfigLoader.clear` should be called
223 to erase any previous state.
223 to erase any previous state.
224 """
224 """
225 self.clear()
225 self.clear()
226 return self.config
226 return self.config
227
227
228
228
229 class FileConfigLoader(ConfigLoader):
229 class FileConfigLoader(ConfigLoader):
230 """A base class for file based configurations.
230 """A base class for file based configurations.
231
231
232 As we add more file based config loaders, the common logic should go
232 As we add more file based config loaders, the common logic should go
233 here.
233 here.
234 """
234 """
235 pass
235 pass
236
236
237
237
238 class PyFileConfigLoader(FileConfigLoader):
238 class PyFileConfigLoader(FileConfigLoader):
239 """A config loader for pure python files.
239 """A config loader for pure python files.
240
240
241 This calls execfile on a plain python file and looks for attributes
241 This calls execfile on a plain python file and looks for attributes
242 that are all caps. These attribute are added to the config Struct.
242 that are all caps. These attribute are added to the config Struct.
243 """
243 """
244
244
245 def __init__(self, filename, path=None):
245 def __init__(self, filename, path=None):
246 """Build a config loader for a filename and path.
246 """Build a config loader for a filename and path.
247
247
248 Parameters
248 Parameters
249 ----------
249 ----------
250 filename : str
250 filename : str
251 The file name of the config file.
251 The file name of the config file.
252 path : str, list, tuple
252 path : str, list, tuple
253 The path to search for the config file on, or a sequence of
253 The path to search for the config file on, or a sequence of
254 paths to try in order.
254 paths to try in order.
255 """
255 """
256 super(PyFileConfigLoader, self).__init__()
256 super(PyFileConfigLoader, self).__init__()
257 self.filename = filename
257 self.filename = filename
258 self.path = path
258 self.path = path
259 self.full_filename = ''
259 self.full_filename = ''
260 self.data = None
260 self.data = None
261
261
262 def load_config(self):
262 def load_config(self):
263 """Load the config from a file and return it as a Struct."""
263 """Load the config from a file and return it as a Struct."""
264 self.clear()
264 self.clear()
265 try:
265 try:
266 self._find_file()
266 self._find_file()
267 except IOError as e:
267 except IOError as e:
268 raise ConfigFileNotFound(str(e))
268 raise ConfigFileNotFound(str(e))
269 self._read_file_as_dict()
269 self._read_file_as_dict()
270 self._convert_to_config()
270 self._convert_to_config()
271 return self.config
271 return self.config
272
272
273 def _find_file(self):
273 def _find_file(self):
274 """Try to find the file by searching the paths."""
274 """Try to find the file by searching the paths."""
275 self.full_filename = filefind(self.filename, self.path)
275 self.full_filename = filefind(self.filename, self.path)
276
276
277 def _read_file_as_dict(self):
277 def _read_file_as_dict(self):
278 """Load the config file into self.config, with recursive loading."""
278 """Load the config file into self.config, with recursive loading."""
279 # This closure is made available in the namespace that is used
279 # This closure is made available in the namespace that is used
280 # to exec the config file. It allows users to call
280 # to exec the config file. It allows users to call
281 # load_subconfig('myconfig.py') to load config files recursively.
281 # load_subconfig('myconfig.py') to load config files recursively.
282 # It needs to be a closure because it has references to self.path
282 # It needs to be a closure because it has references to self.path
283 # and self.config. The sub-config is loaded with the same path
283 # and self.config. The sub-config is loaded with the same path
284 # as the parent, but it uses an empty config which is then merged
284 # as the parent, but it uses an empty config which is then merged
285 # with the parents.
285 # with the parents.
286
286
287 # If a profile is specified, the config file will be loaded
287 # If a profile is specified, the config file will be loaded
288 # from that profile
288 # from that profile
289
289
290 def load_subconfig(fname, profile=None):
290 def load_subconfig(fname, profile=None):
291 # import here to prevent circular imports
291 # import here to prevent circular imports
292 from IPython.core.profiledir import ProfileDir, ProfileDirError
292 from IPython.core.profiledir import ProfileDir, ProfileDirError
293 if profile is not None:
293 if profile is not None:
294 try:
294 try:
295 profile_dir = ProfileDir.find_profile_dir_by_name(
295 profile_dir = ProfileDir.find_profile_dir_by_name(
296 get_ipython_dir(),
296 get_ipython_dir(),
297 profile,
297 profile,
298 )
298 )
299 except ProfileDirError:
299 except ProfileDirError:
300 return
300 return
301 path = profile_dir.location
301 path = profile_dir.location
302 else:
302 else:
303 path = self.path
303 path = self.path
304 loader = PyFileConfigLoader(fname, path)
304 loader = PyFileConfigLoader(fname, path)
305 try:
305 try:
306 sub_config = loader.load_config()
306 sub_config = loader.load_config()
307 except ConfigFileNotFound:
307 except ConfigFileNotFound:
308 # Pass silently if the sub config is not there. This happens
308 # Pass silently if the sub config is not there. This happens
309 # when a user s using a profile, but not the default config.
309 # when a user s using a profile, but not the default config.
310 pass
310 pass
311 else:
311 else:
312 self.config._merge(sub_config)
312 self.config._merge(sub_config)
313
313
314 # Again, this needs to be a closure and should be used in config
314 # Again, this needs to be a closure and should be used in config
315 # files to get the config being loaded.
315 # files to get the config being loaded.
316 def get_config():
316 def get_config():
317 return self.config
317 return self.config
318
318
319 namespace = dict(load_subconfig=load_subconfig, get_config=get_config)
319 namespace = dict(load_subconfig=load_subconfig, get_config=get_config)
320 fs_encoding = sys.getfilesystemencoding() or 'ascii'
320 fs_encoding = sys.getfilesystemencoding() or 'ascii'
321 conf_filename = self.full_filename.encode(fs_encoding)
321 conf_filename = self.full_filename.encode(fs_encoding)
322 py3compat.execfile(conf_filename, namespace)
322 py3compat.execfile(conf_filename, namespace)
323
323
324 def _convert_to_config(self):
324 def _convert_to_config(self):
325 if self.data is None:
325 if self.data is None:
326 ConfigLoaderError('self.data does not exist')
326 ConfigLoaderError('self.data does not exist')
327
327
328
328
329 class CommandLineConfigLoader(ConfigLoader):
329 class CommandLineConfigLoader(ConfigLoader):
330 """A config loader for command line arguments.
330 """A config loader for command line arguments.
331
331
332 As we add more command line based loaders, the common logic should go
332 As we add more command line based loaders, the common logic should go
333 here.
333 here.
334 """
334 """
335
335
336 def _exec_config_str(self, lhs, rhs):
336 def _exec_config_str(self, lhs, rhs):
337 """execute self.config.<lhs> = <rhs>
337 """execute self.config.<lhs> = <rhs>
338
338
339 * expands ~ with expanduser
339 * expands ~ with expanduser
340 * tries to assign with raw eval, otherwise assigns with just the string,
340 * tries to assign with raw eval, otherwise assigns with just the string,
341 allowing `--C.a=foobar` and `--C.a="foobar"` to be equivalent. *Not*
341 allowing `--C.a=foobar` and `--C.a="foobar"` to be equivalent. *Not*
342 equivalent are `--C.a=4` and `--C.a='4'`.
342 equivalent are `--C.a=4` and `--C.a='4'`.
343 """
343 """
344 rhs = os.path.expanduser(rhs)
344 rhs = os.path.expanduser(rhs)
345 try:
345 try:
346 # Try to see if regular Python syntax will work. This
346 # Try to see if regular Python syntax will work. This
347 # won't handle strings as the quote marks are removed
347 # won't handle strings as the quote marks are removed
348 # by the system shell.
348 # by the system shell.
349 value = eval(rhs)
349 value = eval(rhs)
350 except (NameError, SyntaxError):
350 except (NameError, SyntaxError):
351 # This case happens if the rhs is a string.
351 # This case happens if the rhs is a string.
352 value = rhs
352 value = rhs
353
353
354 exec u'self.config.%s = value' % lhs
354 exec u'self.config.%s = value' % lhs
355
355
356 def _load_flag(self, cfg):
356 def _load_flag(self, cfg):
357 """update self.config from a flag, which can be a dict or Config"""
357 """update self.config from a flag, which can be a dict or Config"""
358 if isinstance(cfg, (dict, Config)):
358 if isinstance(cfg, (dict, Config)):
359 # don't clobber whole config sections, update
359 # don't clobber whole config sections, update
360 # each section from config:
360 # each section from config:
361 for sec,c in cfg.iteritems():
361 for sec,c in cfg.iteritems():
362 self.config[sec].update(c)
362 self.config[sec].update(c)
363 else:
363 else:
364 raise TypeError("Invalid flag: %r" % cfg)
364 raise TypeError("Invalid flag: %r" % cfg)
365
365
366 # raw --identifier=value pattern
366 # raw --identifier=value pattern
367 # but *also* accept '-' as wordsep, for aliases
367 # but *also* accept '-' as wordsep, for aliases
368 # accepts: --foo=a
368 # accepts: --foo=a
369 # --Class.trait=value
369 # --Class.trait=value
370 # --alias-name=value
370 # --alias-name=value
371 # rejects: -foo=value
371 # rejects: -foo=value
372 # --foo
372 # --foo
373 # --Class.trait
373 # --Class.trait
374 kv_pattern = re.compile(r'\-\-[A-Za-z][\w\-]*(\.[\w\-]+)*\=.*')
374 kv_pattern = re.compile(r'\-\-[A-Za-z][\w\-]*(\.[\w\-]+)*\=.*')
375
375
376 # just flags, no assignments, with two *or one* leading '-'
376 # just flags, no assignments, with two *or one* leading '-'
377 # accepts: --foo
377 # accepts: --foo
378 # -foo-bar-again
378 # -foo-bar-again
379 # rejects: --anything=anything
379 # rejects: --anything=anything
380 # --two.word
380 # --two.word
381
381
382 flag_pattern = re.compile(r'\-\-?\w+[\-\w]*$')
382 flag_pattern = re.compile(r'\-\-?\w+[\-\w]*$')
383
383
384 class KeyValueConfigLoader(CommandLineConfigLoader):
384 class KeyValueConfigLoader(CommandLineConfigLoader):
385 """A config loader that loads key value pairs from the command line.
385 """A config loader that loads key value pairs from the command line.
386
386
387 This allows command line options to be gives in the following form::
387 This allows command line options to be gives in the following form::
388
388
389 ipython --profile="foo" --InteractiveShell.autocall=False
389 ipython --profile="foo" --InteractiveShell.autocall=False
390 """
390 """
391
391
392 def __init__(self, argv=None, aliases=None, flags=None):
392 def __init__(self, argv=None, aliases=None, flags=None):
393 """Create a key value pair config loader.
393 """Create a key value pair config loader.
394
394
395 Parameters
395 Parameters
396 ----------
396 ----------
397 argv : list
397 argv : list
398 A list that has the form of sys.argv[1:] which has unicode
398 A list that has the form of sys.argv[1:] which has unicode
399 elements of the form u"key=value". If this is None (default),
399 elements of the form u"key=value". If this is None (default),
400 then sys.argv[1:] will be used.
400 then sys.argv[1:] will be used.
401 aliases : dict
401 aliases : dict
402 A dict of aliases for configurable traits.
402 A dict of aliases for configurable traits.
403 Keys are the short aliases, Values are the resolved trait.
403 Keys are the short aliases, Values are the resolved trait.
404 Of the form: `{'alias' : 'Configurable.trait'}`
404 Of the form: `{'alias' : 'Configurable.trait'}`
405 flags : dict
405 flags : dict
406 A dict of flags, keyed by str name. Vaues can be Config objects,
406 A dict of flags, keyed by str name. Vaues can be Config objects,
407 dicts, or "key=value" strings. If Config or dict, when the flag
407 dicts, or "key=value" strings. If Config or dict, when the flag
408 is triggered, The flag is loaded as `self.config.update(m)`.
408 is triggered, The flag is loaded as `self.config.update(m)`.
409
409
410 Returns
410 Returns
411 -------
411 -------
412 config : Config
412 config : Config
413 The resulting Config object.
413 The resulting Config object.
414
414
415 Examples
415 Examples
416 --------
416 --------
417
417
418 >>> from IPython.config.loader import KeyValueConfigLoader
418 >>> from IPython.config.loader import KeyValueConfigLoader
419 >>> cl = KeyValueConfigLoader()
419 >>> cl = KeyValueConfigLoader()
420 >>> d = cl.load_config(["--A.name='brian'","--B.number=0"])
420 >>> d = cl.load_config(["--A.name='brian'","--B.number=0"])
421 >>> sorted(d.items())
421 >>> sorted(d.items())
422 [('A', {'name': 'brian'}), ('B', {'number': 0})]
422 [('A', {'name': 'brian'}), ('B', {'number': 0})]
423 """
423 """
424 self.clear()
424 self.clear()
425 if argv is None:
425 if argv is None:
426 argv = sys.argv[1:]
426 argv = sys.argv[1:]
427 self.argv = argv
427 self.argv = argv
428 self.aliases = aliases or {}
428 self.aliases = aliases or {}
429 self.flags = flags or {}
429 self.flags = flags or {}
430
430
431
431
432 def clear(self):
432 def clear(self):
433 super(KeyValueConfigLoader, self).clear()
433 super(KeyValueConfigLoader, self).clear()
434 self.extra_args = []
434 self.extra_args = []
435
435
436
436
437 def _decode_argv(self, argv, enc=None):
437 def _decode_argv(self, argv, enc=None):
438 """decode argv if bytes, using stin.encoding, falling back on default enc"""
438 """decode argv if bytes, using stin.encoding, falling back on default enc"""
439 uargv = []
439 uargv = []
440 if enc is None:
440 if enc is None:
441 enc = DEFAULT_ENCODING
441 enc = DEFAULT_ENCODING
442 for arg in argv:
442 for arg in argv:
443 if not isinstance(arg, unicode):
443 if not isinstance(arg, unicode):
444 # only decode if not already decoded
444 # only decode if not already decoded
445 arg = arg.decode(enc)
445 arg = arg.decode(enc)
446 uargv.append(arg)
446 uargv.append(arg)
447 return uargv
447 return uargv
448
448
449
449
450 def load_config(self, argv=None, aliases=None, flags=None):
450 def load_config(self, argv=None, aliases=None, flags=None):
451 """Parse the configuration and generate the Config object.
451 """Parse the configuration and generate the Config object.
452
452
453 After loading, any arguments that are not key-value or
453 After loading, any arguments that are not key-value or
454 flags will be stored in self.extra_args - a list of
454 flags will be stored in self.extra_args - a list of
455 unparsed command-line arguments. This is used for
455 unparsed command-line arguments. This is used for
456 arguments such as input files or subcommands.
456 arguments such as input files or subcommands.
457
457
458 Parameters
458 Parameters
459 ----------
459 ----------
460 argv : list, optional
460 argv : list, optional
461 A list that has the form of sys.argv[1:] which has unicode
461 A list that has the form of sys.argv[1:] which has unicode
462 elements of the form u"key=value". If this is None (default),
462 elements of the form u"key=value". If this is None (default),
463 then self.argv will be used.
463 then self.argv will be used.
464 aliases : dict
464 aliases : dict
465 A dict of aliases for configurable traits.
465 A dict of aliases for configurable traits.
466 Keys are the short aliases, Values are the resolved trait.
466 Keys are the short aliases, Values are the resolved trait.
467 Of the form: `{'alias' : 'Configurable.trait'}`
467 Of the form: `{'alias' : 'Configurable.trait'}`
468 flags : dict
468 flags : dict
469 A dict of flags, keyed by str name. Values can be Config objects
469 A dict of flags, keyed by str name. Values can be Config objects
470 or dicts. When the flag is triggered, The config is loaded as
470 or dicts. When the flag is triggered, The config is loaded as
471 `self.config.update(cfg)`.
471 `self.config.update(cfg)`.
472 """
472 """
473 from IPython.config.configurable import Configurable
473 from IPython.config.configurable import Configurable
474
474
475 self.clear()
475 self.clear()
476 if argv is None:
476 if argv is None:
477 argv = self.argv
477 argv = self.argv
478 if aliases is None:
478 if aliases is None:
479 aliases = self.aliases
479 aliases = self.aliases
480 if flags is None:
480 if flags is None:
481 flags = self.flags
481 flags = self.flags
482
482
483 # ensure argv is a list of unicode strings:
483 # ensure argv is a list of unicode strings:
484 uargv = self._decode_argv(argv)
484 uargv = self._decode_argv(argv)
485 for idx,raw in enumerate(uargv):
485 for idx,raw in enumerate(uargv):
486 # strip leading '-'
486 # strip leading '-'
487 item = raw.lstrip('-')
487 item = raw.lstrip('-')
488
488
489 if raw == '--':
489 if raw == '--':
490 # don't parse arguments after '--'
490 # don't parse arguments after '--'
491 # this is useful for relaying arguments to scripts, e.g.
491 # this is useful for relaying arguments to scripts, e.g.
492 # ipython -i foo.py --pylab=qt -- args after '--' go-to-foo.py
492 # ipython -i foo.py --pylab=qt -- args after '--' go-to-foo.py
493 self.extra_args.extend(uargv[idx+1:])
493 self.extra_args.extend(uargv[idx+1:])
494 break
494 break
495
495
496 if kv_pattern.match(raw):
496 if kv_pattern.match(raw):
497 lhs,rhs = item.split('=',1)
497 lhs,rhs = item.split('=',1)
498 # Substitute longnames for aliases.
498 # Substitute longnames for aliases.
499 if lhs in aliases:
499 if lhs in aliases:
500 lhs = aliases[lhs]
500 lhs = aliases[lhs]
501 if '.' not in lhs:
501 if '.' not in lhs:
502 # probably a mistyped alias, but not technically illegal
502 # probably a mistyped alias, but not technically illegal
503 warn.warn("Unrecognized alias: '%s', it will probably have no effect."%lhs)
503 warn.warn("Unrecognized alias: '%s', it will probably have no effect."%lhs)
504 try:
504 try:
505 self._exec_config_str(lhs, rhs)
505 self._exec_config_str(lhs, rhs)
506 except Exception:
506 except Exception:
507 raise ArgumentError("Invalid argument: '%s'" % raw)
507 raise ArgumentError("Invalid argument: '%s'" % raw)
508
508
509 elif flag_pattern.match(raw):
509 elif flag_pattern.match(raw):
510 if item in flags:
510 if item in flags:
511 cfg,help = flags[item]
511 cfg,help = flags[item]
512 self._load_flag(cfg)
512 self._load_flag(cfg)
513 else:
513 else:
514 raise ArgumentError("Unrecognized flag: '%s'"%raw)
514 raise ArgumentError("Unrecognized flag: '%s'"%raw)
515 elif raw.startswith('-'):
515 elif raw.startswith('-'):
516 kv = '--'+item
516 kv = '--'+item
517 if kv_pattern.match(kv):
517 if kv_pattern.match(kv):
518 raise ArgumentError("Invalid argument: '%s', did you mean '%s'?"%(raw, kv))
518 raise ArgumentError("Invalid argument: '%s', did you mean '%s'?"%(raw, kv))
519 else:
519 else:
520 raise ArgumentError("Invalid argument: '%s'"%raw)
520 raise ArgumentError("Invalid argument: '%s'"%raw)
521 else:
521 else:
522 # keep all args that aren't valid in a list,
522 # keep all args that aren't valid in a list,
523 # in case our parent knows what to do with them.
523 # in case our parent knows what to do with them.
524 self.extra_args.append(item)
524 self.extra_args.append(item)
525 return self.config
525 return self.config
526
526
527 class ArgParseConfigLoader(CommandLineConfigLoader):
527 class ArgParseConfigLoader(CommandLineConfigLoader):
528 """A loader that uses the argparse module to load from the command line."""
528 """A loader that uses the argparse module to load from the command line."""
529
529
530 def __init__(self, argv=None, aliases=None, flags=None, *parser_args, **parser_kw):
530 def __init__(self, argv=None, aliases=None, flags=None, *parser_args, **parser_kw):
531 """Create a config loader for use with argparse.
531 """Create a config loader for use with argparse.
532
532
533 Parameters
533 Parameters
534 ----------
534 ----------
535
535
536 argv : optional, list
536 argv : optional, list
537 If given, used to read command-line arguments from, otherwise
537 If given, used to read command-line arguments from, otherwise
538 sys.argv[1:] is used.
538 sys.argv[1:] is used.
539
539
540 parser_args : tuple
540 parser_args : tuple
541 A tuple of positional arguments that will be passed to the
541 A tuple of positional arguments that will be passed to the
542 constructor of :class:`argparse.ArgumentParser`.
542 constructor of :class:`argparse.ArgumentParser`.
543
543
544 parser_kw : dict
544 parser_kw : dict
545 A tuple of keyword arguments that will be passed to the
545 A tuple of keyword arguments that will be passed to the
546 constructor of :class:`argparse.ArgumentParser`.
546 constructor of :class:`argparse.ArgumentParser`.
547
547
548 Returns
548 Returns
549 -------
549 -------
550 config : Config
550 config : Config
551 The resulting Config object.
551 The resulting Config object.
552 """
552 """
553 super(CommandLineConfigLoader, self).__init__()
553 super(CommandLineConfigLoader, self).__init__()
554 self.clear()
554 self.clear()
555 if argv is None:
555 if argv is None:
556 argv = sys.argv[1:]
556 argv = sys.argv[1:]
557 self.argv = argv
557 self.argv = argv
558 self.aliases = aliases or {}
558 self.aliases = aliases or {}
559 self.flags = flags or {}
559 self.flags = flags or {}
560
560
561 self.parser_args = parser_args
561 self.parser_args = parser_args
562 self.version = parser_kw.pop("version", None)
562 self.version = parser_kw.pop("version", None)
563 kwargs = dict(argument_default=argparse.SUPPRESS)
563 kwargs = dict(argument_default=argparse.SUPPRESS)
564 kwargs.update(parser_kw)
564 kwargs.update(parser_kw)
565 self.parser_kw = kwargs
565 self.parser_kw = kwargs
566
566
567 def load_config(self, argv=None, aliases=None, flags=None):
567 def load_config(self, argv=None, aliases=None, flags=None):
568 """Parse command line arguments and return as a Config object.
568 """Parse command line arguments and return as a Config object.
569
569
570 Parameters
570 Parameters
571 ----------
571 ----------
572
572
573 args : optional, list
573 args : optional, list
574 If given, a list with the structure of sys.argv[1:] to parse
574 If given, a list with the structure of sys.argv[1:] to parse
575 arguments from. If not given, the instance's self.argv attribute
575 arguments from. If not given, the instance's self.argv attribute
576 (given at construction time) is used."""
576 (given at construction time) is used."""
577 self.clear()
577 self.clear()
578 if argv is None:
578 if argv is None:
579 argv = self.argv
579 argv = self.argv
580 if aliases is None:
580 if aliases is None:
581 aliases = self.aliases
581 aliases = self.aliases
582 if flags is None:
582 if flags is None:
583 flags = self.flags
583 flags = self.flags
584 self._create_parser(aliases, flags)
584 self._create_parser(aliases, flags)
585 self._parse_args(argv)
585 self._parse_args(argv)
586 self._convert_to_config()
586 self._convert_to_config()
587 return self.config
587 return self.config
588
588
589 def get_extra_args(self):
589 def get_extra_args(self):
590 if hasattr(self, 'extra_args'):
590 if hasattr(self, 'extra_args'):
591 return self.extra_args
591 return self.extra_args
592 else:
592 else:
593 return []
593 return []
594
594
595 def _create_parser(self, aliases=None, flags=None):
595 def _create_parser(self, aliases=None, flags=None):
596 self.parser = ArgumentParser(*self.parser_args, **self.parser_kw)
596 self.parser = ArgumentParser(*self.parser_args, **self.parser_kw)
597 self._add_arguments(aliases, flags)
597 self._add_arguments(aliases, flags)
598
598
599 def _add_arguments(self, aliases=None, flags=None):
599 def _add_arguments(self, aliases=None, flags=None):
600 raise NotImplementedError("subclasses must implement _add_arguments")
600 raise NotImplementedError("subclasses must implement _add_arguments")
601
601
602 def _parse_args(self, args):
602 def _parse_args(self, args):
603 """self.parser->self.parsed_data"""
603 """self.parser->self.parsed_data"""
604 # decode sys.argv to support unicode command-line options
604 # decode sys.argv to support unicode command-line options
605 enc = DEFAULT_ENCODING
605 enc = DEFAULT_ENCODING
606 uargs = [py3compat.cast_unicode(a, enc) for a in args]
606 uargs = [py3compat.cast_unicode(a, enc) for a in args]
607 self.parsed_data, self.extra_args = self.parser.parse_known_args(uargs)
607 self.parsed_data, self.extra_args = self.parser.parse_known_args(uargs)
608
608
609 def _convert_to_config(self):
609 def _convert_to_config(self):
610 """self.parsed_data->self.config"""
610 """self.parsed_data->self.config"""
611 for k, v in vars(self.parsed_data).iteritems():
611 for k, v in vars(self.parsed_data).iteritems():
612 exec "self.config.%s = v"%k in locals(), globals()
612 exec "self.config.%s = v"%k in locals(), globals()
613
613
614 class KVArgParseConfigLoader(ArgParseConfigLoader):
614 class KVArgParseConfigLoader(ArgParseConfigLoader):
615 """A config loader that loads aliases and flags with argparse,
615 """A config loader that loads aliases and flags with argparse,
616 but will use KVLoader for the rest. This allows better parsing
616 but will use KVLoader for the rest. This allows better parsing
617 of common args, such as `ipython -c 'print 5'`, but still gets
617 of common args, such as `ipython -c 'print 5'`, but still gets
618 arbitrary config with `ipython --InteractiveShell.use_readline=False`"""
618 arbitrary config with `ipython --InteractiveShell.use_readline=False`"""
619
619
620 def _add_arguments(self, aliases=None, flags=None):
620 def _add_arguments(self, aliases=None, flags=None):
621 self.alias_flags = {}
621 self.alias_flags = {}
622 # print aliases, flags
622 # print aliases, flags
623 if aliases is None:
623 if aliases is None:
624 aliases = self.aliases
624 aliases = self.aliases
625 if flags is None:
625 if flags is None:
626 flags = self.flags
626 flags = self.flags
627 paa = self.parser.add_argument
627 paa = self.parser.add_argument
628 for key,value in aliases.iteritems():
628 for key,value in aliases.iteritems():
629 if key in flags:
629 if key in flags:
630 # flags
630 # flags
631 nargs = '?'
631 nargs = '?'
632 else:
632 else:
633 nargs = None
633 nargs = None
634 if len(key) is 1:
634 if len(key) is 1:
635 paa('-'+key, '--'+key, type=unicode, dest=value, nargs=nargs)
635 paa('-'+key, '--'+key, type=unicode, dest=value, nargs=nargs)
636 else:
636 else:
637 paa('--'+key, type=unicode, dest=value, nargs=nargs)
637 paa('--'+key, type=unicode, dest=value, nargs=nargs)
638 for key, (value, help) in flags.iteritems():
638 for key, (value, help) in flags.iteritems():
639 if key in self.aliases:
639 if key in self.aliases:
640 #
640 #
641 self.alias_flags[self.aliases[key]] = value
641 self.alias_flags[self.aliases[key]] = value
642 continue
642 continue
643 if len(key) is 1:
643 if len(key) is 1:
644 paa('-'+key, '--'+key, action='append_const', dest='_flags', const=value)
644 paa('-'+key, '--'+key, action='append_const', dest='_flags', const=value)
645 else:
645 else:
646 paa('--'+key, action='append_const', dest='_flags', const=value)
646 paa('--'+key, action='append_const', dest='_flags', const=value)
647
647
648 def _convert_to_config(self):
648 def _convert_to_config(self):
649 """self.parsed_data->self.config, parse unrecognized extra args via KVLoader."""
649 """self.parsed_data->self.config, parse unrecognized extra args via KVLoader."""
650 # remove subconfigs list from namespace before transforming the Namespace
650 # remove subconfigs list from namespace before transforming the Namespace
651 if '_flags' in self.parsed_data:
651 if '_flags' in self.parsed_data:
652 subcs = self.parsed_data._flags
652 subcs = self.parsed_data._flags
653 del self.parsed_data._flags
653 del self.parsed_data._flags
654 else:
654 else:
655 subcs = []
655 subcs = []
656
656
657 for k, v in vars(self.parsed_data).iteritems():
657 for k, v in vars(self.parsed_data).iteritems():
658 if v is None:
658 if v is None:
659 # it was a flag that shares the name of an alias
659 # it was a flag that shares the name of an alias
660 subcs.append(self.alias_flags[k])
660 subcs.append(self.alias_flags[k])
661 else:
661 else:
662 # eval the KV assignment
662 # eval the KV assignment
663 self._exec_config_str(k, v)
663 self._exec_config_str(k, v)
664
664
665 for subc in subcs:
665 for subc in subcs:
666 self._load_flag(subc)
666 self._load_flag(subc)
667
667
668 if self.extra_args:
668 if self.extra_args:
669 sub_parser = KeyValueConfigLoader()
669 sub_parser = KeyValueConfigLoader()
670 sub_parser.load_config(self.extra_args)
670 sub_parser.load_config(self.extra_args)
671 self.config._merge(sub_parser.config)
671 self.config._merge(sub_parser.config)
672 self.extra_args = sub_parser.extra_args
672 self.extra_args = sub_parser.extra_args
673
673
674
674
675 def load_pyconfig_files(config_files, path):
675 def load_pyconfig_files(config_files, path):
676 """Load multiple Python config files, merging each of them in turn.
676 """Load multiple Python config files, merging each of them in turn.
677
677
678 Parameters
678 Parameters
679 ==========
679 ==========
680 config_files : list of str
680 config_files : list of str
681 List of config files names to load and merge into the config.
681 List of config files names to load and merge into the config.
682 path : unicode
682 path : unicode
683 The full path to the location of the config files.
683 The full path to the location of the config files.
684 """
684 """
685 config = Config()
685 config = Config()
686 for cf in config_files:
686 for cf in config_files:
687 loader = PyFileConfigLoader(cf, path=path)
687 loader = PyFileConfigLoader(cf, path=path)
688 try:
688 try:
689 next_config = loader.load_config()
689 next_config = loader.load_config()
690 except ConfigFileNotFound:
690 except ConfigFileNotFound:
691 pass
691 pass
692 except:
692 except:
693 raise
693 raise
694 else:
694 else:
695 config._merge(next_config)
695 config._merge(next_config)
696 return config
696 return config
@@ -1,263 +1,263 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Tests for IPython.config.loader
3 Tests for IPython.config.loader
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 * Fernando Perez (design help)
8 * Fernando Perez (design help)
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 import os
22 import os
23 import sys
23 import sys
24 from tempfile import mkstemp
24 from tempfile import mkstemp
25 from unittest import TestCase
25 from unittest import TestCase
26
26
27 from nose import SkipTest
27 from nose import SkipTest
28
28
29 from IPython.testing.tools import mute_warn
29 from IPython.testing.tools import mute_warn
30
30
31 from IPython.utils.traitlets import Unicode
31 from IPython.utils.traitlets import Unicode
32 from IPython.config.configurable import Configurable
32 from IPython.config.configurable import Configurable
33 from IPython.config.loader import (
33 from IPython.config.loader import (
34 Config,
34 Config,
35 PyFileConfigLoader,
35 PyFileConfigLoader,
36 KeyValueConfigLoader,
36 KeyValueConfigLoader,
37 ArgParseConfigLoader,
37 ArgParseConfigLoader,
38 KVArgParseConfigLoader,
38 KVArgParseConfigLoader,
39 ConfigError
39 ConfigError
40 )
40 )
41
41
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Actual tests
43 # Actual tests
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45
45
46
46
47 pyfile = """
47 pyfile = """
48 c = get_config()
48 c = get_config()
49 c.a=10
49 c.a=10
50 c.b=20
50 c.b=20
51 c.Foo.Bar.value=10
51 c.Foo.Bar.value=10
52 c.Foo.Bam.value=list(range(10)) # list() is just so it's the same on Python 3
52 c.Foo.Bam.value=list(range(10)) # list() is just so it's the same on Python 3
53 c.D.C.value='hi there'
53 c.D.C.value='hi there'
54 """
54 """
55
55
56 class TestPyFileCL(TestCase):
56 class TestPyFileCL(TestCase):
57
57
58 def test_basic(self):
58 def test_basic(self):
59 fd, fname = mkstemp('.py')
59 fd, fname = mkstemp('.py')
60 f = os.fdopen(fd, 'w')
60 f = os.fdopen(fd, 'w')
61 f.write(pyfile)
61 f.write(pyfile)
62 f.close()
62 f.close()
63 # Unlink the file
63 # Unlink the file
64 cl = PyFileConfigLoader(fname)
64 cl = PyFileConfigLoader(fname)
65 config = cl.load_config()
65 config = cl.load_config()
66 self.assertEquals(config.a, 10)
66 self.assertEquals(config.a, 10)
67 self.assertEquals(config.b, 20)
67 self.assertEquals(config.b, 20)
68 self.assertEquals(config.Foo.Bar.value, 10)
68 self.assertEquals(config.Foo.Bar.value, 10)
69 self.assertEquals(config.Foo.Bam.value, range(10))
69 self.assertEquals(config.Foo.Bam.value, range(10))
70 self.assertEquals(config.D.C.value, 'hi there')
70 self.assertEquals(config.D.C.value, 'hi there')
71
71
72 class MyLoader1(ArgParseConfigLoader):
72 class MyLoader1(ArgParseConfigLoader):
73 def _add_arguments(self, aliases=None, flags=None):
73 def _add_arguments(self, aliases=None, flags=None):
74 p = self.parser
74 p = self.parser
75 p.add_argument('-f', '--foo', dest='Global.foo', type=str)
75 p.add_argument('-f', '--foo', dest='Global.foo', type=str)
76 p.add_argument('-b', dest='MyClass.bar', type=int)
76 p.add_argument('-b', dest='MyClass.bar', type=int)
77 p.add_argument('-n', dest='n', action='store_true')
77 p.add_argument('-n', dest='n', action='store_true')
78 p.add_argument('Global.bam', type=str)
78 p.add_argument('Global.bam', type=str)
79
79
80 class MyLoader2(ArgParseConfigLoader):
80 class MyLoader2(ArgParseConfigLoader):
81 def _add_arguments(self, aliases=None, flags=None):
81 def _add_arguments(self, aliases=None, flags=None):
82 subparsers = self.parser.add_subparsers(dest='subparser_name')
82 subparsers = self.parser.add_subparsers(dest='subparser_name')
83 subparser1 = subparsers.add_parser('1')
83 subparser1 = subparsers.add_parser('1')
84 subparser1.add_argument('-x',dest='Global.x')
84 subparser1.add_argument('-x',dest='Global.x')
85 subparser2 = subparsers.add_parser('2')
85 subparser2 = subparsers.add_parser('2')
86 subparser2.add_argument('y')
86 subparser2.add_argument('y')
87
87
88 class TestArgParseCL(TestCase):
88 class TestArgParseCL(TestCase):
89
89
90 def test_basic(self):
90 def test_basic(self):
91 cl = MyLoader1()
91 cl = MyLoader1()
92 config = cl.load_config('-f hi -b 10 -n wow'.split())
92 config = cl.load_config('-f hi -b 10 -n wow'.split())
93 self.assertEquals(config.Global.foo, 'hi')
93 self.assertEquals(config.Global.foo, 'hi')
94 self.assertEquals(config.MyClass.bar, 10)
94 self.assertEquals(config.MyClass.bar, 10)
95 self.assertEquals(config.n, True)
95 self.assertEquals(config.n, True)
96 self.assertEquals(config.Global.bam, 'wow')
96 self.assertEquals(config.Global.bam, 'wow')
97 config = cl.load_config(['wow'])
97 config = cl.load_config(['wow'])
98 self.assertEquals(config.keys(), ['Global'])
98 self.assertEquals(config.keys(), ['Global'])
99 self.assertEquals(config.Global.keys(), ['bam'])
99 self.assertEquals(config.Global.keys(), ['bam'])
100 self.assertEquals(config.Global.bam, 'wow')
100 self.assertEquals(config.Global.bam, 'wow')
101
101
102 def test_add_arguments(self):
102 def test_add_arguments(self):
103 cl = MyLoader2()
103 cl = MyLoader2()
104 config = cl.load_config('2 frobble'.split())
104 config = cl.load_config('2 frobble'.split())
105 self.assertEquals(config.subparser_name, '2')
105 self.assertEquals(config.subparser_name, '2')
106 self.assertEquals(config.y, 'frobble')
106 self.assertEquals(config.y, 'frobble')
107 config = cl.load_config('1 -x frobble'.split())
107 config = cl.load_config('1 -x frobble'.split())
108 self.assertEquals(config.subparser_name, '1')
108 self.assertEquals(config.subparser_name, '1')
109 self.assertEquals(config.Global.x, 'frobble')
109 self.assertEquals(config.Global.x, 'frobble')
110
110
111 def test_argv(self):
111 def test_argv(self):
112 cl = MyLoader1(argv='-f hi -b 10 -n wow'.split())
112 cl = MyLoader1(argv='-f hi -b 10 -n wow'.split())
113 config = cl.load_config()
113 config = cl.load_config()
114 self.assertEquals(config.Global.foo, 'hi')
114 self.assertEquals(config.Global.foo, 'hi')
115 self.assertEquals(config.MyClass.bar, 10)
115 self.assertEquals(config.MyClass.bar, 10)
116 self.assertEquals(config.n, True)
116 self.assertEquals(config.n, True)
117 self.assertEquals(config.Global.bam, 'wow')
117 self.assertEquals(config.Global.bam, 'wow')
118
118
119
119
120 class TestKeyValueCL(TestCase):
120 class TestKeyValueCL(TestCase):
121 klass = KeyValueConfigLoader
121 klass = KeyValueConfigLoader
122
122
123 def test_basic(self):
123 def test_basic(self):
124 cl = self.klass()
124 cl = self.klass()
125 argv = ['--'+s.strip('c.') for s in pyfile.split('\n')[2:-1]]
125 argv = ['--'+s.strip('c.') for s in pyfile.split('\n')[2:-1]]
126 with mute_warn():
126 with mute_warn():
127 config = cl.load_config(argv)
127 config = cl.load_config(argv)
128 self.assertEquals(config.a, 10)
128 self.assertEquals(config.a, 10)
129 self.assertEquals(config.b, 20)
129 self.assertEquals(config.b, 20)
130 self.assertEquals(config.Foo.Bar.value, 10)
130 self.assertEquals(config.Foo.Bar.value, 10)
131 self.assertEquals(config.Foo.Bam.value, range(10))
131 self.assertEquals(config.Foo.Bam.value, range(10))
132 self.assertEquals(config.D.C.value, 'hi there')
132 self.assertEquals(config.D.C.value, 'hi there')
133
133
134 def test_expanduser(self):
134 def test_expanduser(self):
135 cl = self.klass()
135 cl = self.klass()
136 argv = ['--a=~/1/2/3', '--b=~', '--c=~/', '--d="~/"']
136 argv = ['--a=~/1/2/3', '--b=~', '--c=~/', '--d="~/"']
137 with mute_warn():
137 with mute_warn():
138 config = cl.load_config(argv)
138 config = cl.load_config(argv)
139 self.assertEquals(config.a, os.path.expanduser('~/1/2/3'))
139 self.assertEquals(config.a, os.path.expanduser('~/1/2/3'))
140 self.assertEquals(config.b, os.path.expanduser('~'))
140 self.assertEquals(config.b, os.path.expanduser('~'))
141 self.assertEquals(config.c, os.path.expanduser('~/'))
141 self.assertEquals(config.c, os.path.expanduser('~/'))
142 self.assertEquals(config.d, '~/')
142 self.assertEquals(config.d, '~/')
143
143
144 def test_extra_args(self):
144 def test_extra_args(self):
145 cl = self.klass()
145 cl = self.klass()
146 with mute_warn():
146 with mute_warn():
147 config = cl.load_config(['--a=5', 'b', '--c=10', 'd'])
147 config = cl.load_config(['--a=5', 'b', '--c=10', 'd'])
148 self.assertEquals(cl.extra_args, ['b', 'd'])
148 self.assertEquals(cl.extra_args, ['b', 'd'])
149 self.assertEquals(config.a, 5)
149 self.assertEquals(config.a, 5)
150 self.assertEquals(config.c, 10)
150 self.assertEquals(config.c, 10)
151 with mute_warn():
151 with mute_warn():
152 config = cl.load_config(['--', '--a=5', '--c=10'])
152 config = cl.load_config(['--', '--a=5', '--c=10'])
153 self.assertEquals(cl.extra_args, ['--a=5', '--c=10'])
153 self.assertEquals(cl.extra_args, ['--a=5', '--c=10'])
154
154
155 def test_unicode_args(self):
155 def test_unicode_args(self):
156 cl = self.klass()
156 cl = self.klass()
157 argv = [u'--a=épsîlön']
157 argv = [u'--a=épsîlön']
158 with mute_warn():
158 with mute_warn():
159 config = cl.load_config(argv)
159 config = cl.load_config(argv)
160 self.assertEquals(config.a, u'épsîlön')
160 self.assertEquals(config.a, u'épsîlön')
161
161
162 def test_unicode_bytes_args(self):
162 def test_unicode_bytes_args(self):
163 uarg = u'--a=é'
163 uarg = u'--a=é'
164 try:
164 try:
165 barg = uarg.encode(sys.stdin.encoding)
165 barg = uarg.encode(sys.stdin.encoding)
166 except (TypeError, UnicodeEncodeError):
166 except (TypeError, UnicodeEncodeError):
167 raise SkipTest("sys.stdin.encoding can't handle 'é'")
167 raise SkipTest("sys.stdin.encoding can't handle 'é'")
168
168
169 cl = self.klass()
169 cl = self.klass()
170 with mute_warn():
170 with mute_warn():
171 config = cl.load_config([barg])
171 config = cl.load_config([barg])
172 self.assertEquals(config.a, u'é')
172 self.assertEquals(config.a, u'é')
173
173
174 def test_unicode_alias(self):
174 def test_unicode_alias(self):
175 cl = self.klass()
175 cl = self.klass()
176 argv = [u'--a=épsîlön']
176 argv = [u'--a=épsîlön']
177 with mute_warn():
177 with mute_warn():
178 config = cl.load_config(argv, aliases=dict(a='A.a'))
178 config = cl.load_config(argv, aliases=dict(a='A.a'))
179 self.assertEquals(config.A.a, u'épsîlön')
179 self.assertEquals(config.A.a, u'épsîlön')
180
180
181
181
182 class TestArgParseKVCL(TestKeyValueCL):
182 class TestArgParseKVCL(TestKeyValueCL):
183 klass = KVArgParseConfigLoader
183 klass = KVArgParseConfigLoader
184
184
185 def test_expanduser2(self):
185 def test_expanduser2(self):
186 cl = self.klass()
186 cl = self.klass()
187 argv = ['-a', '~/1/2/3', '--b', "'~/1/2/3'"]
187 argv = ['-a', '~/1/2/3', '--b', "'~/1/2/3'"]
188 with mute_warn():
188 with mute_warn():
189 config = cl.load_config(argv, aliases=dict(a='A.a', b='A.b'))
189 config = cl.load_config(argv, aliases=dict(a='A.a', b='A.b'))
190 self.assertEquals(config.A.a, os.path.expanduser('~/1/2/3'))
190 self.assertEquals(config.A.a, os.path.expanduser('~/1/2/3'))
191 self.assertEquals(config.A.b, '~/1/2/3')
191 self.assertEquals(config.A.b, '~/1/2/3')
192
192
193 def test_eval(self):
193 def test_eval(self):
194 cl = self.klass()
194 cl = self.klass()
195 argv = ['-c', 'a=5']
195 argv = ['-c', 'a=5']
196 with mute_warn():
196 with mute_warn():
197 config = cl.load_config(argv, aliases=dict(c='A.c'))
197 config = cl.load_config(argv, aliases=dict(c='A.c'))
198 self.assertEquals(config.A.c, u"a=5")
198 self.assertEquals(config.A.c, u"a=5")
199
199
200
200
201 class TestConfig(TestCase):
201 class TestConfig(TestCase):
202
202
203 def test_setget(self):
203 def test_setget(self):
204 c = Config()
204 c = Config()
205 c.a = 10
205 c.a = 10
206 self.assertEquals(c.a, 10)
206 self.assertEquals(c.a, 10)
207 self.assertEquals(c.has_key('b'), False)
207 self.assertEquals('b' in c, False)
208
208
209 def test_auto_section(self):
209 def test_auto_section(self):
210 c = Config()
210 c = Config()
211 self.assertEquals(c.has_key('A'), True)
211 self.assertEquals('A' in c, True)
212 self.assertEquals(c._has_section('A'), False)
212 self.assertEquals(c._has_section('A'), False)
213 A = c.A
213 A = c.A
214 A.foo = 'hi there'
214 A.foo = 'hi there'
215 self.assertEquals(c._has_section('A'), True)
215 self.assertEquals(c._has_section('A'), True)
216 self.assertEquals(c.A.foo, 'hi there')
216 self.assertEquals(c.A.foo, 'hi there')
217 del c.A
217 del c.A
218 self.assertEquals(len(c.A.keys()),0)
218 self.assertEquals(len(c.A.keys()),0)
219
219
220 def test_merge_doesnt_exist(self):
220 def test_merge_doesnt_exist(self):
221 c1 = Config()
221 c1 = Config()
222 c2 = Config()
222 c2 = Config()
223 c2.bar = 10
223 c2.bar = 10
224 c2.Foo.bar = 10
224 c2.Foo.bar = 10
225 c1._merge(c2)
225 c1._merge(c2)
226 self.assertEquals(c1.Foo.bar, 10)
226 self.assertEquals(c1.Foo.bar, 10)
227 self.assertEquals(c1.bar, 10)
227 self.assertEquals(c1.bar, 10)
228 c2.Bar.bar = 10
228 c2.Bar.bar = 10
229 c1._merge(c2)
229 c1._merge(c2)
230 self.assertEquals(c1.Bar.bar, 10)
230 self.assertEquals(c1.Bar.bar, 10)
231
231
232 def test_merge_exists(self):
232 def test_merge_exists(self):
233 c1 = Config()
233 c1 = Config()
234 c2 = Config()
234 c2 = Config()
235 c1.Foo.bar = 10
235 c1.Foo.bar = 10
236 c1.Foo.bam = 30
236 c1.Foo.bam = 30
237 c2.Foo.bar = 20
237 c2.Foo.bar = 20
238 c2.Foo.wow = 40
238 c2.Foo.wow = 40
239 c1._merge(c2)
239 c1._merge(c2)
240 self.assertEquals(c1.Foo.bam, 30)
240 self.assertEquals(c1.Foo.bam, 30)
241 self.assertEquals(c1.Foo.bar, 20)
241 self.assertEquals(c1.Foo.bar, 20)
242 self.assertEquals(c1.Foo.wow, 40)
242 self.assertEquals(c1.Foo.wow, 40)
243 c2.Foo.Bam.bam = 10
243 c2.Foo.Bam.bam = 10
244 c1._merge(c2)
244 c1._merge(c2)
245 self.assertEquals(c1.Foo.Bam.bam, 10)
245 self.assertEquals(c1.Foo.Bam.bam, 10)
246
246
247 def test_deepcopy(self):
247 def test_deepcopy(self):
248 c1 = Config()
248 c1 = Config()
249 c1.Foo.bar = 10
249 c1.Foo.bar = 10
250 c1.Foo.bam = 30
250 c1.Foo.bam = 30
251 c1.a = 'asdf'
251 c1.a = 'asdf'
252 c1.b = range(10)
252 c1.b = range(10)
253 import copy
253 import copy
254 c2 = copy.deepcopy(c1)
254 c2 = copy.deepcopy(c1)
255 self.assertEquals(c1, c2)
255 self.assertEquals(c1, c2)
256 self.assert_(c1 is not c2)
256 self.assert_(c1 is not c2)
257 self.assert_(c1.Foo is not c2.Foo)
257 self.assert_(c1.Foo is not c2.Foo)
258
258
259 def test_builtin(self):
259 def test_builtin(self):
260 c1 = Config()
260 c1 = Config()
261 exec 'foo = True' in c1
261 exec 'foo = True' in c1
262 self.assertEquals(c1.foo, True)
262 self.assertEquals(c1.foo, True)
263 self.assertRaises(ConfigError, setattr, c1, 'ValueError', 10)
263 self.assertRaises(ConfigError, setattr, c1, 'ValueError', 10)
@@ -1,263 +1,263 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 System command aliases.
3 System command aliases.
4
4
5 Authors:
5 Authors:
6
6
7 * Fernando Perez
7 * Fernando Perez
8 * Brian Granger
8 * Brian Granger
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License.
14 # Distributed under the terms of the BSD License.
15 #
15 #
16 # The full license is in the file COPYING.txt, distributed with this software.
16 # The full license is in the file COPYING.txt, distributed with this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import __builtin__
23 import __builtin__
24 import keyword
24 import keyword
25 import os
25 import os
26 import re
26 import re
27 import sys
27 import sys
28
28
29 from IPython.config.configurable import Configurable
29 from IPython.config.configurable import Configurable
30 from IPython.core.splitinput import split_user_input
30 from IPython.core.splitinput import split_user_input
31
31
32 from IPython.utils.traitlets import List, Instance
32 from IPython.utils.traitlets import List, Instance
33 from IPython.utils.autoattr import auto_attr
33 from IPython.utils.autoattr import auto_attr
34 from IPython.utils.warn import warn, error
34 from IPython.utils.warn import warn, error
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Utilities
37 # Utilities
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40 # This is used as the pattern for calls to split_user_input.
40 # This is used as the pattern for calls to split_user_input.
41 shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')
41 shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')
42
42
43 def default_aliases():
43 def default_aliases():
44 """Return list of shell aliases to auto-define.
44 """Return list of shell aliases to auto-define.
45 """
45 """
46 # Note: the aliases defined here should be safe to use on a kernel
46 # Note: the aliases defined here should be safe to use on a kernel
47 # regardless of what frontend it is attached to. Frontends that use a
47 # regardless of what frontend it is attached to. Frontends that use a
48 # kernel in-process can define additional aliases that will only work in
48 # kernel in-process can define additional aliases that will only work in
49 # their case. For example, things like 'less' or 'clear' that manipulate
49 # their case. For example, things like 'less' or 'clear' that manipulate
50 # the terminal should NOT be declared here, as they will only work if the
50 # the terminal should NOT be declared here, as they will only work if the
51 # kernel is running inside a true terminal, and not over the network.
51 # kernel is running inside a true terminal, and not over the network.
52
52
53 if os.name == 'posix':
53 if os.name == 'posix':
54 default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
54 default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
55 ('mv', 'mv -i'), ('rm', 'rm -i'), ('cp', 'cp -i'),
55 ('mv', 'mv -i'), ('rm', 'rm -i'), ('cp', 'cp -i'),
56 ('cat', 'cat'),
56 ('cat', 'cat'),
57 ]
57 ]
58 # Useful set of ls aliases. The GNU and BSD options are a little
58 # Useful set of ls aliases. The GNU and BSD options are a little
59 # different, so we make aliases that provide as similar as possible
59 # different, so we make aliases that provide as similar as possible
60 # behavior in ipython, by passing the right flags for each platform
60 # behavior in ipython, by passing the right flags for each platform
61 if sys.platform.startswith('linux'):
61 if sys.platform.startswith('linux'):
62 ls_aliases = [('ls', 'ls -F --color'),
62 ls_aliases = [('ls', 'ls -F --color'),
63 # long ls
63 # long ls
64 ('ll', 'ls -F -o --color'),
64 ('ll', 'ls -F -o --color'),
65 # ls normal files only
65 # ls normal files only
66 ('lf', 'ls -F -o --color %l | grep ^-'),
66 ('lf', 'ls -F -o --color %l | grep ^-'),
67 # ls symbolic links
67 # ls symbolic links
68 ('lk', 'ls -F -o --color %l | grep ^l'),
68 ('lk', 'ls -F -o --color %l | grep ^l'),
69 # directories or links to directories,
69 # directories or links to directories,
70 ('ldir', 'ls -F -o --color %l | grep /$'),
70 ('ldir', 'ls -F -o --color %l | grep /$'),
71 # things which are executable
71 # things which are executable
72 ('lx', 'ls -F -o --color %l | grep ^-..x'),
72 ('lx', 'ls -F -o --color %l | grep ^-..x'),
73 ]
73 ]
74 else:
74 else:
75 # BSD, OSX, etc.
75 # BSD, OSX, etc.
76 ls_aliases = [('ls', 'ls -F'),
76 ls_aliases = [('ls', 'ls -F'),
77 # long ls
77 # long ls
78 ('ll', 'ls -F -l'),
78 ('ll', 'ls -F -l'),
79 # ls normal files only
79 # ls normal files only
80 ('lf', 'ls -F -l %l | grep ^-'),
80 ('lf', 'ls -F -l %l | grep ^-'),
81 # ls symbolic links
81 # ls symbolic links
82 ('lk', 'ls -F -l %l | grep ^l'),
82 ('lk', 'ls -F -l %l | grep ^l'),
83 # directories or links to directories,
83 # directories or links to directories,
84 ('ldir', 'ls -F -l %l | grep /$'),
84 ('ldir', 'ls -F -l %l | grep /$'),
85 # things which are executable
85 # things which are executable
86 ('lx', 'ls -F -l %l | grep ^-..x'),
86 ('lx', 'ls -F -l %l | grep ^-..x'),
87 ]
87 ]
88 default_aliases = default_aliases + ls_aliases
88 default_aliases = default_aliases + ls_aliases
89 elif os.name in ['nt', 'dos']:
89 elif os.name in ['nt', 'dos']:
90 default_aliases = [('ls', 'dir /on'),
90 default_aliases = [('ls', 'dir /on'),
91 ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
91 ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
92 ('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
92 ('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
93 ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
93 ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
94 ]
94 ]
95 else:
95 else:
96 default_aliases = []
96 default_aliases = []
97
97
98 return default_aliases
98 return default_aliases
99
99
100
100
101 class AliasError(Exception):
101 class AliasError(Exception):
102 pass
102 pass
103
103
104
104
105 class InvalidAliasError(AliasError):
105 class InvalidAliasError(AliasError):
106 pass
106 pass
107
107
108 #-----------------------------------------------------------------------------
108 #-----------------------------------------------------------------------------
109 # Main AliasManager class
109 # Main AliasManager class
110 #-----------------------------------------------------------------------------
110 #-----------------------------------------------------------------------------
111
111
112 class AliasManager(Configurable):
112 class AliasManager(Configurable):
113
113
114 default_aliases = List(default_aliases(), config=True)
114 default_aliases = List(default_aliases(), config=True)
115 user_aliases = List(default_value=[], config=True)
115 user_aliases = List(default_value=[], config=True)
116 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
116 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
117
117
118 def __init__(self, shell=None, config=None):
118 def __init__(self, shell=None, config=None):
119 super(AliasManager, self).__init__(shell=shell, config=config)
119 super(AliasManager, self).__init__(shell=shell, config=config)
120 self.alias_table = {}
120 self.alias_table = {}
121 self.exclude_aliases()
121 self.exclude_aliases()
122 self.init_aliases()
122 self.init_aliases()
123
123
124 def __contains__(self, name):
124 def __contains__(self, name):
125 return name in self.alias_table
125 return name in self.alias_table
126
126
127 @property
127 @property
128 def aliases(self):
128 def aliases(self):
129 return [(item[0], item[1][1]) for item in self.alias_table.iteritems()]
129 return [(item[0], item[1][1]) for item in self.alias_table.iteritems()]
130
130
131 def exclude_aliases(self):
131 def exclude_aliases(self):
132 # set of things NOT to alias (keywords, builtins and some magics)
132 # set of things NOT to alias (keywords, builtins and some magics)
133 no_alias = set(['cd','popd','pushd','dhist','alias','unalias'])
133 no_alias = set(['cd','popd','pushd','dhist','alias','unalias'])
134 no_alias.update(set(keyword.kwlist))
134 no_alias.update(set(keyword.kwlist))
135 no_alias.update(set(__builtin__.__dict__.keys()))
135 no_alias.update(set(__builtin__.__dict__.keys()))
136 self.no_alias = no_alias
136 self.no_alias = no_alias
137
137
138 def init_aliases(self):
138 def init_aliases(self):
139 # Load default aliases
139 # Load default aliases
140 for name, cmd in self.default_aliases:
140 for name, cmd in self.default_aliases:
141 self.soft_define_alias(name, cmd)
141 self.soft_define_alias(name, cmd)
142
142
143 # Load user aliases
143 # Load user aliases
144 for name, cmd in self.user_aliases:
144 for name, cmd in self.user_aliases:
145 self.soft_define_alias(name, cmd)
145 self.soft_define_alias(name, cmd)
146
146
147 def clear_aliases(self):
147 def clear_aliases(self):
148 self.alias_table.clear()
148 self.alias_table.clear()
149
149
150 def soft_define_alias(self, name, cmd):
150 def soft_define_alias(self, name, cmd):
151 """Define an alias, but don't raise on an AliasError."""
151 """Define an alias, but don't raise on an AliasError."""
152 try:
152 try:
153 self.define_alias(name, cmd)
153 self.define_alias(name, cmd)
154 except AliasError as e:
154 except AliasError as e:
155 error("Invalid alias: %s" % e)
155 error("Invalid alias: %s" % e)
156
156
157 def define_alias(self, name, cmd):
157 def define_alias(self, name, cmd):
158 """Define a new alias after validating it.
158 """Define a new alias after validating it.
159
159
160 This will raise an :exc:`AliasError` if there are validation
160 This will raise an :exc:`AliasError` if there are validation
161 problems.
161 problems.
162 """
162 """
163 nargs = self.validate_alias(name, cmd)
163 nargs = self.validate_alias(name, cmd)
164 self.alias_table[name] = (nargs, cmd)
164 self.alias_table[name] = (nargs, cmd)
165
165
166 def undefine_alias(self, name):
166 def undefine_alias(self, name):
167 if self.alias_table.has_key(name):
167 if name in self.alias_table:
168 del self.alias_table[name]
168 del self.alias_table[name]
169
169
170 def validate_alias(self, name, cmd):
170 def validate_alias(self, name, cmd):
171 """Validate an alias and return the its number of arguments."""
171 """Validate an alias and return the its number of arguments."""
172 if name in self.no_alias:
172 if name in self.no_alias:
173 raise InvalidAliasError("The name %s can't be aliased "
173 raise InvalidAliasError("The name %s can't be aliased "
174 "because it is a keyword or builtin." % name)
174 "because it is a keyword or builtin." % name)
175 if not (isinstance(cmd, basestring)):
175 if not (isinstance(cmd, basestring)):
176 raise InvalidAliasError("An alias command must be a string, "
176 raise InvalidAliasError("An alias command must be a string, "
177 "got: %r" % cmd)
177 "got: %r" % cmd)
178 nargs = cmd.count('%s')
178 nargs = cmd.count('%s')
179 if nargs>0 and cmd.find('%l')>=0:
179 if nargs>0 and cmd.find('%l')>=0:
180 raise InvalidAliasError('The %s and %l specifiers are mutually '
180 raise InvalidAliasError('The %s and %l specifiers are mutually '
181 'exclusive in alias definitions.')
181 'exclusive in alias definitions.')
182 return nargs
182 return nargs
183
183
184 def call_alias(self, alias, rest=''):
184 def call_alias(self, alias, rest=''):
185 """Call an alias given its name and the rest of the line."""
185 """Call an alias given its name and the rest of the line."""
186 cmd = self.transform_alias(alias, rest)
186 cmd = self.transform_alias(alias, rest)
187 try:
187 try:
188 self.shell.system(cmd)
188 self.shell.system(cmd)
189 except:
189 except:
190 self.shell.showtraceback()
190 self.shell.showtraceback()
191
191
192 def transform_alias(self, alias,rest=''):
192 def transform_alias(self, alias,rest=''):
193 """Transform alias to system command string."""
193 """Transform alias to system command string."""
194 nargs, cmd = self.alias_table[alias]
194 nargs, cmd = self.alias_table[alias]
195
195
196 if ' ' in cmd and os.path.isfile(cmd):
196 if ' ' in cmd and os.path.isfile(cmd):
197 cmd = '"%s"' % cmd
197 cmd = '"%s"' % cmd
198
198
199 # Expand the %l special to be the user's input line
199 # Expand the %l special to be the user's input line
200 if cmd.find('%l') >= 0:
200 if cmd.find('%l') >= 0:
201 cmd = cmd.replace('%l', rest)
201 cmd = cmd.replace('%l', rest)
202 rest = ''
202 rest = ''
203 if nargs==0:
203 if nargs==0:
204 # Simple, argument-less aliases
204 # Simple, argument-less aliases
205 cmd = '%s %s' % (cmd, rest)
205 cmd = '%s %s' % (cmd, rest)
206 else:
206 else:
207 # Handle aliases with positional arguments
207 # Handle aliases with positional arguments
208 args = rest.split(None, nargs)
208 args = rest.split(None, nargs)
209 if len(args) < nargs:
209 if len(args) < nargs:
210 raise AliasError('Alias <%s> requires %s arguments, %s given.' %
210 raise AliasError('Alias <%s> requires %s arguments, %s given.' %
211 (alias, nargs, len(args)))
211 (alias, nargs, len(args)))
212 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
212 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
213 return cmd
213 return cmd
214
214
215 def expand_alias(self, line):
215 def expand_alias(self, line):
216 """ Expand an alias in the command line
216 """ Expand an alias in the command line
217
217
218 Returns the provided command line, possibly with the first word
218 Returns the provided command line, possibly with the first word
219 (command) translated according to alias expansion rules.
219 (command) translated according to alias expansion rules.
220
220
221 [ipython]|16> _ip.expand_aliases("np myfile.txt")
221 [ipython]|16> _ip.expand_aliases("np myfile.txt")
222 <16> 'q:/opt/np/notepad++.exe myfile.txt'
222 <16> 'q:/opt/np/notepad++.exe myfile.txt'
223 """
223 """
224
224
225 pre,_,fn,rest = split_user_input(line)
225 pre,_,fn,rest = split_user_input(line)
226 res = pre + self.expand_aliases(fn, rest)
226 res = pre + self.expand_aliases(fn, rest)
227 return res
227 return res
228
228
229 def expand_aliases(self, fn, rest):
229 def expand_aliases(self, fn, rest):
230 """Expand multiple levels of aliases:
230 """Expand multiple levels of aliases:
231
231
232 if:
232 if:
233
233
234 alias foo bar /tmp
234 alias foo bar /tmp
235 alias baz foo
235 alias baz foo
236
236
237 then:
237 then:
238
238
239 baz huhhahhei -> bar /tmp huhhahhei
239 baz huhhahhei -> bar /tmp huhhahhei
240 """
240 """
241 line = fn + " " + rest
241 line = fn + " " + rest
242
242
243 done = set()
243 done = set()
244 while 1:
244 while 1:
245 pre,_,fn,rest = split_user_input(line, shell_line_split)
245 pre,_,fn,rest = split_user_input(line, shell_line_split)
246 if fn in self.alias_table:
246 if fn in self.alias_table:
247 if fn in done:
247 if fn in done:
248 warn("Cyclic alias definition, repeated '%s'" % fn)
248 warn("Cyclic alias definition, repeated '%s'" % fn)
249 return ""
249 return ""
250 done.add(fn)
250 done.add(fn)
251
251
252 l2 = self.transform_alias(fn, rest)
252 l2 = self.transform_alias(fn, rest)
253 if l2 == line:
253 if l2 == line:
254 break
254 break
255 # ls -> ls -F should not recurse forever
255 # ls -> ls -F should not recurse forever
256 if l2.split(None,1)[0] == line.split(None,1)[0]:
256 if l2.split(None,1)[0] == line.split(None,1)[0]:
257 line = l2
257 line = l2
258 break
258 break
259 line=l2
259 line=l2
260 else:
260 else:
261 break
261 break
262
262
263 return line
263 return line
@@ -1,309 +1,309 b''
1 """An interface for publishing rich data to frontends.
1 """An interface for publishing rich data to frontends.
2
2
3 There are two components of the display system:
3 There are two components of the display system:
4
4
5 * Display formatters, which take a Python object and compute the
5 * Display formatters, which take a Python object and compute the
6 representation of the object in various formats (text, HTML, SVg, etc.).
6 representation of the object in various formats (text, HTML, SVg, etc.).
7 * The display publisher that is used to send the representation data to the
7 * The display publisher that is used to send the representation data to the
8 various frontends.
8 various frontends.
9
9
10 This module defines the logic display publishing. The display publisher uses
10 This module defines the logic display publishing. The display publisher uses
11 the ``display_data`` message type that is defined in the IPython messaging
11 the ``display_data`` message type that is defined in the IPython messaging
12 spec.
12 spec.
13
13
14 Authors:
14 Authors:
15
15
16 * Brian Granger
16 * Brian Granger
17 """
17 """
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Copyright (C) 2008-2011 The IPython Development Team
20 # Copyright (C) 2008-2011 The IPython Development Team
21 #
21 #
22 # Distributed under the terms of the BSD License. The full license is in
22 # Distributed under the terms of the BSD License. The full license is in
23 # the file COPYING, distributed as part of this software.
23 # the file COPYING, distributed as part of this software.
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Imports
27 # Imports
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 from __future__ import print_function
30 from __future__ import print_function
31
31
32 from IPython.config.configurable import Configurable
32 from IPython.config.configurable import Configurable
33 from IPython.utils import io
33 from IPython.utils import io
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Main payload class
36 # Main payload class
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38
38
39 class DisplayPublisher(Configurable):
39 class DisplayPublisher(Configurable):
40 """A traited class that publishes display data to frontends.
40 """A traited class that publishes display data to frontends.
41
41
42 Instances of this class are created by the main IPython object and should
42 Instances of this class are created by the main IPython object and should
43 be accessed there.
43 be accessed there.
44 """
44 """
45
45
46 def _validate_data(self, source, data, metadata=None):
46 def _validate_data(self, source, data, metadata=None):
47 """Validate the display data.
47 """Validate the display data.
48
48
49 Parameters
49 Parameters
50 ----------
50 ----------
51 source : str
51 source : str
52 The fully dotted name of the callable that created the data, like
52 The fully dotted name of the callable that created the data, like
53 :func:`foo.bar.my_formatter`.
53 :func:`foo.bar.my_formatter`.
54 data : dict
54 data : dict
55 The formata data dictionary.
55 The formata data dictionary.
56 metadata : dict
56 metadata : dict
57 Any metadata for the data.
57 Any metadata for the data.
58 """
58 """
59
59
60 if not isinstance(source, basestring):
60 if not isinstance(source, basestring):
61 raise TypeError('source must be a str, got: %r' % source)
61 raise TypeError('source must be a str, got: %r' % source)
62 if not isinstance(data, dict):
62 if not isinstance(data, dict):
63 raise TypeError('data must be a dict, got: %r' % data)
63 raise TypeError('data must be a dict, got: %r' % data)
64 if metadata is not None:
64 if metadata is not None:
65 if not isinstance(metadata, dict):
65 if not isinstance(metadata, dict):
66 raise TypeError('metadata must be a dict, got: %r' % data)
66 raise TypeError('metadata must be a dict, got: %r' % data)
67
67
68 def publish(self, source, data, metadata=None):
68 def publish(self, source, data, metadata=None):
69 """Publish data and metadata to all frontends.
69 """Publish data and metadata to all frontends.
70
70
71 See the ``display_data`` message in the messaging documentation for
71 See the ``display_data`` message in the messaging documentation for
72 more details about this message type.
72 more details about this message type.
73
73
74 The following MIME types are currently implemented:
74 The following MIME types are currently implemented:
75
75
76 * text/plain
76 * text/plain
77 * text/html
77 * text/html
78 * text/latex
78 * text/latex
79 * application/json
79 * application/json
80 * application/javascript
80 * application/javascript
81 * image/png
81 * image/png
82 * image/jpeg
82 * image/jpeg
83 * image/svg+xml
83 * image/svg+xml
84
84
85 Parameters
85 Parameters
86 ----------
86 ----------
87 source : str
87 source : str
88 A string that give the function or method that created the data,
88 A string that give the function or method that created the data,
89 such as 'IPython.core.page'.
89 such as 'IPython.core.page'.
90 data : dict
90 data : dict
91 A dictionary having keys that are valid MIME types (like
91 A dictionary having keys that are valid MIME types (like
92 'text/plain' or 'image/svg+xml') and values that are the data for
92 'text/plain' or 'image/svg+xml') and values that are the data for
93 that MIME type. The data itself must be a JSON'able data
93 that MIME type. The data itself must be a JSON'able data
94 structure. Minimally all data should have the 'text/plain' data,
94 structure. Minimally all data should have the 'text/plain' data,
95 which can be displayed by all frontends. If more than the plain
95 which can be displayed by all frontends. If more than the plain
96 text is given, it is up to the frontend to decide which
96 text is given, it is up to the frontend to decide which
97 representation to use.
97 representation to use.
98 metadata : dict
98 metadata : dict
99 A dictionary for metadata related to the data. This can contain
99 A dictionary for metadata related to the data. This can contain
100 arbitrary key, value pairs that frontends can use to interpret
100 arbitrary key, value pairs that frontends can use to interpret
101 the data.
101 the data.
102 """
102 """
103
103
104 # The default is to simply write the plain text data using io.stdout.
104 # The default is to simply write the plain text data using io.stdout.
105 if data.has_key('text/plain'):
105 if 'text/plain' in data:
106 print(data['text/plain'], file=io.stdout)
106 print(data['text/plain'], file=io.stdout)
107
107
108 def clear_output(self, stdout=True, stderr=True, other=True):
108 def clear_output(self, stdout=True, stderr=True, other=True):
109 """Clear the output of the cell receiving output."""
109 """Clear the output of the cell receiving output."""
110 if stdout:
110 if stdout:
111 print('\033[2K\r', file=io.stdout, end='')
111 print('\033[2K\r', file=io.stdout, end='')
112 io.stdout.flush()
112 io.stdout.flush()
113 if stderr:
113 if stderr:
114 print('\033[2K\r', file=io.stderr, end='')
114 print('\033[2K\r', file=io.stderr, end='')
115 io.stderr.flush()
115 io.stderr.flush()
116
116
117
117
118
118
119 def publish_display_data(source, data, metadata=None):
119 def publish_display_data(source, data, metadata=None):
120 """Publish data and metadata to all frontends.
120 """Publish data and metadata to all frontends.
121
121
122 See the ``display_data`` message in the messaging documentation for
122 See the ``display_data`` message in the messaging documentation for
123 more details about this message type.
123 more details about this message type.
124
124
125 The following MIME types are currently implemented:
125 The following MIME types are currently implemented:
126
126
127 * text/plain
127 * text/plain
128 * text/html
128 * text/html
129 * text/latex
129 * text/latex
130 * application/json
130 * application/json
131 * application/javascript
131 * application/javascript
132 * image/png
132 * image/png
133 * image/jpeg
133 * image/jpeg
134 * image/svg+xml
134 * image/svg+xml
135
135
136 Parameters
136 Parameters
137 ----------
137 ----------
138 source : str
138 source : str
139 A string that give the function or method that created the data,
139 A string that give the function or method that created the data,
140 such as 'IPython.core.page'.
140 such as 'IPython.core.page'.
141 data : dict
141 data : dict
142 A dictionary having keys that are valid MIME types (like
142 A dictionary having keys that are valid MIME types (like
143 'text/plain' or 'image/svg+xml') and values that are the data for
143 'text/plain' or 'image/svg+xml') and values that are the data for
144 that MIME type. The data itself must be a JSON'able data
144 that MIME type. The data itself must be a JSON'able data
145 structure. Minimally all data should have the 'text/plain' data,
145 structure. Minimally all data should have the 'text/plain' data,
146 which can be displayed by all frontends. If more than the plain
146 which can be displayed by all frontends. If more than the plain
147 text is given, it is up to the frontend to decide which
147 text is given, it is up to the frontend to decide which
148 representation to use.
148 representation to use.
149 metadata : dict
149 metadata : dict
150 A dictionary for metadata related to the data. This can contain
150 A dictionary for metadata related to the data. This can contain
151 arbitrary key, value pairs that frontends can use to interpret
151 arbitrary key, value pairs that frontends can use to interpret
152 the data.
152 the data.
153 """
153 """
154 from IPython.core.interactiveshell import InteractiveShell
154 from IPython.core.interactiveshell import InteractiveShell
155 InteractiveShell.instance().display_pub.publish(
155 InteractiveShell.instance().display_pub.publish(
156 source,
156 source,
157 data,
157 data,
158 metadata
158 metadata
159 )
159 )
160
160
161
161
162 def publish_pretty(data, metadata=None):
162 def publish_pretty(data, metadata=None):
163 """Publish raw text data to all frontends.
163 """Publish raw text data to all frontends.
164
164
165 Parameters
165 Parameters
166 ----------
166 ----------
167 data : unicode
167 data : unicode
168 The raw text data to publish.
168 The raw text data to publish.
169 metadata : dict
169 metadata : dict
170 A dictionary for metadata related to the data. This can contain
170 A dictionary for metadata related to the data. This can contain
171 arbitrary key, value pairs that frontends can use to interpret
171 arbitrary key, value pairs that frontends can use to interpret
172 the data.
172 the data.
173 """
173 """
174 publish_display_data(
174 publish_display_data(
175 u'IPython.core.displaypub.publish_pretty',
175 u'IPython.core.displaypub.publish_pretty',
176 {'text/plain':data},
176 {'text/plain':data},
177 metadata=metadata
177 metadata=metadata
178 )
178 )
179
179
180
180
181 def publish_html(data, metadata=None):
181 def publish_html(data, metadata=None):
182 """Publish raw HTML data to all frontends.
182 """Publish raw HTML data to all frontends.
183
183
184 Parameters
184 Parameters
185 ----------
185 ----------
186 data : unicode
186 data : unicode
187 The raw HTML data to publish.
187 The raw HTML data to publish.
188 metadata : dict
188 metadata : dict
189 A dictionary for metadata related to the data. This can contain
189 A dictionary for metadata related to the data. This can contain
190 arbitrary key, value pairs that frontends can use to interpret
190 arbitrary key, value pairs that frontends can use to interpret
191 the data.
191 the data.
192 """
192 """
193 publish_display_data(
193 publish_display_data(
194 u'IPython.core.displaypub.publish_html',
194 u'IPython.core.displaypub.publish_html',
195 {'text/html':data},
195 {'text/html':data},
196 metadata=metadata
196 metadata=metadata
197 )
197 )
198
198
199
199
200 def publish_latex(data, metadata=None):
200 def publish_latex(data, metadata=None):
201 """Publish raw LaTeX data to all frontends.
201 """Publish raw LaTeX data to all frontends.
202
202
203 Parameters
203 Parameters
204 ----------
204 ----------
205 data : unicode
205 data : unicode
206 The raw LaTeX data to publish.
206 The raw LaTeX data to publish.
207 metadata : dict
207 metadata : dict
208 A dictionary for metadata related to the data. This can contain
208 A dictionary for metadata related to the data. This can contain
209 arbitrary key, value pairs that frontends can use to interpret
209 arbitrary key, value pairs that frontends can use to interpret
210 the data.
210 the data.
211 """
211 """
212 publish_display_data(
212 publish_display_data(
213 u'IPython.core.displaypub.publish_latex',
213 u'IPython.core.displaypub.publish_latex',
214 {'text/latex':data},
214 {'text/latex':data},
215 metadata=metadata
215 metadata=metadata
216 )
216 )
217
217
218 def publish_png(data, metadata=None):
218 def publish_png(data, metadata=None):
219 """Publish raw binary PNG data to all frontends.
219 """Publish raw binary PNG data to all frontends.
220
220
221 Parameters
221 Parameters
222 ----------
222 ----------
223 data : str/bytes
223 data : str/bytes
224 The raw binary PNG data to publish.
224 The raw binary PNG data to publish.
225 metadata : dict
225 metadata : dict
226 A dictionary for metadata related to the data. This can contain
226 A dictionary for metadata related to the data. This can contain
227 arbitrary key, value pairs that frontends can use to interpret
227 arbitrary key, value pairs that frontends can use to interpret
228 the data.
228 the data.
229 """
229 """
230 publish_display_data(
230 publish_display_data(
231 u'IPython.core.displaypub.publish_png',
231 u'IPython.core.displaypub.publish_png',
232 {'image/png':data},
232 {'image/png':data},
233 metadata=metadata
233 metadata=metadata
234 )
234 )
235
235
236
236
237 def publish_jpeg(data, metadata=None):
237 def publish_jpeg(data, metadata=None):
238 """Publish raw binary JPEG data to all frontends.
238 """Publish raw binary JPEG data to all frontends.
239
239
240 Parameters
240 Parameters
241 ----------
241 ----------
242 data : str/bytes
242 data : str/bytes
243 The raw binary JPEG data to publish.
243 The raw binary JPEG data to publish.
244 metadata : dict
244 metadata : dict
245 A dictionary for metadata related to the data. This can contain
245 A dictionary for metadata related to the data. This can contain
246 arbitrary key, value pairs that frontends can use to interpret
246 arbitrary key, value pairs that frontends can use to interpret
247 the data.
247 the data.
248 """
248 """
249 publish_display_data(
249 publish_display_data(
250 u'IPython.core.displaypub.publish_jpeg',
250 u'IPython.core.displaypub.publish_jpeg',
251 {'image/jpeg':data},
251 {'image/jpeg':data},
252 metadata=metadata
252 metadata=metadata
253 )
253 )
254
254
255
255
256 def publish_svg(data, metadata=None):
256 def publish_svg(data, metadata=None):
257 """Publish raw SVG data to all frontends.
257 """Publish raw SVG data to all frontends.
258
258
259 Parameters
259 Parameters
260 ----------
260 ----------
261 data : unicode
261 data : unicode
262 The raw SVG data to publish.
262 The raw SVG data to publish.
263 metadata : dict
263 metadata : dict
264 A dictionary for metadata related to the data. This can contain
264 A dictionary for metadata related to the data. This can contain
265 arbitrary key, value pairs that frontends can use to interpret
265 arbitrary key, value pairs that frontends can use to interpret
266 the data.
266 the data.
267 """
267 """
268 publish_display_data(
268 publish_display_data(
269 u'IPython.core.displaypub.publish_svg',
269 u'IPython.core.displaypub.publish_svg',
270 {'image/svg+xml':data},
270 {'image/svg+xml':data},
271 metadata=metadata
271 metadata=metadata
272 )
272 )
273
273
274 def publish_json(data, metadata=None):
274 def publish_json(data, metadata=None):
275 """Publish raw JSON data to all frontends.
275 """Publish raw JSON data to all frontends.
276
276
277 Parameters
277 Parameters
278 ----------
278 ----------
279 data : unicode
279 data : unicode
280 The raw JSON data to publish.
280 The raw JSON data to publish.
281 metadata : dict
281 metadata : dict
282 A dictionary for metadata related to the data. This can contain
282 A dictionary for metadata related to the data. This can contain
283 arbitrary key, value pairs that frontends can use to interpret
283 arbitrary key, value pairs that frontends can use to interpret
284 the data.
284 the data.
285 """
285 """
286 publish_display_data(
286 publish_display_data(
287 u'IPython.core.displaypub.publish_json',
287 u'IPython.core.displaypub.publish_json',
288 {'application/json':data},
288 {'application/json':data},
289 metadata=metadata
289 metadata=metadata
290 )
290 )
291
291
292 def publish_javascript(data, metadata=None):
292 def publish_javascript(data, metadata=None):
293 """Publish raw Javascript data to all frontends.
293 """Publish raw Javascript data to all frontends.
294
294
295 Parameters
295 Parameters
296 ----------
296 ----------
297 data : unicode
297 data : unicode
298 The raw Javascript data to publish.
298 The raw Javascript data to publish.
299 metadata : dict
299 metadata : dict
300 A dictionary for metadata related to the data. This can contain
300 A dictionary for metadata related to the data. This can contain
301 arbitrary key, value pairs that frontends can use to interpret
301 arbitrary key, value pairs that frontends can use to interpret
302 the data.
302 the data.
303 """
303 """
304 publish_display_data(
304 publish_display_data(
305 u'IPython.core.displaypub.publish_javascript',
305 u'IPython.core.displaypub.publish_javascript',
306 {'application/javascript':data},
306 {'application/javascript':data},
307 metadata=metadata
307 metadata=metadata
308 )
308 )
309
309
@@ -1,531 +1,531 b''
1 """Implementation of code management magic functions.
1 """Implementation of code management magic functions.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
4 # Copyright (c) 2012 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 # Stdlib
15 # Stdlib
16 import inspect
16 import inspect
17 import io
17 import io
18 import json
18 import json
19 import os
19 import os
20 import sys
20 import sys
21 from urllib2 import urlopen
21 from urllib2 import urlopen
22
22
23 # Our own packages
23 # Our own packages
24 from IPython.core.error import TryNext, StdinNotImplementedError
24 from IPython.core.error import TryNext, StdinNotImplementedError
25 from IPython.core.macro import Macro
25 from IPython.core.macro import Macro
26 from IPython.core.magic import Magics, magics_class, line_magic
26 from IPython.core.magic import Magics, magics_class, line_magic
27 from IPython.core.oinspect import find_file, find_source_lines
27 from IPython.core.oinspect import find_file, find_source_lines
28 from IPython.testing.skipdoctest import skip_doctest
28 from IPython.testing.skipdoctest import skip_doctest
29 from IPython.utils import openpy
29 from IPython.utils import openpy
30 from IPython.utils import py3compat
30 from IPython.utils import py3compat
31 from IPython.utils.io import file_read
31 from IPython.utils.io import file_read
32 from IPython.utils.path import get_py_filename, unquote_filename
32 from IPython.utils.path import get_py_filename, unquote_filename
33 from IPython.utils.warn import warn
33 from IPython.utils.warn import warn
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Magic implementation classes
36 # Magic implementation classes
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38
38
39 # Used for exception handling in magic_edit
39 # Used for exception handling in magic_edit
40 class MacroToEdit(ValueError): pass
40 class MacroToEdit(ValueError): pass
41
41
42
42
43 @magics_class
43 @magics_class
44 class CodeMagics(Magics):
44 class CodeMagics(Magics):
45 """Magics related to code management (loading, saving, editing, ...)."""
45 """Magics related to code management (loading, saving, editing, ...)."""
46
46
47 @line_magic
47 @line_magic
48 def save(self, parameter_s=''):
48 def save(self, parameter_s=''):
49 """Save a set of lines or a macro to a given filename.
49 """Save a set of lines or a macro to a given filename.
50
50
51 Usage:\\
51 Usage:\\
52 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
52 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
53
53
54 Options:
54 Options:
55
55
56 -r: use 'raw' input. By default, the 'processed' history is used,
56 -r: use 'raw' input. By default, the 'processed' history is used,
57 so that magics are loaded in their transformed version to valid
57 so that magics are loaded in their transformed version to valid
58 Python. If this option is given, the raw input as typed as the
58 Python. If this option is given, the raw input as typed as the
59 command line is used instead.
59 command line is used instead.
60
60
61 -f: force overwrite. If file exists, %save will prompt for overwrite
61 -f: force overwrite. If file exists, %save will prompt for overwrite
62 unless -f is given.
62 unless -f is given.
63
63
64 -a: append to the file instead of overwriting it.
64 -a: append to the file instead of overwriting it.
65
65
66 This function uses the same syntax as %history for input ranges,
66 This function uses the same syntax as %history for input ranges,
67 then saves the lines to the filename you specify.
67 then saves the lines to the filename you specify.
68
68
69 It adds a '.py' extension to the file if you don't do so yourself, and
69 It adds a '.py' extension to the file if you don't do so yourself, and
70 it asks for confirmation before overwriting existing files.
70 it asks for confirmation before overwriting existing files.
71
71
72 If `-r` option is used, the default extension is `.ipy`.
72 If `-r` option is used, the default extension is `.ipy`.
73 """
73 """
74
74
75 opts,args = self.parse_options(parameter_s,'fra',mode='list')
75 opts,args = self.parse_options(parameter_s,'fra',mode='list')
76 raw = 'r' in opts
76 raw = 'r' in opts
77 force = 'f' in opts
77 force = 'f' in opts
78 append = 'a' in opts
78 append = 'a' in opts
79 mode = 'a' if append else 'w'
79 mode = 'a' if append else 'w'
80 ext = u'.ipy' if raw else u'.py'
80 ext = u'.ipy' if raw else u'.py'
81 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
81 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
82 if not fname.endswith((u'.py',u'.ipy')):
82 if not fname.endswith((u'.py',u'.ipy')):
83 fname += ext
83 fname += ext
84 file_exists = os.path.isfile(fname)
84 file_exists = os.path.isfile(fname)
85 if file_exists and not force and not append:
85 if file_exists and not force and not append:
86 try:
86 try:
87 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
87 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
88 except StdinNotImplementedError:
88 except StdinNotImplementedError:
89 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
89 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
90 return
90 return
91 if not overwrite :
91 if not overwrite :
92 print 'Operation cancelled.'
92 print 'Operation cancelled.'
93 return
93 return
94 try:
94 try:
95 cmds = self.shell.find_user_code(codefrom,raw)
95 cmds = self.shell.find_user_code(codefrom,raw)
96 except (TypeError, ValueError) as e:
96 except (TypeError, ValueError) as e:
97 print e.args[0]
97 print e.args[0]
98 return
98 return
99 out = py3compat.cast_unicode(cmds)
99 out = py3compat.cast_unicode(cmds)
100 with io.open(fname, mode, encoding="utf-8") as f:
100 with io.open(fname, mode, encoding="utf-8") as f:
101 if not file_exists or not append:
101 if not file_exists or not append:
102 f.write(u"# coding: utf-8\n")
102 f.write(u"# coding: utf-8\n")
103 f.write(out)
103 f.write(out)
104 # make sure we end on a newline
104 # make sure we end on a newline
105 if not out.endswith(u'\n'):
105 if not out.endswith(u'\n'):
106 f.write(u'\n')
106 f.write(u'\n')
107 print 'The following commands were written to file `%s`:' % fname
107 print 'The following commands were written to file `%s`:' % fname
108 print cmds
108 print cmds
109
109
110 @line_magic
110 @line_magic
111 def pastebin(self, parameter_s=''):
111 def pastebin(self, parameter_s=''):
112 """Upload code to Github's Gist paste bin, returning the URL.
112 """Upload code to Github's Gist paste bin, returning the URL.
113
113
114 Usage:\\
114 Usage:\\
115 %pastebin [-d "Custom description"] 1-7
115 %pastebin [-d "Custom description"] 1-7
116
116
117 The argument can be an input history range, a filename, or the name of a
117 The argument can be an input history range, a filename, or the name of a
118 string or macro.
118 string or macro.
119
119
120 Options:
120 Options:
121
121
122 -d: Pass a custom description for the gist. The default will say
122 -d: Pass a custom description for the gist. The default will say
123 "Pasted from IPython".
123 "Pasted from IPython".
124 """
124 """
125 opts, args = self.parse_options(parameter_s, 'd:')
125 opts, args = self.parse_options(parameter_s, 'd:')
126
126
127 try:
127 try:
128 code = self.shell.find_user_code(args)
128 code = self.shell.find_user_code(args)
129 except (ValueError, TypeError) as e:
129 except (ValueError, TypeError) as e:
130 print e.args[0]
130 print e.args[0]
131 return
131 return
132
132
133 post_data = json.dumps({
133 post_data = json.dumps({
134 "description": opts.get('d', "Pasted from IPython"),
134 "description": opts.get('d', "Pasted from IPython"),
135 "public": True,
135 "public": True,
136 "files": {
136 "files": {
137 "file1.py": {
137 "file1.py": {
138 "content": code
138 "content": code
139 }
139 }
140 }
140 }
141 }).encode('utf-8')
141 }).encode('utf-8')
142
142
143 response = urlopen("https://api.github.com/gists", post_data)
143 response = urlopen("https://api.github.com/gists", post_data)
144 response_data = json.loads(response.read().decode('utf-8'))
144 response_data = json.loads(response.read().decode('utf-8'))
145 return response_data['html_url']
145 return response_data['html_url']
146
146
147 @line_magic
147 @line_magic
148 def loadpy(self, arg_s):
148 def loadpy(self, arg_s):
149 """Alias of `%load`
149 """Alias of `%load`
150
150
151 `%loadpy` has gained some flexibility and droped the requirement of a `.py`
151 `%loadpy` has gained some flexibility and droped the requirement of a `.py`
152 extension. So it has been renamed simply into %load. You can look at
152 extension. So it has been renamed simply into %load. You can look at
153 `%load`'s docstring for more info.
153 `%load`'s docstring for more info.
154 """
154 """
155 self.load(arg_s)
155 self.load(arg_s)
156
156
157 @line_magic
157 @line_magic
158 def load(self, arg_s):
158 def load(self, arg_s):
159 """Load code into the current frontend.
159 """Load code into the current frontend.
160
160
161 Usage:\\
161 Usage:\\
162 %load [options] source
162 %load [options] source
163
163
164 where source can be a filename, URL, input history range or macro
164 where source can be a filename, URL, input history range or macro
165
165
166 Options:
166 Options:
167 --------
167 --------
168 -y : Don't ask confirmation for loading source above 200 000 characters.
168 -y : Don't ask confirmation for loading source above 200 000 characters.
169
169
170 This magic command can either take a local filename, a URL, an history
170 This magic command can either take a local filename, a URL, an history
171 range (see %history) or a macro as argument, it will prompt for
171 range (see %history) or a macro as argument, it will prompt for
172 confirmation before loading source with more than 200 000 characters, unless
172 confirmation before loading source with more than 200 000 characters, unless
173 -y flag is passed or if the frontend does not support raw_input::
173 -y flag is passed or if the frontend does not support raw_input::
174
174
175 %load myscript.py
175 %load myscript.py
176 %load 7-27
176 %load 7-27
177 %load myMacro
177 %load myMacro
178 %load http://www.example.com/myscript.py
178 %load http://www.example.com/myscript.py
179 """
179 """
180 opts,args = self.parse_options(arg_s,'y')
180 opts,args = self.parse_options(arg_s,'y')
181
181
182 contents = self.shell.find_user_code(args)
182 contents = self.shell.find_user_code(args)
183 l = len(contents)
183 l = len(contents)
184
184
185 # 200 000 is ~ 2500 full 80 caracter lines
185 # 200 000 is ~ 2500 full 80 caracter lines
186 # so in average, more than 5000 lines
186 # so in average, more than 5000 lines
187 if l > 200000 and 'y' not in opts:
187 if l > 200000 and 'y' not in opts:
188 try:
188 try:
189 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
189 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
190 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
190 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
191 except StdinNotImplementedError:
191 except StdinNotImplementedError:
192 #asume yes if raw input not implemented
192 #asume yes if raw input not implemented
193 ans = True
193 ans = True
194
194
195 if ans is False :
195 if ans is False :
196 print 'Operation cancelled.'
196 print 'Operation cancelled.'
197 return
197 return
198
198
199 self.shell.set_next_input(contents)
199 self.shell.set_next_input(contents)
200
200
201 @staticmethod
201 @staticmethod
202 def _find_edit_target(shell, args, opts, last_call):
202 def _find_edit_target(shell, args, opts, last_call):
203 """Utility method used by magic_edit to find what to edit."""
203 """Utility method used by magic_edit to find what to edit."""
204
204
205 def make_filename(arg):
205 def make_filename(arg):
206 "Make a filename from the given args"
206 "Make a filename from the given args"
207 arg = unquote_filename(arg)
207 arg = unquote_filename(arg)
208 try:
208 try:
209 filename = get_py_filename(arg)
209 filename = get_py_filename(arg)
210 except IOError:
210 except IOError:
211 # If it ends with .py but doesn't already exist, assume we want
211 # If it ends with .py but doesn't already exist, assume we want
212 # a new file.
212 # a new file.
213 if arg.endswith('.py'):
213 if arg.endswith('.py'):
214 filename = arg
214 filename = arg
215 else:
215 else:
216 filename = None
216 filename = None
217 return filename
217 return filename
218
218
219 # Set a few locals from the options for convenience:
219 # Set a few locals from the options for convenience:
220 opts_prev = 'p' in opts
220 opts_prev = 'p' in opts
221 opts_raw = 'r' in opts
221 opts_raw = 'r' in opts
222
222
223 # custom exceptions
223 # custom exceptions
224 class DataIsObject(Exception): pass
224 class DataIsObject(Exception): pass
225
225
226 # Default line number value
226 # Default line number value
227 lineno = opts.get('n',None)
227 lineno = opts.get('n',None)
228
228
229 if opts_prev:
229 if opts_prev:
230 args = '_%s' % last_call[0]
230 args = '_%s' % last_call[0]
231 if not shell.user_ns.has_key(args):
231 if args not in shell.user_ns:
232 args = last_call[1]
232 args = last_call[1]
233
233
234 # use last_call to remember the state of the previous call, but don't
234 # use last_call to remember the state of the previous call, but don't
235 # let it be clobbered by successive '-p' calls.
235 # let it be clobbered by successive '-p' calls.
236 try:
236 try:
237 last_call[0] = shell.displayhook.prompt_count
237 last_call[0] = shell.displayhook.prompt_count
238 if not opts_prev:
238 if not opts_prev:
239 last_call[1] = args
239 last_call[1] = args
240 except:
240 except:
241 pass
241 pass
242
242
243 # by default this is done with temp files, except when the given
243 # by default this is done with temp files, except when the given
244 # arg is a filename
244 # arg is a filename
245 use_temp = True
245 use_temp = True
246
246
247 data = ''
247 data = ''
248
248
249 # First, see if the arguments should be a filename.
249 # First, see if the arguments should be a filename.
250 filename = make_filename(args)
250 filename = make_filename(args)
251 if filename:
251 if filename:
252 use_temp = False
252 use_temp = False
253 elif args:
253 elif args:
254 # Mode where user specifies ranges of lines, like in %macro.
254 # Mode where user specifies ranges of lines, like in %macro.
255 data = shell.extract_input_lines(args, opts_raw)
255 data = shell.extract_input_lines(args, opts_raw)
256 if not data:
256 if not data:
257 try:
257 try:
258 # Load the parameter given as a variable. If not a string,
258 # Load the parameter given as a variable. If not a string,
259 # process it as an object instead (below)
259 # process it as an object instead (below)
260
260
261 #print '*** args',args,'type',type(args) # dbg
261 #print '*** args',args,'type',type(args) # dbg
262 data = eval(args, shell.user_ns)
262 data = eval(args, shell.user_ns)
263 if not isinstance(data, basestring):
263 if not isinstance(data, basestring):
264 raise DataIsObject
264 raise DataIsObject
265
265
266 except (NameError,SyntaxError):
266 except (NameError,SyntaxError):
267 # given argument is not a variable, try as a filename
267 # given argument is not a variable, try as a filename
268 filename = make_filename(args)
268 filename = make_filename(args)
269 if filename is None:
269 if filename is None:
270 warn("Argument given (%s) can't be found as a variable "
270 warn("Argument given (%s) can't be found as a variable "
271 "or as a filename." % args)
271 "or as a filename." % args)
272 return
272 return
273 use_temp = False
273 use_temp = False
274
274
275 except DataIsObject:
275 except DataIsObject:
276 # macros have a special edit function
276 # macros have a special edit function
277 if isinstance(data, Macro):
277 if isinstance(data, Macro):
278 raise MacroToEdit(data)
278 raise MacroToEdit(data)
279
279
280 # For objects, try to edit the file where they are defined
280 # For objects, try to edit the file where they are defined
281 filename = find_file(data)
281 filename = find_file(data)
282 if filename:
282 if filename:
283 if 'fakemodule' in filename.lower() and \
283 if 'fakemodule' in filename.lower() and \
284 inspect.isclass(data):
284 inspect.isclass(data):
285 # class created by %edit? Try to find source
285 # class created by %edit? Try to find source
286 # by looking for method definitions instead, the
286 # by looking for method definitions instead, the
287 # __module__ in those classes is FakeModule.
287 # __module__ in those classes is FakeModule.
288 attrs = [getattr(data, aname) for aname in dir(data)]
288 attrs = [getattr(data, aname) for aname in dir(data)]
289 for attr in attrs:
289 for attr in attrs:
290 if not inspect.ismethod(attr):
290 if not inspect.ismethod(attr):
291 continue
291 continue
292 filename = find_file(attr)
292 filename = find_file(attr)
293 if filename and \
293 if filename and \
294 'fakemodule' not in filename.lower():
294 'fakemodule' not in filename.lower():
295 # change the attribute to be the edit
295 # change the attribute to be the edit
296 # target instead
296 # target instead
297 data = attr
297 data = attr
298 break
298 break
299
299
300 datafile = 1
300 datafile = 1
301 if filename is None:
301 if filename is None:
302 filename = make_filename(args)
302 filename = make_filename(args)
303 datafile = 1
303 datafile = 1
304 warn('Could not find file where `%s` is defined.\n'
304 warn('Could not find file where `%s` is defined.\n'
305 'Opening a file named `%s`' % (args, filename))
305 'Opening a file named `%s`' % (args, filename))
306 # Now, make sure we can actually read the source (if it was
306 # Now, make sure we can actually read the source (if it was
307 # in a temp file it's gone by now).
307 # in a temp file it's gone by now).
308 if datafile:
308 if datafile:
309 if lineno is None:
309 if lineno is None:
310 lineno = find_source_lines(data)
310 lineno = find_source_lines(data)
311 if lineno is None:
311 if lineno is None:
312 filename = make_filename(args)
312 filename = make_filename(args)
313 if filename is None:
313 if filename is None:
314 warn('The file `%s` where `%s` was defined '
314 warn('The file `%s` where `%s` was defined '
315 'cannot be read.' % (filename, data))
315 'cannot be read.' % (filename, data))
316 return
316 return
317 use_temp = False
317 use_temp = False
318
318
319 if use_temp:
319 if use_temp:
320 filename = shell.mktempfile(data)
320 filename = shell.mktempfile(data)
321 print 'IPython will make a temporary file named:',filename
321 print 'IPython will make a temporary file named:',filename
322
322
323 return filename, lineno, use_temp
323 return filename, lineno, use_temp
324
324
325 def _edit_macro(self,mname,macro):
325 def _edit_macro(self,mname,macro):
326 """open an editor with the macro data in a file"""
326 """open an editor with the macro data in a file"""
327 filename = self.shell.mktempfile(macro.value)
327 filename = self.shell.mktempfile(macro.value)
328 self.shell.hooks.editor(filename)
328 self.shell.hooks.editor(filename)
329
329
330 # and make a new macro object, to replace the old one
330 # and make a new macro object, to replace the old one
331 mfile = open(filename)
331 mfile = open(filename)
332 mvalue = mfile.read()
332 mvalue = mfile.read()
333 mfile.close()
333 mfile.close()
334 self.shell.user_ns[mname] = Macro(mvalue)
334 self.shell.user_ns[mname] = Macro(mvalue)
335
335
336 @line_magic
336 @line_magic
337 def ed(self, parameter_s=''):
337 def ed(self, parameter_s=''):
338 """Alias to %edit."""
338 """Alias to %edit."""
339 return self.edit(parameter_s)
339 return self.edit(parameter_s)
340
340
341 @skip_doctest
341 @skip_doctest
342 @line_magic
342 @line_magic
343 def edit(self, parameter_s='',last_call=['','']):
343 def edit(self, parameter_s='',last_call=['','']):
344 """Bring up an editor and execute the resulting code.
344 """Bring up an editor and execute the resulting code.
345
345
346 Usage:
346 Usage:
347 %edit [options] [args]
347 %edit [options] [args]
348
348
349 %edit runs IPython's editor hook. The default version of this hook is
349 %edit runs IPython's editor hook. The default version of this hook is
350 set to call the editor specified by your $EDITOR environment variable.
350 set to call the editor specified by your $EDITOR environment variable.
351 If this isn't found, it will default to vi under Linux/Unix and to
351 If this isn't found, it will default to vi under Linux/Unix and to
352 notepad under Windows. See the end of this docstring for how to change
352 notepad under Windows. See the end of this docstring for how to change
353 the editor hook.
353 the editor hook.
354
354
355 You can also set the value of this editor via the
355 You can also set the value of this editor via the
356 ``TerminalInteractiveShell.editor`` option in your configuration file.
356 ``TerminalInteractiveShell.editor`` option in your configuration file.
357 This is useful if you wish to use a different editor from your typical
357 This is useful if you wish to use a different editor from your typical
358 default with IPython (and for Windows users who typically don't set
358 default with IPython (and for Windows users who typically don't set
359 environment variables).
359 environment variables).
360
360
361 This command allows you to conveniently edit multi-line code right in
361 This command allows you to conveniently edit multi-line code right in
362 your IPython session.
362 your IPython session.
363
363
364 If called without arguments, %edit opens up an empty editor with a
364 If called without arguments, %edit opens up an empty editor with a
365 temporary file and will execute the contents of this file when you
365 temporary file and will execute the contents of this file when you
366 close it (don't forget to save it!).
366 close it (don't forget to save it!).
367
367
368
368
369 Options:
369 Options:
370
370
371 -n <number>: open the editor at a specified line number. By default,
371 -n <number>: open the editor at a specified line number. By default,
372 the IPython editor hook uses the unix syntax 'editor +N filename', but
372 the IPython editor hook uses the unix syntax 'editor +N filename', but
373 you can configure this by providing your own modified hook if your
373 you can configure this by providing your own modified hook if your
374 favorite editor supports line-number specifications with a different
374 favorite editor supports line-number specifications with a different
375 syntax.
375 syntax.
376
376
377 -p: this will call the editor with the same data as the previous time
377 -p: this will call the editor with the same data as the previous time
378 it was used, regardless of how long ago (in your current session) it
378 it was used, regardless of how long ago (in your current session) it
379 was.
379 was.
380
380
381 -r: use 'raw' input. This option only applies to input taken from the
381 -r: use 'raw' input. This option only applies to input taken from the
382 user's history. By default, the 'processed' history is used, so that
382 user's history. By default, the 'processed' history is used, so that
383 magics are loaded in their transformed version to valid Python. If
383 magics are loaded in their transformed version to valid Python. If
384 this option is given, the raw input as typed as the command line is
384 this option is given, the raw input as typed as the command line is
385 used instead. When you exit the editor, it will be executed by
385 used instead. When you exit the editor, it will be executed by
386 IPython's own processor.
386 IPython's own processor.
387
387
388 -x: do not execute the edited code immediately upon exit. This is
388 -x: do not execute the edited code immediately upon exit. This is
389 mainly useful if you are editing programs which need to be called with
389 mainly useful if you are editing programs which need to be called with
390 command line arguments, which you can then do using %run.
390 command line arguments, which you can then do using %run.
391
391
392
392
393 Arguments:
393 Arguments:
394
394
395 If arguments are given, the following possibilities exist:
395 If arguments are given, the following possibilities exist:
396
396
397 - If the argument is a filename, IPython will load that into the
397 - If the argument is a filename, IPython will load that into the
398 editor. It will execute its contents with execfile() when you exit,
398 editor. It will execute its contents with execfile() when you exit,
399 loading any code in the file into your interactive namespace.
399 loading any code in the file into your interactive namespace.
400
400
401 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
401 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
402 The syntax is the same as in the %history magic.
402 The syntax is the same as in the %history magic.
403
403
404 - If the argument is a string variable, its contents are loaded
404 - If the argument is a string variable, its contents are loaded
405 into the editor. You can thus edit any string which contains
405 into the editor. You can thus edit any string which contains
406 python code (including the result of previous edits).
406 python code (including the result of previous edits).
407
407
408 - If the argument is the name of an object (other than a string),
408 - If the argument is the name of an object (other than a string),
409 IPython will try to locate the file where it was defined and open the
409 IPython will try to locate the file where it was defined and open the
410 editor at the point where it is defined. You can use `%edit function`
410 editor at the point where it is defined. You can use `%edit function`
411 to load an editor exactly at the point where 'function' is defined,
411 to load an editor exactly at the point where 'function' is defined,
412 edit it and have the file be executed automatically.
412 edit it and have the file be executed automatically.
413
413
414 - If the object is a macro (see %macro for details), this opens up your
414 - If the object is a macro (see %macro for details), this opens up your
415 specified editor with a temporary file containing the macro's data.
415 specified editor with a temporary file containing the macro's data.
416 Upon exit, the macro is reloaded with the contents of the file.
416 Upon exit, the macro is reloaded with the contents of the file.
417
417
418 Note: opening at an exact line is only supported under Unix, and some
418 Note: opening at an exact line is only supported under Unix, and some
419 editors (like kedit and gedit up to Gnome 2.8) do not understand the
419 editors (like kedit and gedit up to Gnome 2.8) do not understand the
420 '+NUMBER' parameter necessary for this feature. Good editors like
420 '+NUMBER' parameter necessary for this feature. Good editors like
421 (X)Emacs, vi, jed, pico and joe all do.
421 (X)Emacs, vi, jed, pico and joe all do.
422
422
423 After executing your code, %edit will return as output the code you
423 After executing your code, %edit will return as output the code you
424 typed in the editor (except when it was an existing file). This way
424 typed in the editor (except when it was an existing file). This way
425 you can reload the code in further invocations of %edit as a variable,
425 you can reload the code in further invocations of %edit as a variable,
426 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
426 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
427 the output.
427 the output.
428
428
429 Note that %edit is also available through the alias %ed.
429 Note that %edit is also available through the alias %ed.
430
430
431 This is an example of creating a simple function inside the editor and
431 This is an example of creating a simple function inside the editor and
432 then modifying it. First, start up the editor::
432 then modifying it. First, start up the editor::
433
433
434 In [1]: ed
434 In [1]: ed
435 Editing... done. Executing edited code...
435 Editing... done. Executing edited code...
436 Out[1]: 'def foo():\\n print "foo() was defined in an editing
436 Out[1]: 'def foo():\\n print "foo() was defined in an editing
437 session"\\n'
437 session"\\n'
438
438
439 We can then call the function foo()::
439 We can then call the function foo()::
440
440
441 In [2]: foo()
441 In [2]: foo()
442 foo() was defined in an editing session
442 foo() was defined in an editing session
443
443
444 Now we edit foo. IPython automatically loads the editor with the
444 Now we edit foo. IPython automatically loads the editor with the
445 (temporary) file where foo() was previously defined::
445 (temporary) file where foo() was previously defined::
446
446
447 In [3]: ed foo
447 In [3]: ed foo
448 Editing... done. Executing edited code...
448 Editing... done. Executing edited code...
449
449
450 And if we call foo() again we get the modified version::
450 And if we call foo() again we get the modified version::
451
451
452 In [4]: foo()
452 In [4]: foo()
453 foo() has now been changed!
453 foo() has now been changed!
454
454
455 Here is an example of how to edit a code snippet successive
455 Here is an example of how to edit a code snippet successive
456 times. First we call the editor::
456 times. First we call the editor::
457
457
458 In [5]: ed
458 In [5]: ed
459 Editing... done. Executing edited code...
459 Editing... done. Executing edited code...
460 hello
460 hello
461 Out[5]: "print 'hello'\\n"
461 Out[5]: "print 'hello'\\n"
462
462
463 Now we call it again with the previous output (stored in _)::
463 Now we call it again with the previous output (stored in _)::
464
464
465 In [6]: ed _
465 In [6]: ed _
466 Editing... done. Executing edited code...
466 Editing... done. Executing edited code...
467 hello world
467 hello world
468 Out[6]: "print 'hello world'\\n"
468 Out[6]: "print 'hello world'\\n"
469
469
470 Now we call it with the output #8 (stored in _8, also as Out[8])::
470 Now we call it with the output #8 (stored in _8, also as Out[8])::
471
471
472 In [7]: ed _8
472 In [7]: ed _8
473 Editing... done. Executing edited code...
473 Editing... done. Executing edited code...
474 hello again
474 hello again
475 Out[7]: "print 'hello again'\\n"
475 Out[7]: "print 'hello again'\\n"
476
476
477
477
478 Changing the default editor hook:
478 Changing the default editor hook:
479
479
480 If you wish to write your own editor hook, you can put it in a
480 If you wish to write your own editor hook, you can put it in a
481 configuration file which you load at startup time. The default hook
481 configuration file which you load at startup time. The default hook
482 is defined in the IPython.core.hooks module, and you can use that as a
482 is defined in the IPython.core.hooks module, and you can use that as a
483 starting example for further modifications. That file also has
483 starting example for further modifications. That file also has
484 general instructions on how to set a new hook for use once you've
484 general instructions on how to set a new hook for use once you've
485 defined it."""
485 defined it."""
486 opts,args = self.parse_options(parameter_s,'prxn:')
486 opts,args = self.parse_options(parameter_s,'prxn:')
487
487
488 try:
488 try:
489 filename, lineno, is_temp = self._find_edit_target(self.shell,
489 filename, lineno, is_temp = self._find_edit_target(self.shell,
490 args, opts, last_call)
490 args, opts, last_call)
491 except MacroToEdit as e:
491 except MacroToEdit as e:
492 self._edit_macro(args, e.args[0])
492 self._edit_macro(args, e.args[0])
493 return
493 return
494
494
495 # do actual editing here
495 # do actual editing here
496 print 'Editing...',
496 print 'Editing...',
497 sys.stdout.flush()
497 sys.stdout.flush()
498 try:
498 try:
499 # Quote filenames that may have spaces in them
499 # Quote filenames that may have spaces in them
500 if ' ' in filename:
500 if ' ' in filename:
501 filename = "'%s'" % filename
501 filename = "'%s'" % filename
502 self.shell.hooks.editor(filename,lineno)
502 self.shell.hooks.editor(filename,lineno)
503 except TryNext:
503 except TryNext:
504 warn('Could not open editor')
504 warn('Could not open editor')
505 return
505 return
506
506
507 # XXX TODO: should this be generalized for all string vars?
507 # XXX TODO: should this be generalized for all string vars?
508 # For now, this is special-cased to blocks created by cpaste
508 # For now, this is special-cased to blocks created by cpaste
509 if args.strip() == 'pasted_block':
509 if args.strip() == 'pasted_block':
510 self.shell.user_ns['pasted_block'] = file_read(filename)
510 self.shell.user_ns['pasted_block'] = file_read(filename)
511
511
512 if 'x' in opts: # -x prevents actual execution
512 if 'x' in opts: # -x prevents actual execution
513 print
513 print
514 else:
514 else:
515 print 'done. Executing edited code...'
515 print 'done. Executing edited code...'
516 if 'r' in opts: # Untranslated IPython code
516 if 'r' in opts: # Untranslated IPython code
517 self.shell.run_cell(file_read(filename),
517 self.shell.run_cell(file_read(filename),
518 store_history=False)
518 store_history=False)
519 else:
519 else:
520 self.shell.safe_execfile(filename, self.shell.user_ns,
520 self.shell.safe_execfile(filename, self.shell.user_ns,
521 self.shell.user_ns)
521 self.shell.user_ns)
522
522
523 if is_temp:
523 if is_temp:
524 try:
524 try:
525 return open(filename).read()
525 return open(filename).read()
526 except IOError as msg:
526 except IOError as msg:
527 if msg.filename == filename:
527 if msg.filename == filename:
528 warn('File not found. Did you forget to save?')
528 warn('File not found. Did you forget to save?')
529 return
529 return
530 else:
530 else:
531 self.shell.showtraceback()
531 self.shell.showtraceback()
@@ -1,1022 +1,1022 b''
1 """Implementation of execution-related magic functions.
1 """Implementation of execution-related magic functions.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
4 # Copyright (c) 2012 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 # Stdlib
15 # Stdlib
16 import __builtin__ as builtin_mod
16 import __builtin__ as builtin_mod
17 import bdb
17 import bdb
18 import os
18 import os
19 import sys
19 import sys
20 import time
20 import time
21 from StringIO import StringIO
21 from StringIO import StringIO
22
22
23 # cProfile was added in Python2.5
23 # cProfile was added in Python2.5
24 try:
24 try:
25 import cProfile as profile
25 import cProfile as profile
26 import pstats
26 import pstats
27 except ImportError:
27 except ImportError:
28 # profile isn't bundled by default in Debian for license reasons
28 # profile isn't bundled by default in Debian for license reasons
29 try:
29 try:
30 import profile, pstats
30 import profile, pstats
31 except ImportError:
31 except ImportError:
32 profile = pstats = None
32 profile = pstats = None
33
33
34 # Our own packages
34 # Our own packages
35 from IPython.core import debugger, oinspect
35 from IPython.core import debugger, oinspect
36 from IPython.core import magic_arguments
36 from IPython.core import magic_arguments
37 from IPython.core import page
37 from IPython.core import page
38 from IPython.core.error import UsageError
38 from IPython.core.error import UsageError
39 from IPython.core.macro import Macro
39 from IPython.core.macro import Macro
40 from IPython.core.magic import (Magics, magics_class, line_magic, cell_magic,
40 from IPython.core.magic import (Magics, magics_class, line_magic, cell_magic,
41 line_cell_magic, on_off, needs_local_scope)
41 line_cell_magic, on_off, needs_local_scope)
42 from IPython.testing.skipdoctest import skip_doctest
42 from IPython.testing.skipdoctest import skip_doctest
43 from IPython.utils import py3compat
43 from IPython.utils import py3compat
44 from IPython.utils.io import capture_output
44 from IPython.utils.io import capture_output
45 from IPython.utils.ipstruct import Struct
45 from IPython.utils.ipstruct import Struct
46 from IPython.utils.module_paths import find_mod
46 from IPython.utils.module_paths import find_mod
47 from IPython.utils.path import get_py_filename, unquote_filename
47 from IPython.utils.path import get_py_filename, unquote_filename
48 from IPython.utils.timing import clock, clock2
48 from IPython.utils.timing import clock, clock2
49 from IPython.utils.warn import warn, error
49 from IPython.utils.warn import warn, error
50
50
51 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
52 # Magic implementation classes
52 # Magic implementation classes
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54
54
55 @magics_class
55 @magics_class
56 class ExecutionMagics(Magics):
56 class ExecutionMagics(Magics):
57 """Magics related to code execution, debugging, profiling, etc.
57 """Magics related to code execution, debugging, profiling, etc.
58
58
59 """
59 """
60
60
61 def __init__(self, shell):
61 def __init__(self, shell):
62 super(ExecutionMagics, self).__init__(shell)
62 super(ExecutionMagics, self).__init__(shell)
63 if profile is None:
63 if profile is None:
64 self.prun = self.profile_missing_notice
64 self.prun = self.profile_missing_notice
65 # Default execution function used to actually run user code.
65 # Default execution function used to actually run user code.
66 self.default_runner = None
66 self.default_runner = None
67
67
68 def profile_missing_notice(self, *args, **kwargs):
68 def profile_missing_notice(self, *args, **kwargs):
69 error("""\
69 error("""\
70 The profile module could not be found. It has been removed from the standard
70 The profile module could not be found. It has been removed from the standard
71 python packages because of its non-free license. To use profiling, install the
71 python packages because of its non-free license. To use profiling, install the
72 python-profiler package from non-free.""")
72 python-profiler package from non-free.""")
73
73
74 @skip_doctest
74 @skip_doctest
75 @line_cell_magic
75 @line_cell_magic
76 def prun(self, parameter_s='', cell=None, user_mode=True,
76 def prun(self, parameter_s='', cell=None, user_mode=True,
77 opts=None,arg_lst=None,prog_ns=None):
77 opts=None,arg_lst=None,prog_ns=None):
78
78
79 """Run a statement through the python code profiler.
79 """Run a statement through the python code profiler.
80
80
81 Usage, in line mode:
81 Usage, in line mode:
82 %prun [options] statement
82 %prun [options] statement
83
83
84 Usage, in cell mode:
84 Usage, in cell mode:
85 %%prun [options] [statement]
85 %%prun [options] [statement]
86 code...
86 code...
87 code...
87 code...
88
88
89 In cell mode, the additional code lines are appended to the (possibly
89 In cell mode, the additional code lines are appended to the (possibly
90 empty) statement in the first line. Cell mode allows you to easily
90 empty) statement in the first line. Cell mode allows you to easily
91 profile multiline blocks without having to put them in a separate
91 profile multiline blocks without having to put them in a separate
92 function.
92 function.
93
93
94 The given statement (which doesn't require quote marks) is run via the
94 The given statement (which doesn't require quote marks) is run via the
95 python profiler in a manner similar to the profile.run() function.
95 python profiler in a manner similar to the profile.run() function.
96 Namespaces are internally managed to work correctly; profile.run
96 Namespaces are internally managed to work correctly; profile.run
97 cannot be used in IPython because it makes certain assumptions about
97 cannot be used in IPython because it makes certain assumptions about
98 namespaces which do not hold under IPython.
98 namespaces which do not hold under IPython.
99
99
100 Options:
100 Options:
101
101
102 -l <limit>: you can place restrictions on what or how much of the
102 -l <limit>: you can place restrictions on what or how much of the
103 profile gets printed. The limit value can be:
103 profile gets printed. The limit value can be:
104
104
105 * A string: only information for function names containing this string
105 * A string: only information for function names containing this string
106 is printed.
106 is printed.
107
107
108 * An integer: only these many lines are printed.
108 * An integer: only these many lines are printed.
109
109
110 * A float (between 0 and 1): this fraction of the report is printed
110 * A float (between 0 and 1): this fraction of the report is printed
111 (for example, use a limit of 0.4 to see the topmost 40% only).
111 (for example, use a limit of 0.4 to see the topmost 40% only).
112
112
113 You can combine several limits with repeated use of the option. For
113 You can combine several limits with repeated use of the option. For
114 example, '-l __init__ -l 5' will print only the topmost 5 lines of
114 example, '-l __init__ -l 5' will print only the topmost 5 lines of
115 information about class constructors.
115 information about class constructors.
116
116
117 -r: return the pstats.Stats object generated by the profiling. This
117 -r: return the pstats.Stats object generated by the profiling. This
118 object has all the information about the profile in it, and you can
118 object has all the information about the profile in it, and you can
119 later use it for further analysis or in other functions.
119 later use it for further analysis or in other functions.
120
120
121 -s <key>: sort profile by given key. You can provide more than one key
121 -s <key>: sort profile by given key. You can provide more than one key
122 by using the option several times: '-s key1 -s key2 -s key3...'. The
122 by using the option several times: '-s key1 -s key2 -s key3...'. The
123 default sorting key is 'time'.
123 default sorting key is 'time'.
124
124
125 The following is copied verbatim from the profile documentation
125 The following is copied verbatim from the profile documentation
126 referenced below:
126 referenced below:
127
127
128 When more than one key is provided, additional keys are used as
128 When more than one key is provided, additional keys are used as
129 secondary criteria when the there is equality in all keys selected
129 secondary criteria when the there is equality in all keys selected
130 before them.
130 before them.
131
131
132 Abbreviations can be used for any key names, as long as the
132 Abbreviations can be used for any key names, as long as the
133 abbreviation is unambiguous. The following are the keys currently
133 abbreviation is unambiguous. The following are the keys currently
134 defined:
134 defined:
135
135
136 Valid Arg Meaning
136 Valid Arg Meaning
137 "calls" call count
137 "calls" call count
138 "cumulative" cumulative time
138 "cumulative" cumulative time
139 "file" file name
139 "file" file name
140 "module" file name
140 "module" file name
141 "pcalls" primitive call count
141 "pcalls" primitive call count
142 "line" line number
142 "line" line number
143 "name" function name
143 "name" function name
144 "nfl" name/file/line
144 "nfl" name/file/line
145 "stdname" standard name
145 "stdname" standard name
146 "time" internal time
146 "time" internal time
147
147
148 Note that all sorts on statistics are in descending order (placing
148 Note that all sorts on statistics are in descending order (placing
149 most time consuming items first), where as name, file, and line number
149 most time consuming items first), where as name, file, and line number
150 searches are in ascending order (i.e., alphabetical). The subtle
150 searches are in ascending order (i.e., alphabetical). The subtle
151 distinction between "nfl" and "stdname" is that the standard name is a
151 distinction between "nfl" and "stdname" is that the standard name is a
152 sort of the name as printed, which means that the embedded line
152 sort of the name as printed, which means that the embedded line
153 numbers get compared in an odd way. For example, lines 3, 20, and 40
153 numbers get compared in an odd way. For example, lines 3, 20, and 40
154 would (if the file names were the same) appear in the string order
154 would (if the file names were the same) appear in the string order
155 "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
155 "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
156 line numbers. In fact, sort_stats("nfl") is the same as
156 line numbers. In fact, sort_stats("nfl") is the same as
157 sort_stats("name", "file", "line").
157 sort_stats("name", "file", "line").
158
158
159 -T <filename>: save profile results as shown on screen to a text
159 -T <filename>: save profile results as shown on screen to a text
160 file. The profile is still shown on screen.
160 file. The profile is still shown on screen.
161
161
162 -D <filename>: save (via dump_stats) profile statistics to given
162 -D <filename>: save (via dump_stats) profile statistics to given
163 filename. This data is in a format understood by the pstats module, and
163 filename. This data is in a format understood by the pstats module, and
164 is generated by a call to the dump_stats() method of profile
164 is generated by a call to the dump_stats() method of profile
165 objects. The profile is still shown on screen.
165 objects. The profile is still shown on screen.
166
166
167 -q: suppress output to the pager. Best used with -T and/or -D above.
167 -q: suppress output to the pager. Best used with -T and/or -D above.
168
168
169 If you want to run complete programs under the profiler's control, use
169 If you want to run complete programs under the profiler's control, use
170 '%run -p [prof_opts] filename.py [args to program]' where prof_opts
170 '%run -p [prof_opts] filename.py [args to program]' where prof_opts
171 contains profiler specific options as described here.
171 contains profiler specific options as described here.
172
172
173 You can read the complete documentation for the profile module with::
173 You can read the complete documentation for the profile module with::
174
174
175 In [1]: import profile; profile.help()
175 In [1]: import profile; profile.help()
176 """
176 """
177
177
178 opts_def = Struct(D=[''],l=[],s=['time'],T=[''])
178 opts_def = Struct(D=[''],l=[],s=['time'],T=[''])
179
179
180 if user_mode: # regular user call
180 if user_mode: # regular user call
181 opts,arg_str = self.parse_options(parameter_s,'D:l:rs:T:q',
181 opts,arg_str = self.parse_options(parameter_s,'D:l:rs:T:q',
182 list_all=True, posix=False)
182 list_all=True, posix=False)
183 namespace = self.shell.user_ns
183 namespace = self.shell.user_ns
184 if cell is not None:
184 if cell is not None:
185 arg_str += '\n' + cell
185 arg_str += '\n' + cell
186 else: # called to run a program by %run -p
186 else: # called to run a program by %run -p
187 try:
187 try:
188 filename = get_py_filename(arg_lst[0])
188 filename = get_py_filename(arg_lst[0])
189 except IOError as e:
189 except IOError as e:
190 try:
190 try:
191 msg = str(e)
191 msg = str(e)
192 except UnicodeError:
192 except UnicodeError:
193 msg = e.message
193 msg = e.message
194 error(msg)
194 error(msg)
195 return
195 return
196
196
197 arg_str = 'execfile(filename,prog_ns)'
197 arg_str = 'execfile(filename,prog_ns)'
198 namespace = {
198 namespace = {
199 'execfile': self.shell.safe_execfile,
199 'execfile': self.shell.safe_execfile,
200 'prog_ns': prog_ns,
200 'prog_ns': prog_ns,
201 'filename': filename
201 'filename': filename
202 }
202 }
203
203
204 opts.merge(opts_def)
204 opts.merge(opts_def)
205
205
206 prof = profile.Profile()
206 prof = profile.Profile()
207 try:
207 try:
208 prof = prof.runctx(arg_str,namespace,namespace)
208 prof = prof.runctx(arg_str,namespace,namespace)
209 sys_exit = ''
209 sys_exit = ''
210 except SystemExit:
210 except SystemExit:
211 sys_exit = """*** SystemExit exception caught in code being profiled."""
211 sys_exit = """*** SystemExit exception caught in code being profiled."""
212
212
213 stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
213 stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
214
214
215 lims = opts.l
215 lims = opts.l
216 if lims:
216 if lims:
217 lims = [] # rebuild lims with ints/floats/strings
217 lims = [] # rebuild lims with ints/floats/strings
218 for lim in opts.l:
218 for lim in opts.l:
219 try:
219 try:
220 lims.append(int(lim))
220 lims.append(int(lim))
221 except ValueError:
221 except ValueError:
222 try:
222 try:
223 lims.append(float(lim))
223 lims.append(float(lim))
224 except ValueError:
224 except ValueError:
225 lims.append(lim)
225 lims.append(lim)
226
226
227 # Trap output.
227 # Trap output.
228 stdout_trap = StringIO()
228 stdout_trap = StringIO()
229
229
230 if hasattr(stats,'stream'):
230 if hasattr(stats,'stream'):
231 # In newer versions of python, the stats object has a 'stream'
231 # In newer versions of python, the stats object has a 'stream'
232 # attribute to write into.
232 # attribute to write into.
233 stats.stream = stdout_trap
233 stats.stream = stdout_trap
234 stats.print_stats(*lims)
234 stats.print_stats(*lims)
235 else:
235 else:
236 # For older versions, we manually redirect stdout during printing
236 # For older versions, we manually redirect stdout during printing
237 sys_stdout = sys.stdout
237 sys_stdout = sys.stdout
238 try:
238 try:
239 sys.stdout = stdout_trap
239 sys.stdout = stdout_trap
240 stats.print_stats(*lims)
240 stats.print_stats(*lims)
241 finally:
241 finally:
242 sys.stdout = sys_stdout
242 sys.stdout = sys_stdout
243
243
244 output = stdout_trap.getvalue()
244 output = stdout_trap.getvalue()
245 output = output.rstrip()
245 output = output.rstrip()
246
246
247 if 'q' not in opts:
247 if 'q' not in opts:
248 page.page(output)
248 page.page(output)
249 print sys_exit,
249 print sys_exit,
250
250
251 dump_file = opts.D[0]
251 dump_file = opts.D[0]
252 text_file = opts.T[0]
252 text_file = opts.T[0]
253 if dump_file:
253 if dump_file:
254 dump_file = unquote_filename(dump_file)
254 dump_file = unquote_filename(dump_file)
255 prof.dump_stats(dump_file)
255 prof.dump_stats(dump_file)
256 print '\n*** Profile stats marshalled to file',\
256 print '\n*** Profile stats marshalled to file',\
257 repr(dump_file)+'.',sys_exit
257 repr(dump_file)+'.',sys_exit
258 if text_file:
258 if text_file:
259 text_file = unquote_filename(text_file)
259 text_file = unquote_filename(text_file)
260 pfile = open(text_file,'w')
260 pfile = open(text_file,'w')
261 pfile.write(output)
261 pfile.write(output)
262 pfile.close()
262 pfile.close()
263 print '\n*** Profile printout saved to text file',\
263 print '\n*** Profile printout saved to text file',\
264 repr(text_file)+'.',sys_exit
264 repr(text_file)+'.',sys_exit
265
265
266 if opts.has_key('r'):
266 if 'r' in opts:
267 return stats
267 return stats
268 else:
268 else:
269 return None
269 return None
270
270
271 @line_magic
271 @line_magic
272 def pdb(self, parameter_s=''):
272 def pdb(self, parameter_s=''):
273 """Control the automatic calling of the pdb interactive debugger.
273 """Control the automatic calling of the pdb interactive debugger.
274
274
275 Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
275 Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
276 argument it works as a toggle.
276 argument it works as a toggle.
277
277
278 When an exception is triggered, IPython can optionally call the
278 When an exception is triggered, IPython can optionally call the
279 interactive pdb debugger after the traceback printout. %pdb toggles
279 interactive pdb debugger after the traceback printout. %pdb toggles
280 this feature on and off.
280 this feature on and off.
281
281
282 The initial state of this feature is set in your configuration
282 The initial state of this feature is set in your configuration
283 file (the option is ``InteractiveShell.pdb``).
283 file (the option is ``InteractiveShell.pdb``).
284
284
285 If you want to just activate the debugger AFTER an exception has fired,
285 If you want to just activate the debugger AFTER an exception has fired,
286 without having to type '%pdb on' and rerunning your code, you can use
286 without having to type '%pdb on' and rerunning your code, you can use
287 the %debug magic."""
287 the %debug magic."""
288
288
289 par = parameter_s.strip().lower()
289 par = parameter_s.strip().lower()
290
290
291 if par:
291 if par:
292 try:
292 try:
293 new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
293 new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
294 except KeyError:
294 except KeyError:
295 print ('Incorrect argument. Use on/1, off/0, '
295 print ('Incorrect argument. Use on/1, off/0, '
296 'or nothing for a toggle.')
296 'or nothing for a toggle.')
297 return
297 return
298 else:
298 else:
299 # toggle
299 # toggle
300 new_pdb = not self.shell.call_pdb
300 new_pdb = not self.shell.call_pdb
301
301
302 # set on the shell
302 # set on the shell
303 self.shell.call_pdb = new_pdb
303 self.shell.call_pdb = new_pdb
304 print 'Automatic pdb calling has been turned',on_off(new_pdb)
304 print 'Automatic pdb calling has been turned',on_off(new_pdb)
305
305
306 @line_magic
306 @line_magic
307 def debug(self, parameter_s=''):
307 def debug(self, parameter_s=''):
308 """Activate the interactive debugger in post-mortem mode.
308 """Activate the interactive debugger in post-mortem mode.
309
309
310 If an exception has just occurred, this lets you inspect its stack
310 If an exception has just occurred, this lets you inspect its stack
311 frames interactively. Note that this will always work only on the last
311 frames interactively. Note that this will always work only on the last
312 traceback that occurred, so you must call this quickly after an
312 traceback that occurred, so you must call this quickly after an
313 exception that you wish to inspect has fired, because if another one
313 exception that you wish to inspect has fired, because if another one
314 occurs, it clobbers the previous one.
314 occurs, it clobbers the previous one.
315
315
316 If you want IPython to automatically do this on every exception, see
316 If you want IPython to automatically do this on every exception, see
317 the %pdb magic for more details.
317 the %pdb magic for more details.
318 """
318 """
319 self.shell.debugger(force=True)
319 self.shell.debugger(force=True)
320
320
321 @line_magic
321 @line_magic
322 def tb(self, s):
322 def tb(self, s):
323 """Print the last traceback with the currently active exception mode.
323 """Print the last traceback with the currently active exception mode.
324
324
325 See %xmode for changing exception reporting modes."""
325 See %xmode for changing exception reporting modes."""
326 self.shell.showtraceback()
326 self.shell.showtraceback()
327
327
328 @skip_doctest
328 @skip_doctest
329 @line_magic
329 @line_magic
330 def run(self, parameter_s='', runner=None,
330 def run(self, parameter_s='', runner=None,
331 file_finder=get_py_filename):
331 file_finder=get_py_filename):
332 """Run the named file inside IPython as a program.
332 """Run the named file inside IPython as a program.
333
333
334 Usage:\\
334 Usage:\\
335 %run [-n -i -t [-N<N>] -d [-b<N>] -p [profile options]] file [args]
335 %run [-n -i -t [-N<N>] -d [-b<N>] -p [profile options]] file [args]
336
336
337 Parameters after the filename are passed as command-line arguments to
337 Parameters after the filename are passed as command-line arguments to
338 the program (put in sys.argv). Then, control returns to IPython's
338 the program (put in sys.argv). Then, control returns to IPython's
339 prompt.
339 prompt.
340
340
341 This is similar to running at a system prompt:\\
341 This is similar to running at a system prompt:\\
342 $ python file args\\
342 $ python file args\\
343 but with the advantage of giving you IPython's tracebacks, and of
343 but with the advantage of giving you IPython's tracebacks, and of
344 loading all variables into your interactive namespace for further use
344 loading all variables into your interactive namespace for further use
345 (unless -p is used, see below).
345 (unless -p is used, see below).
346
346
347 The file is executed in a namespace initially consisting only of
347 The file is executed in a namespace initially consisting only of
348 __name__=='__main__' and sys.argv constructed as indicated. It thus
348 __name__=='__main__' and sys.argv constructed as indicated. It thus
349 sees its environment as if it were being run as a stand-alone program
349 sees its environment as if it were being run as a stand-alone program
350 (except for sharing global objects such as previously imported
350 (except for sharing global objects such as previously imported
351 modules). But after execution, the IPython interactive namespace gets
351 modules). But after execution, the IPython interactive namespace gets
352 updated with all variables defined in the program (except for __name__
352 updated with all variables defined in the program (except for __name__
353 and sys.argv). This allows for very convenient loading of code for
353 and sys.argv). This allows for very convenient loading of code for
354 interactive work, while giving each program a 'clean sheet' to run in.
354 interactive work, while giving each program a 'clean sheet' to run in.
355
355
356 Options:
356 Options:
357
357
358 -n: __name__ is NOT set to '__main__', but to the running file's name
358 -n: __name__ is NOT set to '__main__', but to the running file's name
359 without extension (as python does under import). This allows running
359 without extension (as python does under import). This allows running
360 scripts and reloading the definitions in them without calling code
360 scripts and reloading the definitions in them without calling code
361 protected by an ' if __name__ == "__main__" ' clause.
361 protected by an ' if __name__ == "__main__" ' clause.
362
362
363 -i: run the file in IPython's namespace instead of an empty one. This
363 -i: run the file in IPython's namespace instead of an empty one. This
364 is useful if you are experimenting with code written in a text editor
364 is useful if you are experimenting with code written in a text editor
365 which depends on variables defined interactively.
365 which depends on variables defined interactively.
366
366
367 -e: ignore sys.exit() calls or SystemExit exceptions in the script
367 -e: ignore sys.exit() calls or SystemExit exceptions in the script
368 being run. This is particularly useful if IPython is being used to
368 being run. This is particularly useful if IPython is being used to
369 run unittests, which always exit with a sys.exit() call. In such
369 run unittests, which always exit with a sys.exit() call. In such
370 cases you are interested in the output of the test results, not in
370 cases you are interested in the output of the test results, not in
371 seeing a traceback of the unittest module.
371 seeing a traceback of the unittest module.
372
372
373 -t: print timing information at the end of the run. IPython will give
373 -t: print timing information at the end of the run. IPython will give
374 you an estimated CPU time consumption for your script, which under
374 you an estimated CPU time consumption for your script, which under
375 Unix uses the resource module to avoid the wraparound problems of
375 Unix uses the resource module to avoid the wraparound problems of
376 time.clock(). Under Unix, an estimate of time spent on system tasks
376 time.clock(). Under Unix, an estimate of time spent on system tasks
377 is also given (for Windows platforms this is reported as 0.0).
377 is also given (for Windows platforms this is reported as 0.0).
378
378
379 If -t is given, an additional -N<N> option can be given, where <N>
379 If -t is given, an additional -N<N> option can be given, where <N>
380 must be an integer indicating how many times you want the script to
380 must be an integer indicating how many times you want the script to
381 run. The final timing report will include total and per run results.
381 run. The final timing report will include total and per run results.
382
382
383 For example (testing the script uniq_stable.py)::
383 For example (testing the script uniq_stable.py)::
384
384
385 In [1]: run -t uniq_stable
385 In [1]: run -t uniq_stable
386
386
387 IPython CPU timings (estimated):\\
387 IPython CPU timings (estimated):\\
388 User : 0.19597 s.\\
388 User : 0.19597 s.\\
389 System: 0.0 s.\\
389 System: 0.0 s.\\
390
390
391 In [2]: run -t -N5 uniq_stable
391 In [2]: run -t -N5 uniq_stable
392
392
393 IPython CPU timings (estimated):\\
393 IPython CPU timings (estimated):\\
394 Total runs performed: 5\\
394 Total runs performed: 5\\
395 Times : Total Per run\\
395 Times : Total Per run\\
396 User : 0.910862 s, 0.1821724 s.\\
396 User : 0.910862 s, 0.1821724 s.\\
397 System: 0.0 s, 0.0 s.
397 System: 0.0 s, 0.0 s.
398
398
399 -d: run your program under the control of pdb, the Python debugger.
399 -d: run your program under the control of pdb, the Python debugger.
400 This allows you to execute your program step by step, watch variables,
400 This allows you to execute your program step by step, watch variables,
401 etc. Internally, what IPython does is similar to calling:
401 etc. Internally, what IPython does is similar to calling:
402
402
403 pdb.run('execfile("YOURFILENAME")')
403 pdb.run('execfile("YOURFILENAME")')
404
404
405 with a breakpoint set on line 1 of your file. You can change the line
405 with a breakpoint set on line 1 of your file. You can change the line
406 number for this automatic breakpoint to be <N> by using the -bN option
406 number for this automatic breakpoint to be <N> by using the -bN option
407 (where N must be an integer). For example::
407 (where N must be an integer). For example::
408
408
409 %run -d -b40 myscript
409 %run -d -b40 myscript
410
410
411 will set the first breakpoint at line 40 in myscript.py. Note that
411 will set the first breakpoint at line 40 in myscript.py. Note that
412 the first breakpoint must be set on a line which actually does
412 the first breakpoint must be set on a line which actually does
413 something (not a comment or docstring) for it to stop execution.
413 something (not a comment or docstring) for it to stop execution.
414
414
415 When the pdb debugger starts, you will see a (Pdb) prompt. You must
415 When the pdb debugger starts, you will see a (Pdb) prompt. You must
416 first enter 'c' (without quotes) to start execution up to the first
416 first enter 'c' (without quotes) to start execution up to the first
417 breakpoint.
417 breakpoint.
418
418
419 Entering 'help' gives information about the use of the debugger. You
419 Entering 'help' gives information about the use of the debugger. You
420 can easily see pdb's full documentation with "import pdb;pdb.help()"
420 can easily see pdb's full documentation with "import pdb;pdb.help()"
421 at a prompt.
421 at a prompt.
422
422
423 -p: run program under the control of the Python profiler module (which
423 -p: run program under the control of the Python profiler module (which
424 prints a detailed report of execution times, function calls, etc).
424 prints a detailed report of execution times, function calls, etc).
425
425
426 You can pass other options after -p which affect the behavior of the
426 You can pass other options after -p which affect the behavior of the
427 profiler itself. See the docs for %prun for details.
427 profiler itself. See the docs for %prun for details.
428
428
429 In this mode, the program's variables do NOT propagate back to the
429 In this mode, the program's variables do NOT propagate back to the
430 IPython interactive namespace (because they remain in the namespace
430 IPython interactive namespace (because they remain in the namespace
431 where the profiler executes them).
431 where the profiler executes them).
432
432
433 Internally this triggers a call to %prun, see its documentation for
433 Internally this triggers a call to %prun, see its documentation for
434 details on the options available specifically for profiling.
434 details on the options available specifically for profiling.
435
435
436 There is one special usage for which the text above doesn't apply:
436 There is one special usage for which the text above doesn't apply:
437 if the filename ends with .ipy, the file is run as ipython script,
437 if the filename ends with .ipy, the file is run as ipython script,
438 just as if the commands were written on IPython prompt.
438 just as if the commands were written on IPython prompt.
439
439
440 -m: specify module name to load instead of script path. Similar to
440 -m: specify module name to load instead of script path. Similar to
441 the -m option for the python interpreter. Use this option last if you
441 the -m option for the python interpreter. Use this option last if you
442 want to combine with other %run options. Unlike the python interpreter
442 want to combine with other %run options. Unlike the python interpreter
443 only source modules are allowed no .pyc or .pyo files.
443 only source modules are allowed no .pyc or .pyo files.
444 For example::
444 For example::
445
445
446 %run -m example
446 %run -m example
447
447
448 will run the example module.
448 will run the example module.
449
449
450 """
450 """
451
451
452 # get arguments and set sys.argv for program to be run.
452 # get arguments and set sys.argv for program to be run.
453 opts, arg_lst = self.parse_options(parameter_s, 'nidtN:b:pD:l:rs:T:em:',
453 opts, arg_lst = self.parse_options(parameter_s, 'nidtN:b:pD:l:rs:T:em:',
454 mode='list', list_all=1)
454 mode='list', list_all=1)
455 if "m" in opts:
455 if "m" in opts:
456 modulename = opts["m"][0]
456 modulename = opts["m"][0]
457 modpath = find_mod(modulename)
457 modpath = find_mod(modulename)
458 if modpath is None:
458 if modpath is None:
459 warn('%r is not a valid modulename on sys.path'%modulename)
459 warn('%r is not a valid modulename on sys.path'%modulename)
460 return
460 return
461 arg_lst = [modpath] + arg_lst
461 arg_lst = [modpath] + arg_lst
462 try:
462 try:
463 filename = file_finder(arg_lst[0])
463 filename = file_finder(arg_lst[0])
464 except IndexError:
464 except IndexError:
465 warn('you must provide at least a filename.')
465 warn('you must provide at least a filename.')
466 print '\n%run:\n', oinspect.getdoc(self.run)
466 print '\n%run:\n', oinspect.getdoc(self.run)
467 return
467 return
468 except IOError as e:
468 except IOError as e:
469 try:
469 try:
470 msg = str(e)
470 msg = str(e)
471 except UnicodeError:
471 except UnicodeError:
472 msg = e.message
472 msg = e.message
473 error(msg)
473 error(msg)
474 return
474 return
475
475
476 if filename.lower().endswith('.ipy'):
476 if filename.lower().endswith('.ipy'):
477 self.shell.safe_execfile_ipy(filename)
477 self.shell.safe_execfile_ipy(filename)
478 return
478 return
479
479
480 # Control the response to exit() calls made by the script being run
480 # Control the response to exit() calls made by the script being run
481 exit_ignore = 'e' in opts
481 exit_ignore = 'e' in opts
482
482
483 # Make sure that the running script gets a proper sys.argv as if it
483 # Make sure that the running script gets a proper sys.argv as if it
484 # were run from a system shell.
484 # were run from a system shell.
485 save_argv = sys.argv # save it for later restoring
485 save_argv = sys.argv # save it for later restoring
486
486
487 # simulate shell expansion on arguments, at least tilde expansion
487 # simulate shell expansion on arguments, at least tilde expansion
488 args = [ os.path.expanduser(a) for a in arg_lst[1:] ]
488 args = [ os.path.expanduser(a) for a in arg_lst[1:] ]
489
489
490 sys.argv = [filename] + args # put in the proper filename
490 sys.argv = [filename] + args # put in the proper filename
491 # protect sys.argv from potential unicode strings on Python 2:
491 # protect sys.argv from potential unicode strings on Python 2:
492 if not py3compat.PY3:
492 if not py3compat.PY3:
493 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
493 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
494
494
495 if 'i' in opts:
495 if 'i' in opts:
496 # Run in user's interactive namespace
496 # Run in user's interactive namespace
497 prog_ns = self.shell.user_ns
497 prog_ns = self.shell.user_ns
498 __name__save = self.shell.user_ns['__name__']
498 __name__save = self.shell.user_ns['__name__']
499 prog_ns['__name__'] = '__main__'
499 prog_ns['__name__'] = '__main__'
500 main_mod = self.shell.new_main_mod(prog_ns)
500 main_mod = self.shell.new_main_mod(prog_ns)
501 else:
501 else:
502 # Run in a fresh, empty namespace
502 # Run in a fresh, empty namespace
503 if 'n' in opts:
503 if 'n' in opts:
504 name = os.path.splitext(os.path.basename(filename))[0]
504 name = os.path.splitext(os.path.basename(filename))[0]
505 else:
505 else:
506 name = '__main__'
506 name = '__main__'
507
507
508 main_mod = self.shell.new_main_mod()
508 main_mod = self.shell.new_main_mod()
509 prog_ns = main_mod.__dict__
509 prog_ns = main_mod.__dict__
510 prog_ns['__name__'] = name
510 prog_ns['__name__'] = name
511
511
512 # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
512 # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
513 # set the __file__ global in the script's namespace
513 # set the __file__ global in the script's namespace
514 prog_ns['__file__'] = filename
514 prog_ns['__file__'] = filename
515
515
516 # pickle fix. See interactiveshell for an explanation. But we need to
516 # pickle fix. See interactiveshell for an explanation. But we need to
517 # make sure that, if we overwrite __main__, we replace it at the end
517 # make sure that, if we overwrite __main__, we replace it at the end
518 main_mod_name = prog_ns['__name__']
518 main_mod_name = prog_ns['__name__']
519
519
520 if main_mod_name == '__main__':
520 if main_mod_name == '__main__':
521 restore_main = sys.modules['__main__']
521 restore_main = sys.modules['__main__']
522 else:
522 else:
523 restore_main = False
523 restore_main = False
524
524
525 # This needs to be undone at the end to prevent holding references to
525 # This needs to be undone at the end to prevent holding references to
526 # every single object ever created.
526 # every single object ever created.
527 sys.modules[main_mod_name] = main_mod
527 sys.modules[main_mod_name] = main_mod
528
528
529 try:
529 try:
530 stats = None
530 stats = None
531 with self.shell.readline_no_record:
531 with self.shell.readline_no_record:
532 if 'p' in opts:
532 if 'p' in opts:
533 stats = self.prun('', None, False, opts, arg_lst, prog_ns)
533 stats = self.prun('', None, False, opts, arg_lst, prog_ns)
534 else:
534 else:
535 if 'd' in opts:
535 if 'd' in opts:
536 deb = debugger.Pdb(self.shell.colors)
536 deb = debugger.Pdb(self.shell.colors)
537 # reset Breakpoint state, which is moronically kept
537 # reset Breakpoint state, which is moronically kept
538 # in a class
538 # in a class
539 bdb.Breakpoint.next = 1
539 bdb.Breakpoint.next = 1
540 bdb.Breakpoint.bplist = {}
540 bdb.Breakpoint.bplist = {}
541 bdb.Breakpoint.bpbynumber = [None]
541 bdb.Breakpoint.bpbynumber = [None]
542 # Set an initial breakpoint to stop execution
542 # Set an initial breakpoint to stop execution
543 maxtries = 10
543 maxtries = 10
544 bp = int(opts.get('b', [1])[0])
544 bp = int(opts.get('b', [1])[0])
545 checkline = deb.checkline(filename, bp)
545 checkline = deb.checkline(filename, bp)
546 if not checkline:
546 if not checkline:
547 for bp in range(bp + 1, bp + maxtries + 1):
547 for bp in range(bp + 1, bp + maxtries + 1):
548 if deb.checkline(filename, bp):
548 if deb.checkline(filename, bp):
549 break
549 break
550 else:
550 else:
551 msg = ("\nI failed to find a valid line to set "
551 msg = ("\nI failed to find a valid line to set "
552 "a breakpoint\n"
552 "a breakpoint\n"
553 "after trying up to line: %s.\n"
553 "after trying up to line: %s.\n"
554 "Please set a valid breakpoint manually "
554 "Please set a valid breakpoint manually "
555 "with the -b option." % bp)
555 "with the -b option." % bp)
556 error(msg)
556 error(msg)
557 return
557 return
558 # if we find a good linenumber, set the breakpoint
558 # if we find a good linenumber, set the breakpoint
559 deb.do_break('%s:%s' % (filename, bp))
559 deb.do_break('%s:%s' % (filename, bp))
560 # Start file run
560 # Start file run
561 print "NOTE: Enter 'c' at the",
561 print "NOTE: Enter 'c' at the",
562 print "%s prompt to start your script." % deb.prompt
562 print "%s prompt to start your script." % deb.prompt
563 ns = {'execfile': py3compat.execfile, 'prog_ns': prog_ns}
563 ns = {'execfile': py3compat.execfile, 'prog_ns': prog_ns}
564 try:
564 try:
565 deb.run('execfile("%s", prog_ns)' % filename, ns)
565 deb.run('execfile("%s", prog_ns)' % filename, ns)
566
566
567 except:
567 except:
568 etype, value, tb = sys.exc_info()
568 etype, value, tb = sys.exc_info()
569 # Skip three frames in the traceback: the %run one,
569 # Skip three frames in the traceback: the %run one,
570 # one inside bdb.py, and the command-line typed by the
570 # one inside bdb.py, and the command-line typed by the
571 # user (run by exec in pdb itself).
571 # user (run by exec in pdb itself).
572 self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
572 self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
573 else:
573 else:
574 if runner is None:
574 if runner is None:
575 runner = self.default_runner
575 runner = self.default_runner
576 if runner is None:
576 if runner is None:
577 runner = self.shell.safe_execfile
577 runner = self.shell.safe_execfile
578 if 't' in opts:
578 if 't' in opts:
579 # timed execution
579 # timed execution
580 try:
580 try:
581 nruns = int(opts['N'][0])
581 nruns = int(opts['N'][0])
582 if nruns < 1:
582 if nruns < 1:
583 error('Number of runs must be >=1')
583 error('Number of runs must be >=1')
584 return
584 return
585 except (KeyError):
585 except (KeyError):
586 nruns = 1
586 nruns = 1
587 twall0 = time.time()
587 twall0 = time.time()
588 if nruns == 1:
588 if nruns == 1:
589 t0 = clock2()
589 t0 = clock2()
590 runner(filename, prog_ns, prog_ns,
590 runner(filename, prog_ns, prog_ns,
591 exit_ignore=exit_ignore)
591 exit_ignore=exit_ignore)
592 t1 = clock2()
592 t1 = clock2()
593 t_usr = t1[0] - t0[0]
593 t_usr = t1[0] - t0[0]
594 t_sys = t1[1] - t0[1]
594 t_sys = t1[1] - t0[1]
595 print "\nIPython CPU timings (estimated):"
595 print "\nIPython CPU timings (estimated):"
596 print " User : %10.2f s." % t_usr
596 print " User : %10.2f s." % t_usr
597 print " System : %10.2f s." % t_sys
597 print " System : %10.2f s." % t_sys
598 else:
598 else:
599 runs = range(nruns)
599 runs = range(nruns)
600 t0 = clock2()
600 t0 = clock2()
601 for nr in runs:
601 for nr in runs:
602 runner(filename, prog_ns, prog_ns,
602 runner(filename, prog_ns, prog_ns,
603 exit_ignore=exit_ignore)
603 exit_ignore=exit_ignore)
604 t1 = clock2()
604 t1 = clock2()
605 t_usr = t1[0] - t0[0]
605 t_usr = t1[0] - t0[0]
606 t_sys = t1[1] - t0[1]
606 t_sys = t1[1] - t0[1]
607 print "\nIPython CPU timings (estimated):"
607 print "\nIPython CPU timings (estimated):"
608 print "Total runs performed:", nruns
608 print "Total runs performed:", nruns
609 print " Times : %10.2f %10.2f" % ('Total', 'Per run')
609 print " Times : %10.2f %10.2f" % ('Total', 'Per run')
610 print " User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns)
610 print " User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns)
611 print " System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns)
611 print " System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns)
612 twall1 = time.time()
612 twall1 = time.time()
613 print "Wall time: %10.2f s." % (twall1 - twall0)
613 print "Wall time: %10.2f s." % (twall1 - twall0)
614
614
615 else:
615 else:
616 # regular execution
616 # regular execution
617 runner(filename, prog_ns, prog_ns, exit_ignore=exit_ignore)
617 runner(filename, prog_ns, prog_ns, exit_ignore=exit_ignore)
618
618
619 if 'i' in opts:
619 if 'i' in opts:
620 self.shell.user_ns['__name__'] = __name__save
620 self.shell.user_ns['__name__'] = __name__save
621 else:
621 else:
622 # The shell MUST hold a reference to prog_ns so after %run
622 # The shell MUST hold a reference to prog_ns so after %run
623 # exits, the python deletion mechanism doesn't zero it out
623 # exits, the python deletion mechanism doesn't zero it out
624 # (leaving dangling references).
624 # (leaving dangling references).
625 self.shell.cache_main_mod(prog_ns, filename)
625 self.shell.cache_main_mod(prog_ns, filename)
626 # update IPython interactive namespace
626 # update IPython interactive namespace
627
627
628 # Some forms of read errors on the file may mean the
628 # Some forms of read errors on the file may mean the
629 # __name__ key was never set; using pop we don't have to
629 # __name__ key was never set; using pop we don't have to
630 # worry about a possible KeyError.
630 # worry about a possible KeyError.
631 prog_ns.pop('__name__', None)
631 prog_ns.pop('__name__', None)
632
632
633 self.shell.user_ns.update(prog_ns)
633 self.shell.user_ns.update(prog_ns)
634 finally:
634 finally:
635 # It's a bit of a mystery why, but __builtins__ can change from
635 # It's a bit of a mystery why, but __builtins__ can change from
636 # being a module to becoming a dict missing some key data after
636 # being a module to becoming a dict missing some key data after
637 # %run. As best I can see, this is NOT something IPython is doing
637 # %run. As best I can see, this is NOT something IPython is doing
638 # at all, and similar problems have been reported before:
638 # at all, and similar problems have been reported before:
639 # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
639 # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
640 # Since this seems to be done by the interpreter itself, the best
640 # Since this seems to be done by the interpreter itself, the best
641 # we can do is to at least restore __builtins__ for the user on
641 # we can do is to at least restore __builtins__ for the user on
642 # exit.
642 # exit.
643 self.shell.user_ns['__builtins__'] = builtin_mod
643 self.shell.user_ns['__builtins__'] = builtin_mod
644
644
645 # Ensure key global structures are restored
645 # Ensure key global structures are restored
646 sys.argv = save_argv
646 sys.argv = save_argv
647 if restore_main:
647 if restore_main:
648 sys.modules['__main__'] = restore_main
648 sys.modules['__main__'] = restore_main
649 else:
649 else:
650 # Remove from sys.modules the reference to main_mod we'd
650 # Remove from sys.modules the reference to main_mod we'd
651 # added. Otherwise it will trap references to objects
651 # added. Otherwise it will trap references to objects
652 # contained therein.
652 # contained therein.
653 del sys.modules[main_mod_name]
653 del sys.modules[main_mod_name]
654
654
655 return stats
655 return stats
656
656
657 @skip_doctest
657 @skip_doctest
658 @line_cell_magic
658 @line_cell_magic
659 def timeit(self, line='', cell=None):
659 def timeit(self, line='', cell=None):
660 """Time execution of a Python statement or expression
660 """Time execution of a Python statement or expression
661
661
662 Usage, in line mode:
662 Usage, in line mode:
663 %timeit [-n<N> -r<R> [-t|-c]] statement
663 %timeit [-n<N> -r<R> [-t|-c]] statement
664 or in cell mode:
664 or in cell mode:
665 %%timeit [-n<N> -r<R> [-t|-c]] setup_code
665 %%timeit [-n<N> -r<R> [-t|-c]] setup_code
666 code
666 code
667 code...
667 code...
668
668
669 Time execution of a Python statement or expression using the timeit
669 Time execution of a Python statement or expression using the timeit
670 module. This function can be used both as a line and cell magic:
670 module. This function can be used both as a line and cell magic:
671
671
672 - In line mode you can time a single-line statement (though multiple
672 - In line mode you can time a single-line statement (though multiple
673 ones can be chained with using semicolons).
673 ones can be chained with using semicolons).
674
674
675 - In cell mode, the statement in the first line is used as setup code
675 - In cell mode, the statement in the first line is used as setup code
676 (executed but not timed) and the body of the cell is timed. The cell
676 (executed but not timed) and the body of the cell is timed. The cell
677 body has access to any variables created in the setup code.
677 body has access to any variables created in the setup code.
678
678
679 Options:
679 Options:
680 -n<N>: execute the given statement <N> times in a loop. If this value
680 -n<N>: execute the given statement <N> times in a loop. If this value
681 is not given, a fitting value is chosen.
681 is not given, a fitting value is chosen.
682
682
683 -r<R>: repeat the loop iteration <R> times and take the best result.
683 -r<R>: repeat the loop iteration <R> times and take the best result.
684 Default: 3
684 Default: 3
685
685
686 -t: use time.time to measure the time, which is the default on Unix.
686 -t: use time.time to measure the time, which is the default on Unix.
687 This function measures wall time.
687 This function measures wall time.
688
688
689 -c: use time.clock to measure the time, which is the default on
689 -c: use time.clock to measure the time, which is the default on
690 Windows and measures wall time. On Unix, resource.getrusage is used
690 Windows and measures wall time. On Unix, resource.getrusage is used
691 instead and returns the CPU user time.
691 instead and returns the CPU user time.
692
692
693 -p<P>: use a precision of <P> digits to display the timing result.
693 -p<P>: use a precision of <P> digits to display the timing result.
694 Default: 3
694 Default: 3
695
695
696
696
697 Examples
697 Examples
698 --------
698 --------
699 ::
699 ::
700
700
701 In [1]: %timeit pass
701 In [1]: %timeit pass
702 10000000 loops, best of 3: 53.3 ns per loop
702 10000000 loops, best of 3: 53.3 ns per loop
703
703
704 In [2]: u = None
704 In [2]: u = None
705
705
706 In [3]: %timeit u is None
706 In [3]: %timeit u is None
707 10000000 loops, best of 3: 184 ns per loop
707 10000000 loops, best of 3: 184 ns per loop
708
708
709 In [4]: %timeit -r 4 u == None
709 In [4]: %timeit -r 4 u == None
710 1000000 loops, best of 4: 242 ns per loop
710 1000000 loops, best of 4: 242 ns per loop
711
711
712 In [5]: import time
712 In [5]: import time
713
713
714 In [6]: %timeit -n1 time.sleep(2)
714 In [6]: %timeit -n1 time.sleep(2)
715 1 loops, best of 3: 2 s per loop
715 1 loops, best of 3: 2 s per loop
716
716
717
717
718 The times reported by %timeit will be slightly higher than those
718 The times reported by %timeit will be slightly higher than those
719 reported by the timeit.py script when variables are accessed. This is
719 reported by the timeit.py script when variables are accessed. This is
720 due to the fact that %timeit executes the statement in the namespace
720 due to the fact that %timeit executes the statement in the namespace
721 of the shell, compared with timeit.py, which uses a single setup
721 of the shell, compared with timeit.py, which uses a single setup
722 statement to import function or create variables. Generally, the bias
722 statement to import function or create variables. Generally, the bias
723 does not matter as long as results from timeit.py are not mixed with
723 does not matter as long as results from timeit.py are not mixed with
724 those from %timeit."""
724 those from %timeit."""
725
725
726 import timeit
726 import timeit
727 import math
727 import math
728
728
729 # XXX: Unfortunately the unicode 'micro' symbol can cause problems in
729 # XXX: Unfortunately the unicode 'micro' symbol can cause problems in
730 # certain terminals. Until we figure out a robust way of
730 # certain terminals. Until we figure out a robust way of
731 # auto-detecting if the terminal can deal with it, use plain 'us' for
731 # auto-detecting if the terminal can deal with it, use plain 'us' for
732 # microseconds. I am really NOT happy about disabling the proper
732 # microseconds. I am really NOT happy about disabling the proper
733 # 'micro' prefix, but crashing is worse... If anyone knows what the
733 # 'micro' prefix, but crashing is worse... If anyone knows what the
734 # right solution for this is, I'm all ears...
734 # right solution for this is, I'm all ears...
735 #
735 #
736 # Note: using
736 # Note: using
737 #
737 #
738 # s = u'\xb5'
738 # s = u'\xb5'
739 # s.encode(sys.getdefaultencoding())
739 # s.encode(sys.getdefaultencoding())
740 #
740 #
741 # is not sufficient, as I've seen terminals where that fails but
741 # is not sufficient, as I've seen terminals where that fails but
742 # print s
742 # print s
743 #
743 #
744 # succeeds
744 # succeeds
745 #
745 #
746 # See bug: https://bugs.launchpad.net/ipython/+bug/348466
746 # See bug: https://bugs.launchpad.net/ipython/+bug/348466
747
747
748 #units = [u"s", u"ms",u'\xb5',"ns"]
748 #units = [u"s", u"ms",u'\xb5',"ns"]
749 units = [u"s", u"ms",u'us',"ns"]
749 units = [u"s", u"ms",u'us',"ns"]
750
750
751 scaling = [1, 1e3, 1e6, 1e9]
751 scaling = [1, 1e3, 1e6, 1e9]
752
752
753 opts, stmt = self.parse_options(line,'n:r:tcp:',
753 opts, stmt = self.parse_options(line,'n:r:tcp:',
754 posix=False, strict=False)
754 posix=False, strict=False)
755 if stmt == "" and cell is None:
755 if stmt == "" and cell is None:
756 return
756 return
757 timefunc = timeit.default_timer
757 timefunc = timeit.default_timer
758 number = int(getattr(opts, "n", 0))
758 number = int(getattr(opts, "n", 0))
759 repeat = int(getattr(opts, "r", timeit.default_repeat))
759 repeat = int(getattr(opts, "r", timeit.default_repeat))
760 precision = int(getattr(opts, "p", 3))
760 precision = int(getattr(opts, "p", 3))
761 if hasattr(opts, "t"):
761 if hasattr(opts, "t"):
762 timefunc = time.time
762 timefunc = time.time
763 if hasattr(opts, "c"):
763 if hasattr(opts, "c"):
764 timefunc = clock
764 timefunc = clock
765
765
766 timer = timeit.Timer(timer=timefunc)
766 timer = timeit.Timer(timer=timefunc)
767 # this code has tight coupling to the inner workings of timeit.Timer,
767 # this code has tight coupling to the inner workings of timeit.Timer,
768 # but is there a better way to achieve that the code stmt has access
768 # but is there a better way to achieve that the code stmt has access
769 # to the shell namespace?
769 # to the shell namespace?
770 transform = self.shell.input_splitter.transform_cell
770 transform = self.shell.input_splitter.transform_cell
771 if cell is None:
771 if cell is None:
772 # called as line magic
772 # called as line magic
773 setup = 'pass'
773 setup = 'pass'
774 stmt = timeit.reindent(transform(stmt), 8)
774 stmt = timeit.reindent(transform(stmt), 8)
775 else:
775 else:
776 setup = timeit.reindent(transform(stmt), 4)
776 setup = timeit.reindent(transform(stmt), 4)
777 stmt = timeit.reindent(transform(cell), 8)
777 stmt = timeit.reindent(transform(cell), 8)
778
778
779 # From Python 3.3, this template uses new-style string formatting.
779 # From Python 3.3, this template uses new-style string formatting.
780 if sys.version_info >= (3, 3):
780 if sys.version_info >= (3, 3):
781 src = timeit.template.format(stmt=stmt, setup=setup)
781 src = timeit.template.format(stmt=stmt, setup=setup)
782 else:
782 else:
783 src = timeit.template % dict(stmt=stmt, setup=setup)
783 src = timeit.template % dict(stmt=stmt, setup=setup)
784
784
785 # Track compilation time so it can be reported if too long
785 # Track compilation time so it can be reported if too long
786 # Minimum time above which compilation time will be reported
786 # Minimum time above which compilation time will be reported
787 tc_min = 0.1
787 tc_min = 0.1
788
788
789 t0 = clock()
789 t0 = clock()
790 code = compile(src, "<magic-timeit>", "exec")
790 code = compile(src, "<magic-timeit>", "exec")
791 tc = clock()-t0
791 tc = clock()-t0
792
792
793 ns = {}
793 ns = {}
794 exec code in self.shell.user_ns, ns
794 exec code in self.shell.user_ns, ns
795 timer.inner = ns["inner"]
795 timer.inner = ns["inner"]
796
796
797 if number == 0:
797 if number == 0:
798 # determine number so that 0.2 <= total time < 2.0
798 # determine number so that 0.2 <= total time < 2.0
799 number = 1
799 number = 1
800 for i in range(1, 10):
800 for i in range(1, 10):
801 if timer.timeit(number) >= 0.2:
801 if timer.timeit(number) >= 0.2:
802 break
802 break
803 number *= 10
803 number *= 10
804
804
805 best = min(timer.repeat(repeat, number)) / number
805 best = min(timer.repeat(repeat, number)) / number
806
806
807 if best > 0.0 and best < 1000.0:
807 if best > 0.0 and best < 1000.0:
808 order = min(-int(math.floor(math.log10(best)) // 3), 3)
808 order = min(-int(math.floor(math.log10(best)) // 3), 3)
809 elif best >= 1000.0:
809 elif best >= 1000.0:
810 order = 0
810 order = 0
811 else:
811 else:
812 order = 3
812 order = 3
813 print u"%d loops, best of %d: %.*g %s per loop" % (number, repeat,
813 print u"%d loops, best of %d: %.*g %s per loop" % (number, repeat,
814 precision,
814 precision,
815 best * scaling[order],
815 best * scaling[order],
816 units[order])
816 units[order])
817 if tc > tc_min:
817 if tc > tc_min:
818 print "Compiler time: %.2f s" % tc
818 print "Compiler time: %.2f s" % tc
819
819
820 @skip_doctest
820 @skip_doctest
821 @needs_local_scope
821 @needs_local_scope
822 @line_magic
822 @line_magic
823 def time(self,parameter_s, user_locals):
823 def time(self,parameter_s, user_locals):
824 """Time execution of a Python statement or expression.
824 """Time execution of a Python statement or expression.
825
825
826 The CPU and wall clock times are printed, and the value of the
826 The CPU and wall clock times are printed, and the value of the
827 expression (if any) is returned. Note that under Win32, system time
827 expression (if any) is returned. Note that under Win32, system time
828 is always reported as 0, since it can not be measured.
828 is always reported as 0, since it can not be measured.
829
829
830 This function provides very basic timing functionality. In Python
830 This function provides very basic timing functionality. In Python
831 2.3, the timeit module offers more control and sophistication, so this
831 2.3, the timeit module offers more control and sophistication, so this
832 could be rewritten to use it (patches welcome).
832 could be rewritten to use it (patches welcome).
833
833
834 Examples
834 Examples
835 --------
835 --------
836 ::
836 ::
837
837
838 In [1]: time 2**128
838 In [1]: time 2**128
839 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
839 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
840 Wall time: 0.00
840 Wall time: 0.00
841 Out[1]: 340282366920938463463374607431768211456L
841 Out[1]: 340282366920938463463374607431768211456L
842
842
843 In [2]: n = 1000000
843 In [2]: n = 1000000
844
844
845 In [3]: time sum(range(n))
845 In [3]: time sum(range(n))
846 CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
846 CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
847 Wall time: 1.37
847 Wall time: 1.37
848 Out[3]: 499999500000L
848 Out[3]: 499999500000L
849
849
850 In [4]: time print 'hello world'
850 In [4]: time print 'hello world'
851 hello world
851 hello world
852 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
852 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
853 Wall time: 0.00
853 Wall time: 0.00
854
854
855 Note that the time needed by Python to compile the given expression
855 Note that the time needed by Python to compile the given expression
856 will be reported if it is more than 0.1s. In this example, the
856 will be reported if it is more than 0.1s. In this example, the
857 actual exponentiation is done by Python at compilation time, so while
857 actual exponentiation is done by Python at compilation time, so while
858 the expression can take a noticeable amount of time to compute, that
858 the expression can take a noticeable amount of time to compute, that
859 time is purely due to the compilation:
859 time is purely due to the compilation:
860
860
861 In [5]: time 3**9999;
861 In [5]: time 3**9999;
862 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
862 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
863 Wall time: 0.00 s
863 Wall time: 0.00 s
864
864
865 In [6]: time 3**999999;
865 In [6]: time 3**999999;
866 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
866 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
867 Wall time: 0.00 s
867 Wall time: 0.00 s
868 Compiler : 0.78 s
868 Compiler : 0.78 s
869 """
869 """
870
870
871 # fail immediately if the given expression can't be compiled
871 # fail immediately if the given expression can't be compiled
872
872
873 expr = self.shell.prefilter(parameter_s,False)
873 expr = self.shell.prefilter(parameter_s,False)
874
874
875 # Minimum time above which compilation time will be reported
875 # Minimum time above which compilation time will be reported
876 tc_min = 0.1
876 tc_min = 0.1
877
877
878 try:
878 try:
879 mode = 'eval'
879 mode = 'eval'
880 t0 = clock()
880 t0 = clock()
881 code = compile(expr,'<timed eval>',mode)
881 code = compile(expr,'<timed eval>',mode)
882 tc = clock()-t0
882 tc = clock()-t0
883 except SyntaxError:
883 except SyntaxError:
884 mode = 'exec'
884 mode = 'exec'
885 t0 = clock()
885 t0 = clock()
886 code = compile(expr,'<timed exec>',mode)
886 code = compile(expr,'<timed exec>',mode)
887 tc = clock()-t0
887 tc = clock()-t0
888 # skew measurement as little as possible
888 # skew measurement as little as possible
889 glob = self.shell.user_ns
889 glob = self.shell.user_ns
890 wtime = time.time
890 wtime = time.time
891 # time execution
891 # time execution
892 wall_st = wtime()
892 wall_st = wtime()
893 if mode=='eval':
893 if mode=='eval':
894 st = clock2()
894 st = clock2()
895 out = eval(code, glob, user_locals)
895 out = eval(code, glob, user_locals)
896 end = clock2()
896 end = clock2()
897 else:
897 else:
898 st = clock2()
898 st = clock2()
899 exec code in glob, user_locals
899 exec code in glob, user_locals
900 end = clock2()
900 end = clock2()
901 out = None
901 out = None
902 wall_end = wtime()
902 wall_end = wtime()
903 # Compute actual times and report
903 # Compute actual times and report
904 wall_time = wall_end-wall_st
904 wall_time = wall_end-wall_st
905 cpu_user = end[0]-st[0]
905 cpu_user = end[0]-st[0]
906 cpu_sys = end[1]-st[1]
906 cpu_sys = end[1]-st[1]
907 cpu_tot = cpu_user+cpu_sys
907 cpu_tot = cpu_user+cpu_sys
908 print "CPU times: user %.2f s, sys: %.2f s, total: %.2f s" % \
908 print "CPU times: user %.2f s, sys: %.2f s, total: %.2f s" % \
909 (cpu_user,cpu_sys,cpu_tot)
909 (cpu_user,cpu_sys,cpu_tot)
910 print "Wall time: %.2f s" % wall_time
910 print "Wall time: %.2f s" % wall_time
911 if tc > tc_min:
911 if tc > tc_min:
912 print "Compiler : %.2f s" % tc
912 print "Compiler : %.2f s" % tc
913 return out
913 return out
914
914
915 @skip_doctest
915 @skip_doctest
916 @line_magic
916 @line_magic
917 def macro(self, parameter_s=''):
917 def macro(self, parameter_s=''):
918 """Define a macro for future re-execution. It accepts ranges of history,
918 """Define a macro for future re-execution. It accepts ranges of history,
919 filenames or string objects.
919 filenames or string objects.
920
920
921 Usage:\\
921 Usage:\\
922 %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
922 %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
923
923
924 Options:
924 Options:
925
925
926 -r: use 'raw' input. By default, the 'processed' history is used,
926 -r: use 'raw' input. By default, the 'processed' history is used,
927 so that magics are loaded in their transformed version to valid
927 so that magics are loaded in their transformed version to valid
928 Python. If this option is given, the raw input as typed as the
928 Python. If this option is given, the raw input as typed as the
929 command line is used instead.
929 command line is used instead.
930
930
931 This will define a global variable called `name` which is a string
931 This will define a global variable called `name` which is a string
932 made of joining the slices and lines you specify (n1,n2,... numbers
932 made of joining the slices and lines you specify (n1,n2,... numbers
933 above) from your input history into a single string. This variable
933 above) from your input history into a single string. This variable
934 acts like an automatic function which re-executes those lines as if
934 acts like an automatic function which re-executes those lines as if
935 you had typed them. You just type 'name' at the prompt and the code
935 you had typed them. You just type 'name' at the prompt and the code
936 executes.
936 executes.
937
937
938 The syntax for indicating input ranges is described in %history.
938 The syntax for indicating input ranges is described in %history.
939
939
940 Note: as a 'hidden' feature, you can also use traditional python slice
940 Note: as a 'hidden' feature, you can also use traditional python slice
941 notation, where N:M means numbers N through M-1.
941 notation, where N:M means numbers N through M-1.
942
942
943 For example, if your history contains (%hist prints it)::
943 For example, if your history contains (%hist prints it)::
944
944
945 44: x=1
945 44: x=1
946 45: y=3
946 45: y=3
947 46: z=x+y
947 46: z=x+y
948 47: print x
948 47: print x
949 48: a=5
949 48: a=5
950 49: print 'x',x,'y',y
950 49: print 'x',x,'y',y
951
951
952 you can create a macro with lines 44 through 47 (included) and line 49
952 you can create a macro with lines 44 through 47 (included) and line 49
953 called my_macro with::
953 called my_macro with::
954
954
955 In [55]: %macro my_macro 44-47 49
955 In [55]: %macro my_macro 44-47 49
956
956
957 Now, typing `my_macro` (without quotes) will re-execute all this code
957 Now, typing `my_macro` (without quotes) will re-execute all this code
958 in one pass.
958 in one pass.
959
959
960 You don't need to give the line-numbers in order, and any given line
960 You don't need to give the line-numbers in order, and any given line
961 number can appear multiple times. You can assemble macros with any
961 number can appear multiple times. You can assemble macros with any
962 lines from your input history in any order.
962 lines from your input history in any order.
963
963
964 The macro is a simple object which holds its value in an attribute,
964 The macro is a simple object which holds its value in an attribute,
965 but IPython's display system checks for macros and executes them as
965 but IPython's display system checks for macros and executes them as
966 code instead of printing them when you type their name.
966 code instead of printing them when you type their name.
967
967
968 You can view a macro's contents by explicitly printing it with::
968 You can view a macro's contents by explicitly printing it with::
969
969
970 print macro_name
970 print macro_name
971
971
972 """
972 """
973 opts,args = self.parse_options(parameter_s,'r',mode='list')
973 opts,args = self.parse_options(parameter_s,'r',mode='list')
974 if not args: # List existing macros
974 if not args: # List existing macros
975 return sorted(k for k,v in self.shell.user_ns.iteritems() if\
975 return sorted(k for k,v in self.shell.user_ns.iteritems() if\
976 isinstance(v, Macro))
976 isinstance(v, Macro))
977 if len(args) == 1:
977 if len(args) == 1:
978 raise UsageError(
978 raise UsageError(
979 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
979 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
980 name, codefrom = args[0], " ".join(args[1:])
980 name, codefrom = args[0], " ".join(args[1:])
981
981
982 #print 'rng',ranges # dbg
982 #print 'rng',ranges # dbg
983 try:
983 try:
984 lines = self.shell.find_user_code(codefrom, 'r' in opts)
984 lines = self.shell.find_user_code(codefrom, 'r' in opts)
985 except (ValueError, TypeError) as e:
985 except (ValueError, TypeError) as e:
986 print e.args[0]
986 print e.args[0]
987 return
987 return
988 macro = Macro(lines)
988 macro = Macro(lines)
989 self.shell.define_macro(name, macro)
989 self.shell.define_macro(name, macro)
990 print 'Macro `%s` created. To execute, type its name (without quotes).' % name
990 print 'Macro `%s` created. To execute, type its name (without quotes).' % name
991 print '=== Macro contents: ==='
991 print '=== Macro contents: ==='
992 print macro,
992 print macro,
993
993
994 @magic_arguments.magic_arguments()
994 @magic_arguments.magic_arguments()
995 @magic_arguments.argument('output', type=str, default='', nargs='?',
995 @magic_arguments.argument('output', type=str, default='', nargs='?',
996 help="""The name of the variable in which to store output.
996 help="""The name of the variable in which to store output.
997 This is a utils.io.CapturedIO object with stdout/err attributes
997 This is a utils.io.CapturedIO object with stdout/err attributes
998 for the text of the captured output.
998 for the text of the captured output.
999
999
1000 CapturedOutput also has a show() method for displaying the output,
1000 CapturedOutput also has a show() method for displaying the output,
1001 and __call__ as well, so you can use that to quickly display the
1001 and __call__ as well, so you can use that to quickly display the
1002 output.
1002 output.
1003
1003
1004 If unspecified, captured output is discarded.
1004 If unspecified, captured output is discarded.
1005 """
1005 """
1006 )
1006 )
1007 @magic_arguments.argument('--no-stderr', action="store_true",
1007 @magic_arguments.argument('--no-stderr', action="store_true",
1008 help="""Don't capture stderr."""
1008 help="""Don't capture stderr."""
1009 )
1009 )
1010 @magic_arguments.argument('--no-stdout', action="store_true",
1010 @magic_arguments.argument('--no-stdout', action="store_true",
1011 help="""Don't capture stdout."""
1011 help="""Don't capture stdout."""
1012 )
1012 )
1013 @cell_magic
1013 @cell_magic
1014 def capture(self, line, cell):
1014 def capture(self, line, cell):
1015 """run the cell, capturing stdout/err"""
1015 """run the cell, capturing stdout/err"""
1016 args = magic_arguments.parse_argstring(self.capture, line)
1016 args = magic_arguments.parse_argstring(self.capture, line)
1017 out = not args.no_stdout
1017 out = not args.no_stdout
1018 err = not args.no_stderr
1018 err = not args.no_stderr
1019 with capture_output(out, err) as io:
1019 with capture_output(out, err) as io:
1020 self.shell.run_cell(cell)
1020 self.shell.run_cell(cell)
1021 if args.output:
1021 if args.output:
1022 self.shell.user_ns[args.output] = io
1022 self.shell.user_ns[args.output] = io
@@ -1,700 +1,700 b''
1 """Implementation of namespace-related magic functions.
1 """Implementation of namespace-related magic functions.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
4 # Copyright (c) 2012 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 # Stdlib
15 # Stdlib
16 import gc
16 import gc
17 import re
17 import re
18 import sys
18 import sys
19
19
20 # Our own packages
20 # Our own packages
21 from IPython.core import page
21 from IPython.core import page
22 from IPython.core.error import StdinNotImplementedError
22 from IPython.core.error import StdinNotImplementedError
23 from IPython.core.magic import Magics, magics_class, line_magic
23 from IPython.core.magic import Magics, magics_class, line_magic
24 from IPython.testing.skipdoctest import skip_doctest
24 from IPython.testing.skipdoctest import skip_doctest
25 from IPython.utils.encoding import DEFAULT_ENCODING
25 from IPython.utils.encoding import DEFAULT_ENCODING
26 from IPython.utils.path import get_py_filename
26 from IPython.utils.path import get_py_filename
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Magic implementation classes
29 # Magic implementation classes
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 @magics_class
32 @magics_class
33 class NamespaceMagics(Magics):
33 class NamespaceMagics(Magics):
34 """Magics to manage various aspects of the user's namespace.
34 """Magics to manage various aspects of the user's namespace.
35
35
36 These include listing variables, introspecting into them, etc.
36 These include listing variables, introspecting into them, etc.
37 """
37 """
38
38
39 @line_magic
39 @line_magic
40 def pinfo(self, parameter_s='', namespaces=None):
40 def pinfo(self, parameter_s='', namespaces=None):
41 """Provide detailed information about an object.
41 """Provide detailed information about an object.
42
42
43 '%pinfo object' is just a synonym for object? or ?object."""
43 '%pinfo object' is just a synonym for object? or ?object."""
44
44
45 #print 'pinfo par: <%s>' % parameter_s # dbg
45 #print 'pinfo par: <%s>' % parameter_s # dbg
46 # detail_level: 0 -> obj? , 1 -> obj??
46 # detail_level: 0 -> obj? , 1 -> obj??
47 detail_level = 0
47 detail_level = 0
48 # We need to detect if we got called as 'pinfo pinfo foo', which can
48 # We need to detect if we got called as 'pinfo pinfo foo', which can
49 # happen if the user types 'pinfo foo?' at the cmd line.
49 # happen if the user types 'pinfo foo?' at the cmd line.
50 pinfo,qmark1,oname,qmark2 = \
50 pinfo,qmark1,oname,qmark2 = \
51 re.match('(pinfo )?(\?*)(.*?)(\??$)',parameter_s).groups()
51 re.match('(pinfo )?(\?*)(.*?)(\??$)',parameter_s).groups()
52 if pinfo or qmark1 or qmark2:
52 if pinfo or qmark1 or qmark2:
53 detail_level = 1
53 detail_level = 1
54 if "*" in oname:
54 if "*" in oname:
55 self.psearch(oname)
55 self.psearch(oname)
56 else:
56 else:
57 self.shell._inspect('pinfo', oname, detail_level=detail_level,
57 self.shell._inspect('pinfo', oname, detail_level=detail_level,
58 namespaces=namespaces)
58 namespaces=namespaces)
59
59
60 @line_magic
60 @line_magic
61 def pinfo2(self, parameter_s='', namespaces=None):
61 def pinfo2(self, parameter_s='', namespaces=None):
62 """Provide extra detailed information about an object.
62 """Provide extra detailed information about an object.
63
63
64 '%pinfo2 object' is just a synonym for object?? or ??object."""
64 '%pinfo2 object' is just a synonym for object?? or ??object."""
65 self.shell._inspect('pinfo', parameter_s, detail_level=1,
65 self.shell._inspect('pinfo', parameter_s, detail_level=1,
66 namespaces=namespaces)
66 namespaces=namespaces)
67
67
68 @skip_doctest
68 @skip_doctest
69 @line_magic
69 @line_magic
70 def pdef(self, parameter_s='', namespaces=None):
70 def pdef(self, parameter_s='', namespaces=None):
71 """Print the definition header for any callable object.
71 """Print the definition header for any callable object.
72
72
73 If the object is a class, print the constructor information.
73 If the object is a class, print the constructor information.
74
74
75 Examples
75 Examples
76 --------
76 --------
77 ::
77 ::
78
78
79 In [3]: %pdef urllib.urlopen
79 In [3]: %pdef urllib.urlopen
80 urllib.urlopen(url, data=None, proxies=None)
80 urllib.urlopen(url, data=None, proxies=None)
81 """
81 """
82 self.shell._inspect('pdef',parameter_s, namespaces)
82 self.shell._inspect('pdef',parameter_s, namespaces)
83
83
84 @line_magic
84 @line_magic
85 def pdoc(self, parameter_s='', namespaces=None):
85 def pdoc(self, parameter_s='', namespaces=None):
86 """Print the docstring for an object.
86 """Print the docstring for an object.
87
87
88 If the given object is a class, it will print both the class and the
88 If the given object is a class, it will print both the class and the
89 constructor docstrings."""
89 constructor docstrings."""
90 self.shell._inspect('pdoc',parameter_s, namespaces)
90 self.shell._inspect('pdoc',parameter_s, namespaces)
91
91
92 @line_magic
92 @line_magic
93 def psource(self, parameter_s='', namespaces=None):
93 def psource(self, parameter_s='', namespaces=None):
94 """Print (or run through pager) the source code for an object."""
94 """Print (or run through pager) the source code for an object."""
95 self.shell._inspect('psource',parameter_s, namespaces)
95 self.shell._inspect('psource',parameter_s, namespaces)
96
96
97 @line_magic
97 @line_magic
98 def pfile(self, parameter_s=''):
98 def pfile(self, parameter_s=''):
99 """Print (or run through pager) the file where an object is defined.
99 """Print (or run through pager) the file where an object is defined.
100
100
101 The file opens at the line where the object definition begins. IPython
101 The file opens at the line where the object definition begins. IPython
102 will honor the environment variable PAGER if set, and otherwise will
102 will honor the environment variable PAGER if set, and otherwise will
103 do its best to print the file in a convenient form.
103 do its best to print the file in a convenient form.
104
104
105 If the given argument is not an object currently defined, IPython will
105 If the given argument is not an object currently defined, IPython will
106 try to interpret it as a filename (automatically adding a .py extension
106 try to interpret it as a filename (automatically adding a .py extension
107 if needed). You can thus use %pfile as a syntax highlighting code
107 if needed). You can thus use %pfile as a syntax highlighting code
108 viewer."""
108 viewer."""
109
109
110 # first interpret argument as an object name
110 # first interpret argument as an object name
111 out = self.shell._inspect('pfile',parameter_s)
111 out = self.shell._inspect('pfile',parameter_s)
112 # if not, try the input as a filename
112 # if not, try the input as a filename
113 if out == 'not found':
113 if out == 'not found':
114 try:
114 try:
115 filename = get_py_filename(parameter_s)
115 filename = get_py_filename(parameter_s)
116 except IOError as msg:
116 except IOError as msg:
117 print msg
117 print msg
118 return
118 return
119 page.page(self.shell.inspector.format(open(filename).read()))
119 page.page(self.shell.inspector.format(open(filename).read()))
120
120
121 @line_magic
121 @line_magic
122 def psearch(self, parameter_s=''):
122 def psearch(self, parameter_s=''):
123 """Search for object in namespaces by wildcard.
123 """Search for object in namespaces by wildcard.
124
124
125 %psearch [options] PATTERN [OBJECT TYPE]
125 %psearch [options] PATTERN [OBJECT TYPE]
126
126
127 Note: ? can be used as a synonym for %psearch, at the beginning or at
127 Note: ? can be used as a synonym for %psearch, at the beginning or at
128 the end: both a*? and ?a* are equivalent to '%psearch a*'. Still, the
128 the end: both a*? and ?a* are equivalent to '%psearch a*'. Still, the
129 rest of the command line must be unchanged (options come first), so
129 rest of the command line must be unchanged (options come first), so
130 for example the following forms are equivalent
130 for example the following forms are equivalent
131
131
132 %psearch -i a* function
132 %psearch -i a* function
133 -i a* function?
133 -i a* function?
134 ?-i a* function
134 ?-i a* function
135
135
136 Arguments:
136 Arguments:
137
137
138 PATTERN
138 PATTERN
139
139
140 where PATTERN is a string containing * as a wildcard similar to its
140 where PATTERN is a string containing * as a wildcard similar to its
141 use in a shell. The pattern is matched in all namespaces on the
141 use in a shell. The pattern is matched in all namespaces on the
142 search path. By default objects starting with a single _ are not
142 search path. By default objects starting with a single _ are not
143 matched, many IPython generated objects have a single
143 matched, many IPython generated objects have a single
144 underscore. The default is case insensitive matching. Matching is
144 underscore. The default is case insensitive matching. Matching is
145 also done on the attributes of objects and not only on the objects
145 also done on the attributes of objects and not only on the objects
146 in a module.
146 in a module.
147
147
148 [OBJECT TYPE]
148 [OBJECT TYPE]
149
149
150 Is the name of a python type from the types module. The name is
150 Is the name of a python type from the types module. The name is
151 given in lowercase without the ending type, ex. StringType is
151 given in lowercase without the ending type, ex. StringType is
152 written string. By adding a type here only objects matching the
152 written string. By adding a type here only objects matching the
153 given type are matched. Using all here makes the pattern match all
153 given type are matched. Using all here makes the pattern match all
154 types (this is the default).
154 types (this is the default).
155
155
156 Options:
156 Options:
157
157
158 -a: makes the pattern match even objects whose names start with a
158 -a: makes the pattern match even objects whose names start with a
159 single underscore. These names are normally omitted from the
159 single underscore. These names are normally omitted from the
160 search.
160 search.
161
161
162 -i/-c: make the pattern case insensitive/sensitive. If neither of
162 -i/-c: make the pattern case insensitive/sensitive. If neither of
163 these options are given, the default is read from your configuration
163 these options are given, the default is read from your configuration
164 file, with the option ``InteractiveShell.wildcards_case_sensitive``.
164 file, with the option ``InteractiveShell.wildcards_case_sensitive``.
165 If this option is not specified in your configuration file, IPython's
165 If this option is not specified in your configuration file, IPython's
166 internal default is to do a case sensitive search.
166 internal default is to do a case sensitive search.
167
167
168 -e/-s NAMESPACE: exclude/search a given namespace. The pattern you
168 -e/-s NAMESPACE: exclude/search a given namespace. The pattern you
169 specify can be searched in any of the following namespaces:
169 specify can be searched in any of the following namespaces:
170 'builtin', 'user', 'user_global','internal', 'alias', where
170 'builtin', 'user', 'user_global','internal', 'alias', where
171 'builtin' and 'user' are the search defaults. Note that you should
171 'builtin' and 'user' are the search defaults. Note that you should
172 not use quotes when specifying namespaces.
172 not use quotes when specifying namespaces.
173
173
174 'Builtin' contains the python module builtin, 'user' contains all
174 'Builtin' contains the python module builtin, 'user' contains all
175 user data, 'alias' only contain the shell aliases and no python
175 user data, 'alias' only contain the shell aliases and no python
176 objects, 'internal' contains objects used by IPython. The
176 objects, 'internal' contains objects used by IPython. The
177 'user_global' namespace is only used by embedded IPython instances,
177 'user_global' namespace is only used by embedded IPython instances,
178 and it contains module-level globals. You can add namespaces to the
178 and it contains module-level globals. You can add namespaces to the
179 search with -s or exclude them with -e (these options can be given
179 search with -s or exclude them with -e (these options can be given
180 more than once).
180 more than once).
181
181
182 Examples
182 Examples
183 --------
183 --------
184 ::
184 ::
185
185
186 %psearch a* -> objects beginning with an a
186 %psearch a* -> objects beginning with an a
187 %psearch -e builtin a* -> objects NOT in the builtin space starting in a
187 %psearch -e builtin a* -> objects NOT in the builtin space starting in a
188 %psearch a* function -> all functions beginning with an a
188 %psearch a* function -> all functions beginning with an a
189 %psearch re.e* -> objects beginning with an e in module re
189 %psearch re.e* -> objects beginning with an e in module re
190 %psearch r*.e* -> objects that start with e in modules starting in r
190 %psearch r*.e* -> objects that start with e in modules starting in r
191 %psearch r*.* string -> all strings in modules beginning with r
191 %psearch r*.* string -> all strings in modules beginning with r
192
192
193 Case sensitive search::
193 Case sensitive search::
194
194
195 %psearch -c a* list all object beginning with lower case a
195 %psearch -c a* list all object beginning with lower case a
196
196
197 Show objects beginning with a single _::
197 Show objects beginning with a single _::
198
198
199 %psearch -a _* list objects beginning with a single underscore
199 %psearch -a _* list objects beginning with a single underscore
200 """
200 """
201 try:
201 try:
202 parameter_s.encode('ascii')
202 parameter_s.encode('ascii')
203 except UnicodeEncodeError:
203 except UnicodeEncodeError:
204 print 'Python identifiers can only contain ascii characters.'
204 print 'Python identifiers can only contain ascii characters.'
205 return
205 return
206
206
207 # default namespaces to be searched
207 # default namespaces to be searched
208 def_search = ['user_local', 'user_global', 'builtin']
208 def_search = ['user_local', 'user_global', 'builtin']
209
209
210 # Process options/args
210 # Process options/args
211 opts,args = self.parse_options(parameter_s,'cias:e:',list_all=True)
211 opts,args = self.parse_options(parameter_s,'cias:e:',list_all=True)
212 opt = opts.get
212 opt = opts.get
213 shell = self.shell
213 shell = self.shell
214 psearch = shell.inspector.psearch
214 psearch = shell.inspector.psearch
215
215
216 # select case options
216 # select case options
217 if opts.has_key('i'):
217 if 'i' in opts:
218 ignore_case = True
218 ignore_case = True
219 elif opts.has_key('c'):
219 elif 'c' in opts:
220 ignore_case = False
220 ignore_case = False
221 else:
221 else:
222 ignore_case = not shell.wildcards_case_sensitive
222 ignore_case = not shell.wildcards_case_sensitive
223
223
224 # Build list of namespaces to search from user options
224 # Build list of namespaces to search from user options
225 def_search.extend(opt('s',[]))
225 def_search.extend(opt('s',[]))
226 ns_exclude = ns_exclude=opt('e',[])
226 ns_exclude = ns_exclude=opt('e',[])
227 ns_search = [nm for nm in def_search if nm not in ns_exclude]
227 ns_search = [nm for nm in def_search if nm not in ns_exclude]
228
228
229 # Call the actual search
229 # Call the actual search
230 try:
230 try:
231 psearch(args,shell.ns_table,ns_search,
231 psearch(args,shell.ns_table,ns_search,
232 show_all=opt('a'),ignore_case=ignore_case)
232 show_all=opt('a'),ignore_case=ignore_case)
233 except:
233 except:
234 shell.showtraceback()
234 shell.showtraceback()
235
235
236 @skip_doctest
236 @skip_doctest
237 @line_magic
237 @line_magic
238 def who_ls(self, parameter_s=''):
238 def who_ls(self, parameter_s=''):
239 """Return a sorted list of all interactive variables.
239 """Return a sorted list of all interactive variables.
240
240
241 If arguments are given, only variables of types matching these
241 If arguments are given, only variables of types matching these
242 arguments are returned.
242 arguments are returned.
243
243
244 Examples
244 Examples
245 --------
245 --------
246
246
247 Define two variables and list them with who_ls::
247 Define two variables and list them with who_ls::
248
248
249 In [1]: alpha = 123
249 In [1]: alpha = 123
250
250
251 In [2]: beta = 'test'
251 In [2]: beta = 'test'
252
252
253 In [3]: %who_ls
253 In [3]: %who_ls
254 Out[3]: ['alpha', 'beta']
254 Out[3]: ['alpha', 'beta']
255
255
256 In [4]: %who_ls int
256 In [4]: %who_ls int
257 Out[4]: ['alpha']
257 Out[4]: ['alpha']
258
258
259 In [5]: %who_ls str
259 In [5]: %who_ls str
260 Out[5]: ['beta']
260 Out[5]: ['beta']
261 """
261 """
262
262
263 user_ns = self.shell.user_ns
263 user_ns = self.shell.user_ns
264 user_ns_hidden = self.shell.user_ns_hidden
264 user_ns_hidden = self.shell.user_ns_hidden
265 out = [ i for i in user_ns
265 out = [ i for i in user_ns
266 if not i.startswith('_') \
266 if not i.startswith('_') \
267 and not i in user_ns_hidden ]
267 and not i in user_ns_hidden ]
268
268
269 typelist = parameter_s.split()
269 typelist = parameter_s.split()
270 if typelist:
270 if typelist:
271 typeset = set(typelist)
271 typeset = set(typelist)
272 out = [i for i in out if type(user_ns[i]).__name__ in typeset]
272 out = [i for i in out if type(user_ns[i]).__name__ in typeset]
273
273
274 out.sort()
274 out.sort()
275 return out
275 return out
276
276
277 @skip_doctest
277 @skip_doctest
278 @line_magic
278 @line_magic
279 def who(self, parameter_s=''):
279 def who(self, parameter_s=''):
280 """Print all interactive variables, with some minimal formatting.
280 """Print all interactive variables, with some minimal formatting.
281
281
282 If any arguments are given, only variables whose type matches one of
282 If any arguments are given, only variables whose type matches one of
283 these are printed. For example::
283 these are printed. For example::
284
284
285 %who function str
285 %who function str
286
286
287 will only list functions and strings, excluding all other types of
287 will only list functions and strings, excluding all other types of
288 variables. To find the proper type names, simply use type(var) at a
288 variables. To find the proper type names, simply use type(var) at a
289 command line to see how python prints type names. For example:
289 command line to see how python prints type names. For example:
290
290
291 ::
291 ::
292
292
293 In [1]: type('hello')\\
293 In [1]: type('hello')\\
294 Out[1]: <type 'str'>
294 Out[1]: <type 'str'>
295
295
296 indicates that the type name for strings is 'str'.
296 indicates that the type name for strings is 'str'.
297
297
298 ``%who`` always excludes executed names loaded through your configuration
298 ``%who`` always excludes executed names loaded through your configuration
299 file and things which are internal to IPython.
299 file and things which are internal to IPython.
300
300
301 This is deliberate, as typically you may load many modules and the
301 This is deliberate, as typically you may load many modules and the
302 purpose of %who is to show you only what you've manually defined.
302 purpose of %who is to show you only what you've manually defined.
303
303
304 Examples
304 Examples
305 --------
305 --------
306
306
307 Define two variables and list them with who::
307 Define two variables and list them with who::
308
308
309 In [1]: alpha = 123
309 In [1]: alpha = 123
310
310
311 In [2]: beta = 'test'
311 In [2]: beta = 'test'
312
312
313 In [3]: %who
313 In [3]: %who
314 alpha beta
314 alpha beta
315
315
316 In [4]: %who int
316 In [4]: %who int
317 alpha
317 alpha
318
318
319 In [5]: %who str
319 In [5]: %who str
320 beta
320 beta
321 """
321 """
322
322
323 varlist = self.who_ls(parameter_s)
323 varlist = self.who_ls(parameter_s)
324 if not varlist:
324 if not varlist:
325 if parameter_s:
325 if parameter_s:
326 print 'No variables match your requested type.'
326 print 'No variables match your requested type.'
327 else:
327 else:
328 print 'Interactive namespace is empty.'
328 print 'Interactive namespace is empty.'
329 return
329 return
330
330
331 # if we have variables, move on...
331 # if we have variables, move on...
332 count = 0
332 count = 0
333 for i in varlist:
333 for i in varlist:
334 print i+'\t',
334 print i+'\t',
335 count += 1
335 count += 1
336 if count > 8:
336 if count > 8:
337 count = 0
337 count = 0
338 print
338 print
339 print
339 print
340
340
341 @skip_doctest
341 @skip_doctest
342 @line_magic
342 @line_magic
343 def whos(self, parameter_s=''):
343 def whos(self, parameter_s=''):
344 """Like %who, but gives some extra information about each variable.
344 """Like %who, but gives some extra information about each variable.
345
345
346 The same type filtering of %who can be applied here.
346 The same type filtering of %who can be applied here.
347
347
348 For all variables, the type is printed. Additionally it prints:
348 For all variables, the type is printed. Additionally it prints:
349
349
350 - For {},[],(): their length.
350 - For {},[],(): their length.
351
351
352 - For numpy arrays, a summary with shape, number of
352 - For numpy arrays, a summary with shape, number of
353 elements, typecode and size in memory.
353 elements, typecode and size in memory.
354
354
355 - Everything else: a string representation, snipping their middle if
355 - Everything else: a string representation, snipping their middle if
356 too long.
356 too long.
357
357
358 Examples
358 Examples
359 --------
359 --------
360
360
361 Define two variables and list them with whos::
361 Define two variables and list them with whos::
362
362
363 In [1]: alpha = 123
363 In [1]: alpha = 123
364
364
365 In [2]: beta = 'test'
365 In [2]: beta = 'test'
366
366
367 In [3]: %whos
367 In [3]: %whos
368 Variable Type Data/Info
368 Variable Type Data/Info
369 --------------------------------
369 --------------------------------
370 alpha int 123
370 alpha int 123
371 beta str test
371 beta str test
372 """
372 """
373
373
374 varnames = self.who_ls(parameter_s)
374 varnames = self.who_ls(parameter_s)
375 if not varnames:
375 if not varnames:
376 if parameter_s:
376 if parameter_s:
377 print 'No variables match your requested type.'
377 print 'No variables match your requested type.'
378 else:
378 else:
379 print 'Interactive namespace is empty.'
379 print 'Interactive namespace is empty.'
380 return
380 return
381
381
382 # if we have variables, move on...
382 # if we have variables, move on...
383
383
384 # for these types, show len() instead of data:
384 # for these types, show len() instead of data:
385 seq_types = ['dict', 'list', 'tuple']
385 seq_types = ['dict', 'list', 'tuple']
386
386
387 # for numpy arrays, display summary info
387 # for numpy arrays, display summary info
388 ndarray_type = None
388 ndarray_type = None
389 if 'numpy' in sys.modules:
389 if 'numpy' in sys.modules:
390 try:
390 try:
391 from numpy import ndarray
391 from numpy import ndarray
392 except ImportError:
392 except ImportError:
393 pass
393 pass
394 else:
394 else:
395 ndarray_type = ndarray.__name__
395 ndarray_type = ndarray.__name__
396
396
397 # Find all variable names and types so we can figure out column sizes
397 # Find all variable names and types so we can figure out column sizes
398 def get_vars(i):
398 def get_vars(i):
399 return self.shell.user_ns[i]
399 return self.shell.user_ns[i]
400
400
401 # some types are well known and can be shorter
401 # some types are well known and can be shorter
402 abbrevs = {'IPython.core.macro.Macro' : 'Macro'}
402 abbrevs = {'IPython.core.macro.Macro' : 'Macro'}
403 def type_name(v):
403 def type_name(v):
404 tn = type(v).__name__
404 tn = type(v).__name__
405 return abbrevs.get(tn,tn)
405 return abbrevs.get(tn,tn)
406
406
407 varlist = map(get_vars,varnames)
407 varlist = map(get_vars,varnames)
408
408
409 typelist = []
409 typelist = []
410 for vv in varlist:
410 for vv in varlist:
411 tt = type_name(vv)
411 tt = type_name(vv)
412
412
413 if tt=='instance':
413 if tt=='instance':
414 typelist.append( abbrevs.get(str(vv.__class__),
414 typelist.append( abbrevs.get(str(vv.__class__),
415 str(vv.__class__)))
415 str(vv.__class__)))
416 else:
416 else:
417 typelist.append(tt)
417 typelist.append(tt)
418
418
419 # column labels and # of spaces as separator
419 # column labels and # of spaces as separator
420 varlabel = 'Variable'
420 varlabel = 'Variable'
421 typelabel = 'Type'
421 typelabel = 'Type'
422 datalabel = 'Data/Info'
422 datalabel = 'Data/Info'
423 colsep = 3
423 colsep = 3
424 # variable format strings
424 # variable format strings
425 vformat = "{0:<{varwidth}}{1:<{typewidth}}"
425 vformat = "{0:<{varwidth}}{1:<{typewidth}}"
426 aformat = "%s: %s elems, type `%s`, %s bytes"
426 aformat = "%s: %s elems, type `%s`, %s bytes"
427 # find the size of the columns to format the output nicely
427 # find the size of the columns to format the output nicely
428 varwidth = max(max(map(len,varnames)), len(varlabel)) + colsep
428 varwidth = max(max(map(len,varnames)), len(varlabel)) + colsep
429 typewidth = max(max(map(len,typelist)), len(typelabel)) + colsep
429 typewidth = max(max(map(len,typelist)), len(typelabel)) + colsep
430 # table header
430 # table header
431 print varlabel.ljust(varwidth) + typelabel.ljust(typewidth) + \
431 print varlabel.ljust(varwidth) + typelabel.ljust(typewidth) + \
432 ' '+datalabel+'\n' + '-'*(varwidth+typewidth+len(datalabel)+1)
432 ' '+datalabel+'\n' + '-'*(varwidth+typewidth+len(datalabel)+1)
433 # and the table itself
433 # and the table itself
434 kb = 1024
434 kb = 1024
435 Mb = 1048576 # kb**2
435 Mb = 1048576 # kb**2
436 for vname,var,vtype in zip(varnames,varlist,typelist):
436 for vname,var,vtype in zip(varnames,varlist,typelist):
437 print vformat.format(vname, vtype, varwidth=varwidth, typewidth=typewidth),
437 print vformat.format(vname, vtype, varwidth=varwidth, typewidth=typewidth),
438 if vtype in seq_types:
438 if vtype in seq_types:
439 print "n="+str(len(var))
439 print "n="+str(len(var))
440 elif vtype == ndarray_type:
440 elif vtype == ndarray_type:
441 vshape = str(var.shape).replace(',','').replace(' ','x')[1:-1]
441 vshape = str(var.shape).replace(',','').replace(' ','x')[1:-1]
442 if vtype==ndarray_type:
442 if vtype==ndarray_type:
443 # numpy
443 # numpy
444 vsize = var.size
444 vsize = var.size
445 vbytes = vsize*var.itemsize
445 vbytes = vsize*var.itemsize
446 vdtype = var.dtype
446 vdtype = var.dtype
447
447
448 if vbytes < 100000:
448 if vbytes < 100000:
449 print aformat % (vshape, vsize, vdtype, vbytes)
449 print aformat % (vshape, vsize, vdtype, vbytes)
450 else:
450 else:
451 print aformat % (vshape, vsize, vdtype, vbytes),
451 print aformat % (vshape, vsize, vdtype, vbytes),
452 if vbytes < Mb:
452 if vbytes < Mb:
453 print '(%s kb)' % (vbytes/kb,)
453 print '(%s kb)' % (vbytes/kb,)
454 else:
454 else:
455 print '(%s Mb)' % (vbytes/Mb,)
455 print '(%s Mb)' % (vbytes/Mb,)
456 else:
456 else:
457 try:
457 try:
458 vstr = str(var)
458 vstr = str(var)
459 except UnicodeEncodeError:
459 except UnicodeEncodeError:
460 vstr = unicode(var).encode(DEFAULT_ENCODING,
460 vstr = unicode(var).encode(DEFAULT_ENCODING,
461 'backslashreplace')
461 'backslashreplace')
462 except:
462 except:
463 vstr = "<object with id %d (str() failed)>" % id(var)
463 vstr = "<object with id %d (str() failed)>" % id(var)
464 vstr = vstr.replace('\n', '\\n')
464 vstr = vstr.replace('\n', '\\n')
465 if len(vstr) < 50:
465 if len(vstr) < 50:
466 print vstr
466 print vstr
467 else:
467 else:
468 print vstr[:25] + "<...>" + vstr[-25:]
468 print vstr[:25] + "<...>" + vstr[-25:]
469
469
470 @line_magic
470 @line_magic
471 def reset(self, parameter_s=''):
471 def reset(self, parameter_s=''):
472 """Resets the namespace by removing all names defined by the user, if
472 """Resets the namespace by removing all names defined by the user, if
473 called without arguments, or by removing some types of objects, such
473 called without arguments, or by removing some types of objects, such
474 as everything currently in IPython's In[] and Out[] containers (see
474 as everything currently in IPython's In[] and Out[] containers (see
475 the parameters for details).
475 the parameters for details).
476
476
477 Parameters
477 Parameters
478 ----------
478 ----------
479 -f : force reset without asking for confirmation.
479 -f : force reset without asking for confirmation.
480
480
481 -s : 'Soft' reset: Only clears your namespace, leaving history intact.
481 -s : 'Soft' reset: Only clears your namespace, leaving history intact.
482 References to objects may be kept. By default (without this option),
482 References to objects may be kept. By default (without this option),
483 we do a 'hard' reset, giving you a new session and removing all
483 we do a 'hard' reset, giving you a new session and removing all
484 references to objects from the current session.
484 references to objects from the current session.
485
485
486 in : reset input history
486 in : reset input history
487
487
488 out : reset output history
488 out : reset output history
489
489
490 dhist : reset directory history
490 dhist : reset directory history
491
491
492 array : reset only variables that are NumPy arrays
492 array : reset only variables that are NumPy arrays
493
493
494 See Also
494 See Also
495 --------
495 --------
496 magic_reset_selective : invoked as ``%reset_selective``
496 magic_reset_selective : invoked as ``%reset_selective``
497
497
498 Examples
498 Examples
499 --------
499 --------
500 ::
500 ::
501
501
502 In [6]: a = 1
502 In [6]: a = 1
503
503
504 In [7]: a
504 In [7]: a
505 Out[7]: 1
505 Out[7]: 1
506
506
507 In [8]: 'a' in _ip.user_ns
507 In [8]: 'a' in _ip.user_ns
508 Out[8]: True
508 Out[8]: True
509
509
510 In [9]: %reset -f
510 In [9]: %reset -f
511
511
512 In [1]: 'a' in _ip.user_ns
512 In [1]: 'a' in _ip.user_ns
513 Out[1]: False
513 Out[1]: False
514
514
515 In [2]: %reset -f in
515 In [2]: %reset -f in
516 Flushing input history
516 Flushing input history
517
517
518 In [3]: %reset -f dhist in
518 In [3]: %reset -f dhist in
519 Flushing directory history
519 Flushing directory history
520 Flushing input history
520 Flushing input history
521
521
522 Notes
522 Notes
523 -----
523 -----
524 Calling this magic from clients that do not implement standard input,
524 Calling this magic from clients that do not implement standard input,
525 such as the ipython notebook interface, will reset the namespace
525 such as the ipython notebook interface, will reset the namespace
526 without confirmation.
526 without confirmation.
527 """
527 """
528 opts, args = self.parse_options(parameter_s,'sf', mode='list')
528 opts, args = self.parse_options(parameter_s,'sf', mode='list')
529 if 'f' in opts:
529 if 'f' in opts:
530 ans = True
530 ans = True
531 else:
531 else:
532 try:
532 try:
533 ans = self.shell.ask_yes_no(
533 ans = self.shell.ask_yes_no(
534 "Once deleted, variables cannot be recovered. Proceed (y/[n])?",
534 "Once deleted, variables cannot be recovered. Proceed (y/[n])?",
535 default='n')
535 default='n')
536 except StdinNotImplementedError:
536 except StdinNotImplementedError:
537 ans = True
537 ans = True
538 if not ans:
538 if not ans:
539 print 'Nothing done.'
539 print 'Nothing done.'
540 return
540 return
541
541
542 if 's' in opts: # Soft reset
542 if 's' in opts: # Soft reset
543 user_ns = self.shell.user_ns
543 user_ns = self.shell.user_ns
544 for i in self.who_ls():
544 for i in self.who_ls():
545 del(user_ns[i])
545 del(user_ns[i])
546 elif len(args) == 0: # Hard reset
546 elif len(args) == 0: # Hard reset
547 self.shell.reset(new_session = False)
547 self.shell.reset(new_session = False)
548
548
549 # reset in/out/dhist/array: previously extensinions/clearcmd.py
549 # reset in/out/dhist/array: previously extensinions/clearcmd.py
550 ip = self.shell
550 ip = self.shell
551 user_ns = self.shell.user_ns # local lookup, heavily used
551 user_ns = self.shell.user_ns # local lookup, heavily used
552
552
553 for target in args:
553 for target in args:
554 target = target.lower() # make matches case insensitive
554 target = target.lower() # make matches case insensitive
555 if target == 'out':
555 if target == 'out':
556 print "Flushing output cache (%d entries)" % len(user_ns['_oh'])
556 print "Flushing output cache (%d entries)" % len(user_ns['_oh'])
557 self.shell.displayhook.flush()
557 self.shell.displayhook.flush()
558
558
559 elif target == 'in':
559 elif target == 'in':
560 print "Flushing input history"
560 print "Flushing input history"
561 pc = self.shell.displayhook.prompt_count + 1
561 pc = self.shell.displayhook.prompt_count + 1
562 for n in range(1, pc):
562 for n in range(1, pc):
563 key = '_i'+repr(n)
563 key = '_i'+repr(n)
564 user_ns.pop(key,None)
564 user_ns.pop(key,None)
565 user_ns.update(dict(_i=u'',_ii=u'',_iii=u''))
565 user_ns.update(dict(_i=u'',_ii=u'',_iii=u''))
566 hm = ip.history_manager
566 hm = ip.history_manager
567 # don't delete these, as %save and %macro depending on the
567 # don't delete these, as %save and %macro depending on the
568 # length of these lists to be preserved
568 # length of these lists to be preserved
569 hm.input_hist_parsed[:] = [''] * pc
569 hm.input_hist_parsed[:] = [''] * pc
570 hm.input_hist_raw[:] = [''] * pc
570 hm.input_hist_raw[:] = [''] * pc
571 # hm has internal machinery for _i,_ii,_iii, clear it out
571 # hm has internal machinery for _i,_ii,_iii, clear it out
572 hm._i = hm._ii = hm._iii = hm._i00 = u''
572 hm._i = hm._ii = hm._iii = hm._i00 = u''
573
573
574 elif target == 'array':
574 elif target == 'array':
575 # Support cleaning up numpy arrays
575 # Support cleaning up numpy arrays
576 try:
576 try:
577 from numpy import ndarray
577 from numpy import ndarray
578 # This must be done with items and not iteritems because
578 # This must be done with items and not iteritems because
579 # we're going to modify the dict in-place.
579 # we're going to modify the dict in-place.
580 for x,val in user_ns.items():
580 for x,val in user_ns.items():
581 if isinstance(val,ndarray):
581 if isinstance(val,ndarray):
582 del user_ns[x]
582 del user_ns[x]
583 except ImportError:
583 except ImportError:
584 print "reset array only works if Numpy is available."
584 print "reset array only works if Numpy is available."
585
585
586 elif target == 'dhist':
586 elif target == 'dhist':
587 print "Flushing directory history"
587 print "Flushing directory history"
588 del user_ns['_dh'][:]
588 del user_ns['_dh'][:]
589
589
590 else:
590 else:
591 print "Don't know how to reset ",
591 print "Don't know how to reset ",
592 print target + ", please run `%reset?` for details"
592 print target + ", please run `%reset?` for details"
593
593
594 gc.collect()
594 gc.collect()
595
595
596 @line_magic
596 @line_magic
597 def reset_selective(self, parameter_s=''):
597 def reset_selective(self, parameter_s=''):
598 """Resets the namespace by removing names defined by the user.
598 """Resets the namespace by removing names defined by the user.
599
599
600 Input/Output history are left around in case you need them.
600 Input/Output history are left around in case you need them.
601
601
602 %reset_selective [-f] regex
602 %reset_selective [-f] regex
603
603
604 No action is taken if regex is not included
604 No action is taken if regex is not included
605
605
606 Options
606 Options
607 -f : force reset without asking for confirmation.
607 -f : force reset without asking for confirmation.
608
608
609 See Also
609 See Also
610 --------
610 --------
611 magic_reset : invoked as ``%reset``
611 magic_reset : invoked as ``%reset``
612
612
613 Examples
613 Examples
614 --------
614 --------
615
615
616 We first fully reset the namespace so your output looks identical to
616 We first fully reset the namespace so your output looks identical to
617 this example for pedagogical reasons; in practice you do not need a
617 this example for pedagogical reasons; in practice you do not need a
618 full reset::
618 full reset::
619
619
620 In [1]: %reset -f
620 In [1]: %reset -f
621
621
622 Now, with a clean namespace we can make a few variables and use
622 Now, with a clean namespace we can make a few variables and use
623 ``%reset_selective`` to only delete names that match our regexp::
623 ``%reset_selective`` to only delete names that match our regexp::
624
624
625 In [2]: a=1; b=2; c=3; b1m=4; b2m=5; b3m=6; b4m=7; b2s=8
625 In [2]: a=1; b=2; c=3; b1m=4; b2m=5; b3m=6; b4m=7; b2s=8
626
626
627 In [3]: who_ls
627 In [3]: who_ls
628 Out[3]: ['a', 'b', 'b1m', 'b2m', 'b2s', 'b3m', 'b4m', 'c']
628 Out[3]: ['a', 'b', 'b1m', 'b2m', 'b2s', 'b3m', 'b4m', 'c']
629
629
630 In [4]: %reset_selective -f b[2-3]m
630 In [4]: %reset_selective -f b[2-3]m
631
631
632 In [5]: who_ls
632 In [5]: who_ls
633 Out[5]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
633 Out[5]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
634
634
635 In [6]: %reset_selective -f d
635 In [6]: %reset_selective -f d
636
636
637 In [7]: who_ls
637 In [7]: who_ls
638 Out[7]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
638 Out[7]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
639
639
640 In [8]: %reset_selective -f c
640 In [8]: %reset_selective -f c
641
641
642 In [9]: who_ls
642 In [9]: who_ls
643 Out[9]: ['a', 'b', 'b1m', 'b2s', 'b4m']
643 Out[9]: ['a', 'b', 'b1m', 'b2s', 'b4m']
644
644
645 In [10]: %reset_selective -f b
645 In [10]: %reset_selective -f b
646
646
647 In [11]: who_ls
647 In [11]: who_ls
648 Out[11]: ['a']
648 Out[11]: ['a']
649
649
650 Notes
650 Notes
651 -----
651 -----
652 Calling this magic from clients that do not implement standard input,
652 Calling this magic from clients that do not implement standard input,
653 such as the ipython notebook interface, will reset the namespace
653 such as the ipython notebook interface, will reset the namespace
654 without confirmation.
654 without confirmation.
655 """
655 """
656
656
657 opts, regex = self.parse_options(parameter_s,'f')
657 opts, regex = self.parse_options(parameter_s,'f')
658
658
659 if opts.has_key('f'):
659 if 'f' in opts:
660 ans = True
660 ans = True
661 else:
661 else:
662 try:
662 try:
663 ans = self.shell.ask_yes_no(
663 ans = self.shell.ask_yes_no(
664 "Once deleted, variables cannot be recovered. Proceed (y/[n])? ",
664 "Once deleted, variables cannot be recovered. Proceed (y/[n])? ",
665 default='n')
665 default='n')
666 except StdinNotImplementedError:
666 except StdinNotImplementedError:
667 ans = True
667 ans = True
668 if not ans:
668 if not ans:
669 print 'Nothing done.'
669 print 'Nothing done.'
670 return
670 return
671 user_ns = self.shell.user_ns
671 user_ns = self.shell.user_ns
672 if not regex:
672 if not regex:
673 print 'No regex pattern specified. Nothing done.'
673 print 'No regex pattern specified. Nothing done.'
674 return
674 return
675 else:
675 else:
676 try:
676 try:
677 m = re.compile(regex)
677 m = re.compile(regex)
678 except TypeError:
678 except TypeError:
679 raise TypeError('regex must be a string or compiled pattern')
679 raise TypeError('regex must be a string or compiled pattern')
680 for i in self.who_ls():
680 for i in self.who_ls():
681 if m.search(i):
681 if m.search(i):
682 del(user_ns[i])
682 del(user_ns[i])
683
683
684 @line_magic
684 @line_magic
685 def xdel(self, parameter_s=''):
685 def xdel(self, parameter_s=''):
686 """Delete a variable, trying to clear it from anywhere that
686 """Delete a variable, trying to clear it from anywhere that
687 IPython's machinery has references to it. By default, this uses
687 IPython's machinery has references to it. By default, this uses
688 the identity of the named object in the user namespace to remove
688 the identity of the named object in the user namespace to remove
689 references held under other names. The object is also removed
689 references held under other names. The object is also removed
690 from the output history.
690 from the output history.
691
691
692 Options
692 Options
693 -n : Delete the specified name from all namespaces, without
693 -n : Delete the specified name from all namespaces, without
694 checking their identity.
694 checking their identity.
695 """
695 """
696 opts, varname = self.parse_options(parameter_s,'n')
696 opts, varname = self.parse_options(parameter_s,'n')
697 try:
697 try:
698 self.shell.del_var(varname, ('n' in opts))
698 self.shell.del_var(varname, ('n' in opts))
699 except (NameError, ValueError) as e:
699 except (NameError, ValueError) as e:
700 print type(e).__name__ +": "+ str(e)
700 print type(e).__name__ +": "+ str(e)
@@ -1,51 +1,51 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """IPython plugins.
2 """IPython plugins.
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010-2011 The IPython Development Team
10 # Copyright (C) 2010-2011 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 from IPython.config.configurable import Configurable
20 from IPython.config.configurable import Configurable
21 from IPython.utils.traitlets import Dict
21 from IPython.utils.traitlets import Dict
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Main class
24 # Main class
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 class PluginManager(Configurable):
27 class PluginManager(Configurable):
28 """A manager for IPython plugins."""
28 """A manager for IPython plugins."""
29
29
30 plugins = Dict({})
30 plugins = Dict({})
31
31
32 def __init__(self, config=None):
32 def __init__(self, config=None):
33 super(PluginManager, self).__init__(config=config)
33 super(PluginManager, self).__init__(config=config)
34
34
35 def register_plugin(self, name, plugin):
35 def register_plugin(self, name, plugin):
36 if not isinstance(plugin, Plugin):
36 if not isinstance(plugin, Plugin):
37 raise TypeError('Expected Plugin, got: %r' % plugin)
37 raise TypeError('Expected Plugin, got: %r' % plugin)
38 if self.plugins.has_key(name):
38 if name in self.plugins:
39 raise KeyError('Plugin with name already exists: %r' % name)
39 raise KeyError('Plugin with name already exists: %r' % name)
40 self.plugins[name] = plugin
40 self.plugins[name] = plugin
41
41
42 def unregister_plugin(self, name):
42 def unregister_plugin(self, name):
43 del self.plugins[name]
43 del self.plugins[name]
44
44
45 def get_plugin(self, name, default=None):
45 def get_plugin(self, name, default=None):
46 return self.plugins.get(name, default)
46 return self.plugins.get(name, default)
47
47
48
48
49 class Plugin(Configurable):
49 class Plugin(Configurable):
50 """Base class for IPython plugins."""
50 """Base class for IPython plugins."""
51 pass
51 pass
@@ -1,1244 +1,1244 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 ultratb.py -- Spice up your tracebacks!
3 ultratb.py -- Spice up your tracebacks!
4
4
5 * ColorTB
5 * ColorTB
6 I've always found it a bit hard to visually parse tracebacks in Python. The
6 I've always found it a bit hard to visually parse tracebacks in Python. The
7 ColorTB class is a solution to that problem. It colors the different parts of a
7 ColorTB class is a solution to that problem. It colors the different parts of a
8 traceback in a manner similar to what you would expect from a syntax-highlighting
8 traceback in a manner similar to what you would expect from a syntax-highlighting
9 text editor.
9 text editor.
10
10
11 Installation instructions for ColorTB:
11 Installation instructions for ColorTB:
12 import sys,ultratb
12 import sys,ultratb
13 sys.excepthook = ultratb.ColorTB()
13 sys.excepthook = ultratb.ColorTB()
14
14
15 * VerboseTB
15 * VerboseTB
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
18 and intended it for CGI programmers, but why should they have all the fun? I
18 and intended it for CGI programmers, but why should they have all the fun? I
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
20 but kind of neat, and maybe useful for long-running programs that you believe
20 but kind of neat, and maybe useful for long-running programs that you believe
21 are bug-free. If a crash *does* occur in that type of program you want details.
21 are bug-free. If a crash *does* occur in that type of program you want details.
22 Give it a shot--you'll love it or you'll hate it.
22 Give it a shot--you'll love it or you'll hate it.
23
23
24 Note:
24 Note:
25
25
26 The Verbose mode prints the variables currently visible where the exception
26 The Verbose mode prints the variables currently visible where the exception
27 happened (shortening their strings if too long). This can potentially be
27 happened (shortening their strings if too long). This can potentially be
28 very slow, if you happen to have a huge data structure whose string
28 very slow, if you happen to have a huge data structure whose string
29 representation is complex to compute. Your computer may appear to freeze for
29 representation is complex to compute. Your computer may appear to freeze for
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
31 with Ctrl-C (maybe hitting it more than once).
31 with Ctrl-C (maybe hitting it more than once).
32
32
33 If you encounter this kind of situation often, you may want to use the
33 If you encounter this kind of situation often, you may want to use the
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
35 variables (but otherwise includes the information and context given by
35 variables (but otherwise includes the information and context given by
36 Verbose).
36 Verbose).
37
37
38
38
39 Installation instructions for ColorTB:
39 Installation instructions for ColorTB:
40 import sys,ultratb
40 import sys,ultratb
41 sys.excepthook = ultratb.VerboseTB()
41 sys.excepthook = ultratb.VerboseTB()
42
42
43 Note: Much of the code in this module was lifted verbatim from the standard
43 Note: Much of the code in this module was lifted verbatim from the standard
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
45
45
46 * Color schemes
46 * Color schemes
47 The colors are defined in the class TBTools through the use of the
47 The colors are defined in the class TBTools through the use of the
48 ColorSchemeTable class. Currently the following exist:
48 ColorSchemeTable class. Currently the following exist:
49
49
50 - NoColor: allows all of this module to be used in any terminal (the color
50 - NoColor: allows all of this module to be used in any terminal (the color
51 escapes are just dummy blank strings).
51 escapes are just dummy blank strings).
52
52
53 - Linux: is meant to look good in a terminal like the Linux console (black
53 - Linux: is meant to look good in a terminal like the Linux console (black
54 or very dark background).
54 or very dark background).
55
55
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
57 in light background terminals.
57 in light background terminals.
58
58
59 You can implement other color schemes easily, the syntax is fairly
59 You can implement other color schemes easily, the syntax is fairly
60 self-explanatory. Please send back new schemes you develop to the author for
60 self-explanatory. Please send back new schemes you develop to the author for
61 possible inclusion in future releases.
61 possible inclusion in future releases.
62 """
62 """
63
63
64 #*****************************************************************************
64 #*****************************************************************************
65 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
65 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
66 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
66 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
67 #
67 #
68 # Distributed under the terms of the BSD License. The full license is in
68 # Distributed under the terms of the BSD License. The full license is in
69 # the file COPYING, distributed as part of this software.
69 # the file COPYING, distributed as part of this software.
70 #*****************************************************************************
70 #*****************************************************************************
71
71
72 from __future__ import with_statement
72 from __future__ import with_statement
73
73
74 import inspect
74 import inspect
75 import keyword
75 import keyword
76 import linecache
76 import linecache
77 import os
77 import os
78 import pydoc
78 import pydoc
79 import re
79 import re
80 import sys
80 import sys
81 import time
81 import time
82 import tokenize
82 import tokenize
83 import traceback
83 import traceback
84 import types
84 import types
85
85
86 try: # Python 2
86 try: # Python 2
87 generate_tokens = tokenize.generate_tokens
87 generate_tokens = tokenize.generate_tokens
88 except AttributeError: # Python 3
88 except AttributeError: # Python 3
89 generate_tokens = tokenize.tokenize
89 generate_tokens = tokenize.tokenize
90
90
91 # For purposes of monkeypatching inspect to fix a bug in it.
91 # For purposes of monkeypatching inspect to fix a bug in it.
92 from inspect import getsourcefile, getfile, getmodule,\
92 from inspect import getsourcefile, getfile, getmodule,\
93 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
93 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
94
94
95 # IPython's own modules
95 # IPython's own modules
96 # Modified pdb which doesn't damage IPython's readline handling
96 # Modified pdb which doesn't damage IPython's readline handling
97 from IPython.core import debugger, ipapi
97 from IPython.core import debugger, ipapi
98 from IPython.core.display_trap import DisplayTrap
98 from IPython.core.display_trap import DisplayTrap
99 from IPython.core.excolors import exception_colors
99 from IPython.core.excolors import exception_colors
100 from IPython.utils import PyColorize
100 from IPython.utils import PyColorize
101 from IPython.utils import io
101 from IPython.utils import io
102 from IPython.utils import py3compat
102 from IPython.utils import py3compat
103 from IPython.utils import pyfile
103 from IPython.utils import pyfile
104 from IPython.utils.data import uniq_stable
104 from IPython.utils.data import uniq_stable
105 from IPython.utils.warn import info, error
105 from IPython.utils.warn import info, error
106
106
107 # Globals
107 # Globals
108 # amount of space to put line numbers before verbose tracebacks
108 # amount of space to put line numbers before verbose tracebacks
109 INDENT_SIZE = 8
109 INDENT_SIZE = 8
110
110
111 # Default color scheme. This is used, for example, by the traceback
111 # Default color scheme. This is used, for example, by the traceback
112 # formatter. When running in an actual IPython instance, the user's rc.colors
112 # formatter. When running in an actual IPython instance, the user's rc.colors
113 # value is used, but havinga module global makes this functionality available
113 # value is used, but havinga module global makes this functionality available
114 # to users of ultratb who are NOT running inside ipython.
114 # to users of ultratb who are NOT running inside ipython.
115 DEFAULT_SCHEME = 'NoColor'
115 DEFAULT_SCHEME = 'NoColor'
116
116
117 #---------------------------------------------------------------------------
117 #---------------------------------------------------------------------------
118 # Code begins
118 # Code begins
119
119
120 # Utility functions
120 # Utility functions
121 def inspect_error():
121 def inspect_error():
122 """Print a message about internal inspect errors.
122 """Print a message about internal inspect errors.
123
123
124 These are unfortunately quite common."""
124 These are unfortunately quite common."""
125
125
126 error('Internal Python error in the inspect module.\n'
126 error('Internal Python error in the inspect module.\n'
127 'Below is the traceback from this internal error.\n')
127 'Below is the traceback from this internal error.\n')
128
128
129
129
130 # N.B. This function is a monkeypatch we are currently not applying.
130 # N.B. This function is a monkeypatch we are currently not applying.
131 # It was written some time ago, to fix an apparent Python bug with
131 # It was written some time ago, to fix an apparent Python bug with
132 # codeobj.co_firstlineno . Unfortunately, we don't know under what conditions
132 # codeobj.co_firstlineno . Unfortunately, we don't know under what conditions
133 # the bug occurred, so we can't tell if it has been fixed. If it reappears, we
133 # the bug occurred, so we can't tell if it has been fixed. If it reappears, we
134 # will apply the monkeypatch again. Also, note that findsource() is not called
134 # will apply the monkeypatch again. Also, note that findsource() is not called
135 # by our code at this time - we don't know if it was when the monkeypatch was
135 # by our code at this time - we don't know if it was when the monkeypatch was
136 # written, or if the monkeypatch is needed for some other code (like a debugger).
136 # written, or if the monkeypatch is needed for some other code (like a debugger).
137 # For the discussion about not applying it, see gh-1229. TK, Jan 2011.
137 # For the discussion about not applying it, see gh-1229. TK, Jan 2011.
138 def findsource(object):
138 def findsource(object):
139 """Return the entire source file and starting line number for an object.
139 """Return the entire source file and starting line number for an object.
140
140
141 The argument may be a module, class, method, function, traceback, frame,
141 The argument may be a module, class, method, function, traceback, frame,
142 or code object. The source code is returned as a list of all the lines
142 or code object. The source code is returned as a list of all the lines
143 in the file and the line number indexes a line in that list. An IOError
143 in the file and the line number indexes a line in that list. An IOError
144 is raised if the source code cannot be retrieved.
144 is raised if the source code cannot be retrieved.
145
145
146 FIXED version with which we monkeypatch the stdlib to work around a bug."""
146 FIXED version with which we monkeypatch the stdlib to work around a bug."""
147
147
148 file = getsourcefile(object) or getfile(object)
148 file = getsourcefile(object) or getfile(object)
149 # If the object is a frame, then trying to get the globals dict from its
149 # If the object is a frame, then trying to get the globals dict from its
150 # module won't work. Instead, the frame object itself has the globals
150 # module won't work. Instead, the frame object itself has the globals
151 # dictionary.
151 # dictionary.
152 globals_dict = None
152 globals_dict = None
153 if inspect.isframe(object):
153 if inspect.isframe(object):
154 # XXX: can this ever be false?
154 # XXX: can this ever be false?
155 globals_dict = object.f_globals
155 globals_dict = object.f_globals
156 else:
156 else:
157 module = getmodule(object, file)
157 module = getmodule(object, file)
158 if module:
158 if module:
159 globals_dict = module.__dict__
159 globals_dict = module.__dict__
160 lines = linecache.getlines(file, globals_dict)
160 lines = linecache.getlines(file, globals_dict)
161 if not lines:
161 if not lines:
162 raise IOError('could not get source code')
162 raise IOError('could not get source code')
163
163
164 if ismodule(object):
164 if ismodule(object):
165 return lines, 0
165 return lines, 0
166
166
167 if isclass(object):
167 if isclass(object):
168 name = object.__name__
168 name = object.__name__
169 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
169 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
170 # make some effort to find the best matching class definition:
170 # make some effort to find the best matching class definition:
171 # use the one with the least indentation, which is the one
171 # use the one with the least indentation, which is the one
172 # that's most probably not inside a function definition.
172 # that's most probably not inside a function definition.
173 candidates = []
173 candidates = []
174 for i in range(len(lines)):
174 for i in range(len(lines)):
175 match = pat.match(lines[i])
175 match = pat.match(lines[i])
176 if match:
176 if match:
177 # if it's at toplevel, it's already the best one
177 # if it's at toplevel, it's already the best one
178 if lines[i][0] == 'c':
178 if lines[i][0] == 'c':
179 return lines, i
179 return lines, i
180 # else add whitespace to candidate list
180 # else add whitespace to candidate list
181 candidates.append((match.group(1), i))
181 candidates.append((match.group(1), i))
182 if candidates:
182 if candidates:
183 # this will sort by whitespace, and by line number,
183 # this will sort by whitespace, and by line number,
184 # less whitespace first
184 # less whitespace first
185 candidates.sort()
185 candidates.sort()
186 return lines, candidates[0][1]
186 return lines, candidates[0][1]
187 else:
187 else:
188 raise IOError('could not find class definition')
188 raise IOError('could not find class definition')
189
189
190 if ismethod(object):
190 if ismethod(object):
191 object = object.im_func
191 object = object.im_func
192 if isfunction(object):
192 if isfunction(object):
193 object = object.func_code
193 object = object.func_code
194 if istraceback(object):
194 if istraceback(object):
195 object = object.tb_frame
195 object = object.tb_frame
196 if isframe(object):
196 if isframe(object):
197 object = object.f_code
197 object = object.f_code
198 if iscode(object):
198 if iscode(object):
199 if not hasattr(object, 'co_firstlineno'):
199 if not hasattr(object, 'co_firstlineno'):
200 raise IOError('could not find function definition')
200 raise IOError('could not find function definition')
201 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
201 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
202 pmatch = pat.match
202 pmatch = pat.match
203 # fperez - fix: sometimes, co_firstlineno can give a number larger than
203 # fperez - fix: sometimes, co_firstlineno can give a number larger than
204 # the length of lines, which causes an error. Safeguard against that.
204 # the length of lines, which causes an error. Safeguard against that.
205 lnum = min(object.co_firstlineno,len(lines))-1
205 lnum = min(object.co_firstlineno,len(lines))-1
206 while lnum > 0:
206 while lnum > 0:
207 if pmatch(lines[lnum]): break
207 if pmatch(lines[lnum]): break
208 lnum -= 1
208 lnum -= 1
209
209
210 return lines, lnum
210 return lines, lnum
211 raise IOError('could not find code object')
211 raise IOError('could not find code object')
212
212
213 # Not applying the monkeypatch - see above the function for details. TK, Jan 2012
213 # Not applying the monkeypatch - see above the function for details. TK, Jan 2012
214 # Monkeypatch inspect to apply our bugfix. This code only works with py25
214 # Monkeypatch inspect to apply our bugfix. This code only works with py25
215 #if sys.version_info[:2] >= (2,5):
215 #if sys.version_info[:2] >= (2,5):
216 # inspect.findsource = findsource
216 # inspect.findsource = findsource
217
217
218 def fix_frame_records_filenames(records):
218 def fix_frame_records_filenames(records):
219 """Try to fix the filenames in each record from inspect.getinnerframes().
219 """Try to fix the filenames in each record from inspect.getinnerframes().
220
220
221 Particularly, modules loaded from within zip files have useless filenames
221 Particularly, modules loaded from within zip files have useless filenames
222 attached to their code object, and inspect.getinnerframes() just uses it.
222 attached to their code object, and inspect.getinnerframes() just uses it.
223 """
223 """
224 fixed_records = []
224 fixed_records = []
225 for frame, filename, line_no, func_name, lines, index in records:
225 for frame, filename, line_no, func_name, lines, index in records:
226 # Look inside the frame's globals dictionary for __file__, which should
226 # Look inside the frame's globals dictionary for __file__, which should
227 # be better.
227 # be better.
228 better_fn = frame.f_globals.get('__file__', None)
228 better_fn = frame.f_globals.get('__file__', None)
229 if isinstance(better_fn, str):
229 if isinstance(better_fn, str):
230 # Check the type just in case someone did something weird with
230 # Check the type just in case someone did something weird with
231 # __file__. It might also be None if the error occurred during
231 # __file__. It might also be None if the error occurred during
232 # import.
232 # import.
233 filename = better_fn
233 filename = better_fn
234 fixed_records.append((frame, filename, line_no, func_name, lines, index))
234 fixed_records.append((frame, filename, line_no, func_name, lines, index))
235 return fixed_records
235 return fixed_records
236
236
237
237
238 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
238 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
239 import linecache
239 import linecache
240 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
240 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
241
241
242 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
242 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
243
243
244 # If the error is at the console, don't build any context, since it would
244 # If the error is at the console, don't build any context, since it would
245 # otherwise produce 5 blank lines printed out (there is no file at the
245 # otherwise produce 5 blank lines printed out (there is no file at the
246 # console)
246 # console)
247 rec_check = records[tb_offset:]
247 rec_check = records[tb_offset:]
248 try:
248 try:
249 rname = rec_check[0][1]
249 rname = rec_check[0][1]
250 if rname == '<ipython console>' or rname.endswith('<string>'):
250 if rname == '<ipython console>' or rname.endswith('<string>'):
251 return rec_check
251 return rec_check
252 except IndexError:
252 except IndexError:
253 pass
253 pass
254
254
255 aux = traceback.extract_tb(etb)
255 aux = traceback.extract_tb(etb)
256 assert len(records) == len(aux)
256 assert len(records) == len(aux)
257 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
257 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
258 maybeStart = lnum-1 - context//2
258 maybeStart = lnum-1 - context//2
259 start = max(maybeStart, 0)
259 start = max(maybeStart, 0)
260 end = start + context
260 end = start + context
261 lines = linecache.getlines(file)[start:end]
261 lines = linecache.getlines(file)[start:end]
262 buf = list(records[i])
262 buf = list(records[i])
263 buf[LNUM_POS] = lnum
263 buf[LNUM_POS] = lnum
264 buf[INDEX_POS] = lnum - 1 - start
264 buf[INDEX_POS] = lnum - 1 - start
265 buf[LINES_POS] = lines
265 buf[LINES_POS] = lines
266 records[i] = tuple(buf)
266 records[i] = tuple(buf)
267 return records[tb_offset:]
267 return records[tb_offset:]
268
268
269 # Helper function -- largely belongs to VerboseTB, but we need the same
269 # Helper function -- largely belongs to VerboseTB, but we need the same
270 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
270 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
271 # can be recognized properly by ipython.el's py-traceback-line-re
271 # can be recognized properly by ipython.el's py-traceback-line-re
272 # (SyntaxErrors have to be treated specially because they have no traceback)
272 # (SyntaxErrors have to be treated specially because they have no traceback)
273
273
274 _parser = PyColorize.Parser()
274 _parser = PyColorize.Parser()
275
275
276 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
276 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
277 numbers_width = INDENT_SIZE - 1
277 numbers_width = INDENT_SIZE - 1
278 res = []
278 res = []
279 i = lnum - index
279 i = lnum - index
280
280
281 # This lets us get fully syntax-highlighted tracebacks.
281 # This lets us get fully syntax-highlighted tracebacks.
282 if scheme is None:
282 if scheme is None:
283 ipinst = ipapi.get()
283 ipinst = ipapi.get()
284 if ipinst is not None:
284 if ipinst is not None:
285 scheme = ipinst.colors
285 scheme = ipinst.colors
286 else:
286 else:
287 scheme = DEFAULT_SCHEME
287 scheme = DEFAULT_SCHEME
288
288
289 _line_format = _parser.format2
289 _line_format = _parser.format2
290
290
291 for line in lines:
291 for line in lines:
292 # FIXME: we need to ensure the source is a pure string at this point,
292 # FIXME: we need to ensure the source is a pure string at this point,
293 # else the coloring code makes a royal mess. This is in need of a
293 # else the coloring code makes a royal mess. This is in need of a
294 # serious refactoring, so that all of the ultratb and PyColorize code
294 # serious refactoring, so that all of the ultratb and PyColorize code
295 # is unicode-safe. So for now this is rather an ugly hack, but
295 # is unicode-safe. So for now this is rather an ugly hack, but
296 # necessary to at least have readable tracebacks. Improvements welcome!
296 # necessary to at least have readable tracebacks. Improvements welcome!
297 line = py3compat.cast_bytes_py2(line, 'utf-8')
297 line = py3compat.cast_bytes_py2(line, 'utf-8')
298
298
299 new_line, err = _line_format(line, 'str', scheme)
299 new_line, err = _line_format(line, 'str', scheme)
300 if not err: line = new_line
300 if not err: line = new_line
301
301
302 if i == lnum:
302 if i == lnum:
303 # This is the line with the error
303 # This is the line with the error
304 pad = numbers_width - len(str(i))
304 pad = numbers_width - len(str(i))
305 if pad >= 3:
305 if pad >= 3:
306 marker = '-'*(pad-3) + '-> '
306 marker = '-'*(pad-3) + '-> '
307 elif pad == 2:
307 elif pad == 2:
308 marker = '> '
308 marker = '> '
309 elif pad == 1:
309 elif pad == 1:
310 marker = '>'
310 marker = '>'
311 else:
311 else:
312 marker = ''
312 marker = ''
313 num = marker + str(i)
313 num = marker + str(i)
314 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
314 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
315 Colors.line, line, Colors.Normal)
315 Colors.line, line, Colors.Normal)
316 else:
316 else:
317 num = '%*s' % (numbers_width,i)
317 num = '%*s' % (numbers_width,i)
318 line = '%s%s%s %s' %(Colors.lineno, num,
318 line = '%s%s%s %s' %(Colors.lineno, num,
319 Colors.Normal, line)
319 Colors.Normal, line)
320
320
321 res.append(line)
321 res.append(line)
322 if lvals and i == lnum:
322 if lvals and i == lnum:
323 res.append(lvals + '\n')
323 res.append(lvals + '\n')
324 i = i + 1
324 i = i + 1
325 return res
325 return res
326
326
327
327
328 #---------------------------------------------------------------------------
328 #---------------------------------------------------------------------------
329 # Module classes
329 # Module classes
330 class TBTools(object):
330 class TBTools(object):
331 """Basic tools used by all traceback printer classes."""
331 """Basic tools used by all traceback printer classes."""
332
332
333 # Number of frames to skip when reporting tracebacks
333 # Number of frames to skip when reporting tracebacks
334 tb_offset = 0
334 tb_offset = 0
335
335
336 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
336 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
337 # Whether to call the interactive pdb debugger after printing
337 # Whether to call the interactive pdb debugger after printing
338 # tracebacks or not
338 # tracebacks or not
339 self.call_pdb = call_pdb
339 self.call_pdb = call_pdb
340
340
341 # Output stream to write to. Note that we store the original value in
341 # Output stream to write to. Note that we store the original value in
342 # a private attribute and then make the public ostream a property, so
342 # a private attribute and then make the public ostream a property, so
343 # that we can delay accessing io.stdout until runtime. The way
343 # that we can delay accessing io.stdout until runtime. The way
344 # things are written now, the io.stdout object is dynamically managed
344 # things are written now, the io.stdout object is dynamically managed
345 # so a reference to it should NEVER be stored statically. This
345 # so a reference to it should NEVER be stored statically. This
346 # property approach confines this detail to a single location, and all
346 # property approach confines this detail to a single location, and all
347 # subclasses can simply access self.ostream for writing.
347 # subclasses can simply access self.ostream for writing.
348 self._ostream = ostream
348 self._ostream = ostream
349
349
350 # Create color table
350 # Create color table
351 self.color_scheme_table = exception_colors()
351 self.color_scheme_table = exception_colors()
352
352
353 self.set_colors(color_scheme)
353 self.set_colors(color_scheme)
354 self.old_scheme = color_scheme # save initial value for toggles
354 self.old_scheme = color_scheme # save initial value for toggles
355
355
356 if call_pdb:
356 if call_pdb:
357 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
357 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
358 else:
358 else:
359 self.pdb = None
359 self.pdb = None
360
360
361 def _get_ostream(self):
361 def _get_ostream(self):
362 """Output stream that exceptions are written to.
362 """Output stream that exceptions are written to.
363
363
364 Valid values are:
364 Valid values are:
365
365
366 - None: the default, which means that IPython will dynamically resolve
366 - None: the default, which means that IPython will dynamically resolve
367 to io.stdout. This ensures compatibility with most tools, including
367 to io.stdout. This ensures compatibility with most tools, including
368 Windows (where plain stdout doesn't recognize ANSI escapes).
368 Windows (where plain stdout doesn't recognize ANSI escapes).
369
369
370 - Any object with 'write' and 'flush' attributes.
370 - Any object with 'write' and 'flush' attributes.
371 """
371 """
372 return io.stdout if self._ostream is None else self._ostream
372 return io.stdout if self._ostream is None else self._ostream
373
373
374 def _set_ostream(self, val):
374 def _set_ostream(self, val):
375 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
375 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
376 self._ostream = val
376 self._ostream = val
377
377
378 ostream = property(_get_ostream, _set_ostream)
378 ostream = property(_get_ostream, _set_ostream)
379
379
380 def set_colors(self,*args,**kw):
380 def set_colors(self,*args,**kw):
381 """Shorthand access to the color table scheme selector method."""
381 """Shorthand access to the color table scheme selector method."""
382
382
383 # Set own color table
383 # Set own color table
384 self.color_scheme_table.set_active_scheme(*args,**kw)
384 self.color_scheme_table.set_active_scheme(*args,**kw)
385 # for convenience, set Colors to the active scheme
385 # for convenience, set Colors to the active scheme
386 self.Colors = self.color_scheme_table.active_colors
386 self.Colors = self.color_scheme_table.active_colors
387 # Also set colors of debugger
387 # Also set colors of debugger
388 if hasattr(self,'pdb') and self.pdb is not None:
388 if hasattr(self,'pdb') and self.pdb is not None:
389 self.pdb.set_colors(*args,**kw)
389 self.pdb.set_colors(*args,**kw)
390
390
391 def color_toggle(self):
391 def color_toggle(self):
392 """Toggle between the currently active color scheme and NoColor."""
392 """Toggle between the currently active color scheme and NoColor."""
393
393
394 if self.color_scheme_table.active_scheme_name == 'NoColor':
394 if self.color_scheme_table.active_scheme_name == 'NoColor':
395 self.color_scheme_table.set_active_scheme(self.old_scheme)
395 self.color_scheme_table.set_active_scheme(self.old_scheme)
396 self.Colors = self.color_scheme_table.active_colors
396 self.Colors = self.color_scheme_table.active_colors
397 else:
397 else:
398 self.old_scheme = self.color_scheme_table.active_scheme_name
398 self.old_scheme = self.color_scheme_table.active_scheme_name
399 self.color_scheme_table.set_active_scheme('NoColor')
399 self.color_scheme_table.set_active_scheme('NoColor')
400 self.Colors = self.color_scheme_table.active_colors
400 self.Colors = self.color_scheme_table.active_colors
401
401
402 def stb2text(self, stb):
402 def stb2text(self, stb):
403 """Convert a structured traceback (a list) to a string."""
403 """Convert a structured traceback (a list) to a string."""
404 return '\n'.join(stb)
404 return '\n'.join(stb)
405
405
406 def text(self, etype, value, tb, tb_offset=None, context=5):
406 def text(self, etype, value, tb, tb_offset=None, context=5):
407 """Return formatted traceback.
407 """Return formatted traceback.
408
408
409 Subclasses may override this if they add extra arguments.
409 Subclasses may override this if they add extra arguments.
410 """
410 """
411 tb_list = self.structured_traceback(etype, value, tb,
411 tb_list = self.structured_traceback(etype, value, tb,
412 tb_offset, context)
412 tb_offset, context)
413 return self.stb2text(tb_list)
413 return self.stb2text(tb_list)
414
414
415 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
415 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
416 context=5, mode=None):
416 context=5, mode=None):
417 """Return a list of traceback frames.
417 """Return a list of traceback frames.
418
418
419 Must be implemented by each class.
419 Must be implemented by each class.
420 """
420 """
421 raise NotImplementedError()
421 raise NotImplementedError()
422
422
423
423
424 #---------------------------------------------------------------------------
424 #---------------------------------------------------------------------------
425 class ListTB(TBTools):
425 class ListTB(TBTools):
426 """Print traceback information from a traceback list, with optional color.
426 """Print traceback information from a traceback list, with optional color.
427
427
428 Calling: requires 3 arguments:
428 Calling: requires 3 arguments:
429 (etype, evalue, elist)
429 (etype, evalue, elist)
430 as would be obtained by:
430 as would be obtained by:
431 etype, evalue, tb = sys.exc_info()
431 etype, evalue, tb = sys.exc_info()
432 if tb:
432 if tb:
433 elist = traceback.extract_tb(tb)
433 elist = traceback.extract_tb(tb)
434 else:
434 else:
435 elist = None
435 elist = None
436
436
437 It can thus be used by programs which need to process the traceback before
437 It can thus be used by programs which need to process the traceback before
438 printing (such as console replacements based on the code module from the
438 printing (such as console replacements based on the code module from the
439 standard library).
439 standard library).
440
440
441 Because they are meant to be called without a full traceback (only a
441 Because they are meant to be called without a full traceback (only a
442 list), instances of this class can't call the interactive pdb debugger."""
442 list), instances of this class can't call the interactive pdb debugger."""
443
443
444 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
444 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
445 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
445 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
446 ostream=ostream)
446 ostream=ostream)
447
447
448 def __call__(self, etype, value, elist):
448 def __call__(self, etype, value, elist):
449 self.ostream.flush()
449 self.ostream.flush()
450 self.ostream.write(self.text(etype, value, elist))
450 self.ostream.write(self.text(etype, value, elist))
451 self.ostream.write('\n')
451 self.ostream.write('\n')
452
452
453 def structured_traceback(self, etype, value, elist, tb_offset=None,
453 def structured_traceback(self, etype, value, elist, tb_offset=None,
454 context=5):
454 context=5):
455 """Return a color formatted string with the traceback info.
455 """Return a color formatted string with the traceback info.
456
456
457 Parameters
457 Parameters
458 ----------
458 ----------
459 etype : exception type
459 etype : exception type
460 Type of the exception raised.
460 Type of the exception raised.
461
461
462 value : object
462 value : object
463 Data stored in the exception
463 Data stored in the exception
464
464
465 elist : list
465 elist : list
466 List of frames, see class docstring for details.
466 List of frames, see class docstring for details.
467
467
468 tb_offset : int, optional
468 tb_offset : int, optional
469 Number of frames in the traceback to skip. If not given, the
469 Number of frames in the traceback to skip. If not given, the
470 instance value is used (set in constructor).
470 instance value is used (set in constructor).
471
471
472 context : int, optional
472 context : int, optional
473 Number of lines of context information to print.
473 Number of lines of context information to print.
474
474
475 Returns
475 Returns
476 -------
476 -------
477 String with formatted exception.
477 String with formatted exception.
478 """
478 """
479 tb_offset = self.tb_offset if tb_offset is None else tb_offset
479 tb_offset = self.tb_offset if tb_offset is None else tb_offset
480 Colors = self.Colors
480 Colors = self.Colors
481 out_list = []
481 out_list = []
482 if elist:
482 if elist:
483
483
484 if tb_offset and len(elist) > tb_offset:
484 if tb_offset and len(elist) > tb_offset:
485 elist = elist[tb_offset:]
485 elist = elist[tb_offset:]
486
486
487 out_list.append('Traceback %s(most recent call last)%s:' %
487 out_list.append('Traceback %s(most recent call last)%s:' %
488 (Colors.normalEm, Colors.Normal) + '\n')
488 (Colors.normalEm, Colors.Normal) + '\n')
489 out_list.extend(self._format_list(elist))
489 out_list.extend(self._format_list(elist))
490 # The exception info should be a single entry in the list.
490 # The exception info should be a single entry in the list.
491 lines = ''.join(self._format_exception_only(etype, value))
491 lines = ''.join(self._format_exception_only(etype, value))
492 out_list.append(lines)
492 out_list.append(lines)
493
493
494 # Note: this code originally read:
494 # Note: this code originally read:
495
495
496 ## for line in lines[:-1]:
496 ## for line in lines[:-1]:
497 ## out_list.append(" "+line)
497 ## out_list.append(" "+line)
498 ## out_list.append(lines[-1])
498 ## out_list.append(lines[-1])
499
499
500 # This means it was indenting everything but the last line by a little
500 # This means it was indenting everything but the last line by a little
501 # bit. I've disabled this for now, but if we see ugliness somewhre we
501 # bit. I've disabled this for now, but if we see ugliness somewhre we
502 # can restore it.
502 # can restore it.
503
503
504 return out_list
504 return out_list
505
505
506 def _format_list(self, extracted_list):
506 def _format_list(self, extracted_list):
507 """Format a list of traceback entry tuples for printing.
507 """Format a list of traceback entry tuples for printing.
508
508
509 Given a list of tuples as returned by extract_tb() or
509 Given a list of tuples as returned by extract_tb() or
510 extract_stack(), return a list of strings ready for printing.
510 extract_stack(), return a list of strings ready for printing.
511 Each string in the resulting list corresponds to the item with the
511 Each string in the resulting list corresponds to the item with the
512 same index in the argument list. Each string ends in a newline;
512 same index in the argument list. Each string ends in a newline;
513 the strings may contain internal newlines as well, for those items
513 the strings may contain internal newlines as well, for those items
514 whose source text line is not None.
514 whose source text line is not None.
515
515
516 Lifted almost verbatim from traceback.py
516 Lifted almost verbatim from traceback.py
517 """
517 """
518
518
519 Colors = self.Colors
519 Colors = self.Colors
520 list = []
520 list = []
521 for filename, lineno, name, line in extracted_list[:-1]:
521 for filename, lineno, name, line in extracted_list[:-1]:
522 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
522 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
523 (Colors.filename, filename, Colors.Normal,
523 (Colors.filename, filename, Colors.Normal,
524 Colors.lineno, lineno, Colors.Normal,
524 Colors.lineno, lineno, Colors.Normal,
525 Colors.name, name, Colors.Normal)
525 Colors.name, name, Colors.Normal)
526 if line:
526 if line:
527 item += ' %s\n' % line.strip()
527 item += ' %s\n' % line.strip()
528 list.append(item)
528 list.append(item)
529 # Emphasize the last entry
529 # Emphasize the last entry
530 filename, lineno, name, line = extracted_list[-1]
530 filename, lineno, name, line = extracted_list[-1]
531 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
531 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
532 (Colors.normalEm,
532 (Colors.normalEm,
533 Colors.filenameEm, filename, Colors.normalEm,
533 Colors.filenameEm, filename, Colors.normalEm,
534 Colors.linenoEm, lineno, Colors.normalEm,
534 Colors.linenoEm, lineno, Colors.normalEm,
535 Colors.nameEm, name, Colors.normalEm,
535 Colors.nameEm, name, Colors.normalEm,
536 Colors.Normal)
536 Colors.Normal)
537 if line:
537 if line:
538 item += '%s %s%s\n' % (Colors.line, line.strip(),
538 item += '%s %s%s\n' % (Colors.line, line.strip(),
539 Colors.Normal)
539 Colors.Normal)
540 list.append(item)
540 list.append(item)
541 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
541 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
542 return list
542 return list
543
543
544 def _format_exception_only(self, etype, value):
544 def _format_exception_only(self, etype, value):
545 """Format the exception part of a traceback.
545 """Format the exception part of a traceback.
546
546
547 The arguments are the exception type and value such as given by
547 The arguments are the exception type and value such as given by
548 sys.exc_info()[:2]. The return value is a list of strings, each ending
548 sys.exc_info()[:2]. The return value is a list of strings, each ending
549 in a newline. Normally, the list contains a single string; however,
549 in a newline. Normally, the list contains a single string; however,
550 for SyntaxError exceptions, it contains several lines that (when
550 for SyntaxError exceptions, it contains several lines that (when
551 printed) display detailed information about where the syntax error
551 printed) display detailed information about where the syntax error
552 occurred. The message indicating which exception occurred is the
552 occurred. The message indicating which exception occurred is the
553 always last string in the list.
553 always last string in the list.
554
554
555 Also lifted nearly verbatim from traceback.py
555 Also lifted nearly verbatim from traceback.py
556 """
556 """
557
557
558 have_filedata = False
558 have_filedata = False
559 Colors = self.Colors
559 Colors = self.Colors
560 list = []
560 list = []
561 stype = Colors.excName + etype.__name__ + Colors.Normal
561 stype = Colors.excName + etype.__name__ + Colors.Normal
562 if value is None:
562 if value is None:
563 # Not sure if this can still happen in Python 2.6 and above
563 # Not sure if this can still happen in Python 2.6 and above
564 list.append( str(stype) + '\n')
564 list.append( str(stype) + '\n')
565 else:
565 else:
566 if etype is SyntaxError:
566 if etype is SyntaxError:
567 have_filedata = True
567 have_filedata = True
568 #print 'filename is',filename # dbg
568 #print 'filename is',filename # dbg
569 if not value.filename: value.filename = "<string>"
569 if not value.filename: value.filename = "<string>"
570 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
570 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
571 (Colors.normalEm,
571 (Colors.normalEm,
572 Colors.filenameEm, value.filename, Colors.normalEm,
572 Colors.filenameEm, value.filename, Colors.normalEm,
573 Colors.linenoEm, value.lineno, Colors.Normal ))
573 Colors.linenoEm, value.lineno, Colors.Normal ))
574 if value.text is not None:
574 if value.text is not None:
575 i = 0
575 i = 0
576 while i < len(value.text) and value.text[i].isspace():
576 while i < len(value.text) and value.text[i].isspace():
577 i += 1
577 i += 1
578 list.append('%s %s%s\n' % (Colors.line,
578 list.append('%s %s%s\n' % (Colors.line,
579 value.text.strip(),
579 value.text.strip(),
580 Colors.Normal))
580 Colors.Normal))
581 if value.offset is not None:
581 if value.offset is not None:
582 s = ' '
582 s = ' '
583 for c in value.text[i:value.offset-1]:
583 for c in value.text[i:value.offset-1]:
584 if c.isspace():
584 if c.isspace():
585 s += c
585 s += c
586 else:
586 else:
587 s += ' '
587 s += ' '
588 list.append('%s%s^%s\n' % (Colors.caret, s,
588 list.append('%s%s^%s\n' % (Colors.caret, s,
589 Colors.Normal) )
589 Colors.Normal) )
590
590
591 try:
591 try:
592 s = value.msg
592 s = value.msg
593 except Exception:
593 except Exception:
594 s = self._some_str(value)
594 s = self._some_str(value)
595 if s:
595 if s:
596 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
596 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
597 Colors.Normal, s))
597 Colors.Normal, s))
598 else:
598 else:
599 list.append('%s\n' % str(stype))
599 list.append('%s\n' % str(stype))
600
600
601 # sync with user hooks
601 # sync with user hooks
602 if have_filedata:
602 if have_filedata:
603 ipinst = ipapi.get()
603 ipinst = ipapi.get()
604 if ipinst is not None:
604 if ipinst is not None:
605 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
605 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
606
606
607 return list
607 return list
608
608
609 def get_exception_only(self, etype, value):
609 def get_exception_only(self, etype, value):
610 """Only print the exception type and message, without a traceback.
610 """Only print the exception type and message, without a traceback.
611
611
612 Parameters
612 Parameters
613 ----------
613 ----------
614 etype : exception type
614 etype : exception type
615 value : exception value
615 value : exception value
616 """
616 """
617 return ListTB.structured_traceback(self, etype, value, [])
617 return ListTB.structured_traceback(self, etype, value, [])
618
618
619
619
620 def show_exception_only(self, etype, evalue):
620 def show_exception_only(self, etype, evalue):
621 """Only print the exception type and message, without a traceback.
621 """Only print the exception type and message, without a traceback.
622
622
623 Parameters
623 Parameters
624 ----------
624 ----------
625 etype : exception type
625 etype : exception type
626 value : exception value
626 value : exception value
627 """
627 """
628 # This method needs to use __call__ from *this* class, not the one from
628 # This method needs to use __call__ from *this* class, not the one from
629 # a subclass whose signature or behavior may be different
629 # a subclass whose signature or behavior may be different
630 ostream = self.ostream
630 ostream = self.ostream
631 ostream.flush()
631 ostream.flush()
632 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
632 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
633 ostream.flush()
633 ostream.flush()
634
634
635 def _some_str(self, value):
635 def _some_str(self, value):
636 # Lifted from traceback.py
636 # Lifted from traceback.py
637 try:
637 try:
638 return str(value)
638 return str(value)
639 except:
639 except:
640 return '<unprintable %s object>' % type(value).__name__
640 return '<unprintable %s object>' % type(value).__name__
641
641
642 #----------------------------------------------------------------------------
642 #----------------------------------------------------------------------------
643 class VerboseTB(TBTools):
643 class VerboseTB(TBTools):
644 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
644 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
645 of HTML. Requires inspect and pydoc. Crazy, man.
645 of HTML. Requires inspect and pydoc. Crazy, man.
646
646
647 Modified version which optionally strips the topmost entries from the
647 Modified version which optionally strips the topmost entries from the
648 traceback, to be used with alternate interpreters (because their own code
648 traceback, to be used with alternate interpreters (because their own code
649 would appear in the traceback)."""
649 would appear in the traceback)."""
650
650
651 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
651 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
652 tb_offset=0, long_header=False, include_vars=True,
652 tb_offset=0, long_header=False, include_vars=True,
653 check_cache=None):
653 check_cache=None):
654 """Specify traceback offset, headers and color scheme.
654 """Specify traceback offset, headers and color scheme.
655
655
656 Define how many frames to drop from the tracebacks. Calling it with
656 Define how many frames to drop from the tracebacks. Calling it with
657 tb_offset=1 allows use of this handler in interpreters which will have
657 tb_offset=1 allows use of this handler in interpreters which will have
658 their own code at the top of the traceback (VerboseTB will first
658 their own code at the top of the traceback (VerboseTB will first
659 remove that frame before printing the traceback info)."""
659 remove that frame before printing the traceback info)."""
660 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
660 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
661 ostream=ostream)
661 ostream=ostream)
662 self.tb_offset = tb_offset
662 self.tb_offset = tb_offset
663 self.long_header = long_header
663 self.long_header = long_header
664 self.include_vars = include_vars
664 self.include_vars = include_vars
665 # By default we use linecache.checkcache, but the user can provide a
665 # By default we use linecache.checkcache, but the user can provide a
666 # different check_cache implementation. This is used by the IPython
666 # different check_cache implementation. This is used by the IPython
667 # kernel to provide tracebacks for interactive code that is cached,
667 # kernel to provide tracebacks for interactive code that is cached,
668 # by a compiler instance that flushes the linecache but preserves its
668 # by a compiler instance that flushes the linecache but preserves its
669 # own code cache.
669 # own code cache.
670 if check_cache is None:
670 if check_cache is None:
671 check_cache = linecache.checkcache
671 check_cache = linecache.checkcache
672 self.check_cache = check_cache
672 self.check_cache = check_cache
673
673
674 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
674 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
675 context=5):
675 context=5):
676 """Return a nice text document describing the traceback."""
676 """Return a nice text document describing the traceback."""
677
677
678 tb_offset = self.tb_offset if tb_offset is None else tb_offset
678 tb_offset = self.tb_offset if tb_offset is None else tb_offset
679
679
680 # some locals
680 # some locals
681 try:
681 try:
682 etype = etype.__name__
682 etype = etype.__name__
683 except AttributeError:
683 except AttributeError:
684 pass
684 pass
685 Colors = self.Colors # just a shorthand + quicker name lookup
685 Colors = self.Colors # just a shorthand + quicker name lookup
686 ColorsNormal = Colors.Normal # used a lot
686 ColorsNormal = Colors.Normal # used a lot
687 col_scheme = self.color_scheme_table.active_scheme_name
687 col_scheme = self.color_scheme_table.active_scheme_name
688 indent = ' '*INDENT_SIZE
688 indent = ' '*INDENT_SIZE
689 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
689 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
690 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
690 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
691 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
691 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
692
692
693 # some internal-use functions
693 # some internal-use functions
694 def text_repr(value):
694 def text_repr(value):
695 """Hopefully pretty robust repr equivalent."""
695 """Hopefully pretty robust repr equivalent."""
696 # this is pretty horrible but should always return *something*
696 # this is pretty horrible but should always return *something*
697 try:
697 try:
698 return pydoc.text.repr(value)
698 return pydoc.text.repr(value)
699 except KeyboardInterrupt:
699 except KeyboardInterrupt:
700 raise
700 raise
701 except:
701 except:
702 try:
702 try:
703 return repr(value)
703 return repr(value)
704 except KeyboardInterrupt:
704 except KeyboardInterrupt:
705 raise
705 raise
706 except:
706 except:
707 try:
707 try:
708 # all still in an except block so we catch
708 # all still in an except block so we catch
709 # getattr raising
709 # getattr raising
710 name = getattr(value, '__name__', None)
710 name = getattr(value, '__name__', None)
711 if name:
711 if name:
712 # ick, recursion
712 # ick, recursion
713 return text_repr(name)
713 return text_repr(name)
714 klass = getattr(value, '__class__', None)
714 klass = getattr(value, '__class__', None)
715 if klass:
715 if klass:
716 return '%s instance' % text_repr(klass)
716 return '%s instance' % text_repr(klass)
717 except KeyboardInterrupt:
717 except KeyboardInterrupt:
718 raise
718 raise
719 except:
719 except:
720 return 'UNRECOVERABLE REPR FAILURE'
720 return 'UNRECOVERABLE REPR FAILURE'
721 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
721 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
722 def nullrepr(value, repr=text_repr): return ''
722 def nullrepr(value, repr=text_repr): return ''
723
723
724 # meat of the code begins
724 # meat of the code begins
725 try:
725 try:
726 etype = etype.__name__
726 etype = etype.__name__
727 except AttributeError:
727 except AttributeError:
728 pass
728 pass
729
729
730 if self.long_header:
730 if self.long_header:
731 # Header with the exception type, python version, and date
731 # Header with the exception type, python version, and date
732 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
732 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
733 date = time.ctime(time.time())
733 date = time.ctime(time.time())
734
734
735 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
735 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
736 exc, ' '*(75-len(str(etype))-len(pyver)),
736 exc, ' '*(75-len(str(etype))-len(pyver)),
737 pyver, date.rjust(75) )
737 pyver, date.rjust(75) )
738 head += "\nA problem occured executing Python code. Here is the sequence of function"\
738 head += "\nA problem occured executing Python code. Here is the sequence of function"\
739 "\ncalls leading up to the error, with the most recent (innermost) call last."
739 "\ncalls leading up to the error, with the most recent (innermost) call last."
740 else:
740 else:
741 # Simplified header
741 # Simplified header
742 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
742 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
743 'Traceback (most recent call last)'.\
743 'Traceback (most recent call last)'.\
744 rjust(75 - len(str(etype)) ) )
744 rjust(75 - len(str(etype)) ) )
745 frames = []
745 frames = []
746 # Flush cache before calling inspect. This helps alleviate some of the
746 # Flush cache before calling inspect. This helps alleviate some of the
747 # problems with python 2.3's inspect.py.
747 # problems with python 2.3's inspect.py.
748 ##self.check_cache()
748 ##self.check_cache()
749 # Drop topmost frames if requested
749 # Drop topmost frames if requested
750 try:
750 try:
751 # Try the default getinnerframes and Alex's: Alex's fixes some
751 # Try the default getinnerframes and Alex's: Alex's fixes some
752 # problems, but it generates empty tracebacks for console errors
752 # problems, but it generates empty tracebacks for console errors
753 # (5 blanks lines) where none should be returned.
753 # (5 blanks lines) where none should be returned.
754 #records = inspect.getinnerframes(etb, context)[tb_offset:]
754 #records = inspect.getinnerframes(etb, context)[tb_offset:]
755 #print 'python records:', records # dbg
755 #print 'python records:', records # dbg
756 records = _fixed_getinnerframes(etb, context, tb_offset)
756 records = _fixed_getinnerframes(etb, context, tb_offset)
757 #print 'alex records:', records # dbg
757 #print 'alex records:', records # dbg
758 except:
758 except:
759
759
760 # FIXME: I've been getting many crash reports from python 2.3
760 # FIXME: I've been getting many crash reports from python 2.3
761 # users, traceable to inspect.py. If I can find a small test-case
761 # users, traceable to inspect.py. If I can find a small test-case
762 # to reproduce this, I should either write a better workaround or
762 # to reproduce this, I should either write a better workaround or
763 # file a bug report against inspect (if that's the real problem).
763 # file a bug report against inspect (if that's the real problem).
764 # So far, I haven't been able to find an isolated example to
764 # So far, I haven't been able to find an isolated example to
765 # reproduce the problem.
765 # reproduce the problem.
766 inspect_error()
766 inspect_error()
767 traceback.print_exc(file=self.ostream)
767 traceback.print_exc(file=self.ostream)
768 info('\nUnfortunately, your original traceback can not be constructed.\n')
768 info('\nUnfortunately, your original traceback can not be constructed.\n')
769 return ''
769 return ''
770
770
771 # build some color string templates outside these nested loops
771 # build some color string templates outside these nested loops
772 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
772 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
773 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
773 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
774 ColorsNormal)
774 ColorsNormal)
775 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
775 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
776 (Colors.vName, Colors.valEm, ColorsNormal)
776 (Colors.vName, Colors.valEm, ColorsNormal)
777 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
777 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
778 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
778 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
779 Colors.vName, ColorsNormal)
779 Colors.vName, ColorsNormal)
780 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
780 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
781 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
781 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
782 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
782 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
783 ColorsNormal)
783 ColorsNormal)
784
784
785 # now, loop over all records printing context and info
785 # now, loop over all records printing context and info
786 abspath = os.path.abspath
786 abspath = os.path.abspath
787 for frame, file, lnum, func, lines, index in records:
787 for frame, file, lnum, func, lines, index in records:
788 #print '*** record:',file,lnum,func,lines,index # dbg
788 #print '*** record:',file,lnum,func,lines,index # dbg
789
789
790 if not file:
790 if not file:
791 file = '?'
791 file = '?'
792 elif not(file.startswith("<") and file.endswith(">")):
792 elif not(file.startswith("<") and file.endswith(">")):
793 # Guess that filenames like <string> aren't real filenames, so
793 # Guess that filenames like <string> aren't real filenames, so
794 # don't call abspath on them.
794 # don't call abspath on them.
795 try:
795 try:
796 file = abspath(file)
796 file = abspath(file)
797 except OSError:
797 except OSError:
798 # Not sure if this can still happen: abspath now works with
798 # Not sure if this can still happen: abspath now works with
799 # file names like <string>
799 # file names like <string>
800 pass
800 pass
801
801
802 link = tpl_link % file
802 link = tpl_link % file
803 args, varargs, varkw, locals = inspect.getargvalues(frame)
803 args, varargs, varkw, locals = inspect.getargvalues(frame)
804
804
805 if func == '?':
805 if func == '?':
806 call = ''
806 call = ''
807 else:
807 else:
808 # Decide whether to include variable details or not
808 # Decide whether to include variable details or not
809 var_repr = self.include_vars and eqrepr or nullrepr
809 var_repr = self.include_vars and eqrepr or nullrepr
810 try:
810 try:
811 call = tpl_call % (func,inspect.formatargvalues(args,
811 call = tpl_call % (func,inspect.formatargvalues(args,
812 varargs, varkw,
812 varargs, varkw,
813 locals,formatvalue=var_repr))
813 locals,formatvalue=var_repr))
814 except KeyError:
814 except KeyError:
815 # This happens in situations like errors inside generator
815 # This happens in situations like errors inside generator
816 # expressions, where local variables are listed in the
816 # expressions, where local variables are listed in the
817 # line, but can't be extracted from the frame. I'm not
817 # line, but can't be extracted from the frame. I'm not
818 # 100% sure this isn't actually a bug in inspect itself,
818 # 100% sure this isn't actually a bug in inspect itself,
819 # but since there's no info for us to compute with, the
819 # but since there's no info for us to compute with, the
820 # best we can do is report the failure and move on. Here
820 # best we can do is report the failure and move on. Here
821 # we must *not* call any traceback construction again,
821 # we must *not* call any traceback construction again,
822 # because that would mess up use of %debug later on. So we
822 # because that would mess up use of %debug later on. So we
823 # simply report the failure and move on. The only
823 # simply report the failure and move on. The only
824 # limitation will be that this frame won't have locals
824 # limitation will be that this frame won't have locals
825 # listed in the call signature. Quite subtle problem...
825 # listed in the call signature. Quite subtle problem...
826 # I can't think of a good way to validate this in a unit
826 # I can't think of a good way to validate this in a unit
827 # test, but running a script consisting of:
827 # test, but running a script consisting of:
828 # dict( (k,v.strip()) for (k,v) in range(10) )
828 # dict( (k,v.strip()) for (k,v) in range(10) )
829 # will illustrate the error, if this exception catch is
829 # will illustrate the error, if this exception catch is
830 # disabled.
830 # disabled.
831 call = tpl_call_fail % func
831 call = tpl_call_fail % func
832
832
833 # Don't attempt to tokenize binary files.
833 # Don't attempt to tokenize binary files.
834 if file.endswith(('.so', '.pyd', '.dll')):
834 if file.endswith(('.so', '.pyd', '.dll')):
835 frames.append('%s %s\n' % (link,call))
835 frames.append('%s %s\n' % (link,call))
836 continue
836 continue
837 elif file.endswith(('.pyc','.pyo')):
837 elif file.endswith(('.pyc','.pyo')):
838 # Look up the corresponding source file.
838 # Look up the corresponding source file.
839 file = pyfile.source_from_cache(file)
839 file = pyfile.source_from_cache(file)
840
840
841 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
841 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
842 line = getline(file, lnum[0])
842 line = getline(file, lnum[0])
843 lnum[0] += 1
843 lnum[0] += 1
844 return line
844 return line
845
845
846 # Build the list of names on this line of code where the exception
846 # Build the list of names on this line of code where the exception
847 # occurred.
847 # occurred.
848 try:
848 try:
849 names = []
849 names = []
850 name_cont = False
850 name_cont = False
851
851
852 for token_type, token, start, end, line in generate_tokens(linereader):
852 for token_type, token, start, end, line in generate_tokens(linereader):
853 # build composite names
853 # build composite names
854 if token_type == tokenize.NAME and token not in keyword.kwlist:
854 if token_type == tokenize.NAME and token not in keyword.kwlist:
855 if name_cont:
855 if name_cont:
856 # Continuation of a dotted name
856 # Continuation of a dotted name
857 try:
857 try:
858 names[-1].append(token)
858 names[-1].append(token)
859 except IndexError:
859 except IndexError:
860 names.append([token])
860 names.append([token])
861 name_cont = False
861 name_cont = False
862 else:
862 else:
863 # Regular new names. We append everything, the caller
863 # Regular new names. We append everything, the caller
864 # will be responsible for pruning the list later. It's
864 # will be responsible for pruning the list later. It's
865 # very tricky to try to prune as we go, b/c composite
865 # very tricky to try to prune as we go, b/c composite
866 # names can fool us. The pruning at the end is easy
866 # names can fool us. The pruning at the end is easy
867 # to do (or the caller can print a list with repeated
867 # to do (or the caller can print a list with repeated
868 # names if so desired.
868 # names if so desired.
869 names.append([token])
869 names.append([token])
870 elif token == '.':
870 elif token == '.':
871 name_cont = True
871 name_cont = True
872 elif token_type == tokenize.NEWLINE:
872 elif token_type == tokenize.NEWLINE:
873 break
873 break
874
874
875 except (IndexError, UnicodeDecodeError):
875 except (IndexError, UnicodeDecodeError):
876 # signals exit of tokenizer
876 # signals exit of tokenizer
877 pass
877 pass
878 except tokenize.TokenError as msg:
878 except tokenize.TokenError as msg:
879 _m = ("An unexpected error occurred while tokenizing input\n"
879 _m = ("An unexpected error occurred while tokenizing input\n"
880 "The following traceback may be corrupted or invalid\n"
880 "The following traceback may be corrupted or invalid\n"
881 "The error message is: %s\n" % msg)
881 "The error message is: %s\n" % msg)
882 error(_m)
882 error(_m)
883
883
884 # Join composite names (e.g. "dict.fromkeys")
884 # Join composite names (e.g. "dict.fromkeys")
885 names = ['.'.join(n) for n in names]
885 names = ['.'.join(n) for n in names]
886 # prune names list of duplicates, but keep the right order
886 # prune names list of duplicates, but keep the right order
887 unique_names = uniq_stable(names)
887 unique_names = uniq_stable(names)
888
888
889 # Start loop over vars
889 # Start loop over vars
890 lvals = []
890 lvals = []
891 if self.include_vars:
891 if self.include_vars:
892 for name_full in unique_names:
892 for name_full in unique_names:
893 name_base = name_full.split('.',1)[0]
893 name_base = name_full.split('.',1)[0]
894 if name_base in frame.f_code.co_varnames:
894 if name_base in frame.f_code.co_varnames:
895 if locals.has_key(name_base):
895 if name_base in locals:
896 try:
896 try:
897 value = repr(eval(name_full,locals))
897 value = repr(eval(name_full,locals))
898 except:
898 except:
899 value = undefined
899 value = undefined
900 else:
900 else:
901 value = undefined
901 value = undefined
902 name = tpl_local_var % name_full
902 name = tpl_local_var % name_full
903 else:
903 else:
904 if frame.f_globals.has_key(name_base):
904 if name_base in frame.f_globals:
905 try:
905 try:
906 value = repr(eval(name_full,frame.f_globals))
906 value = repr(eval(name_full,frame.f_globals))
907 except:
907 except:
908 value = undefined
908 value = undefined
909 else:
909 else:
910 value = undefined
910 value = undefined
911 name = tpl_global_var % name_full
911 name = tpl_global_var % name_full
912 lvals.append(tpl_name_val % (name,value))
912 lvals.append(tpl_name_val % (name,value))
913 if lvals:
913 if lvals:
914 lvals = '%s%s' % (indent,em_normal.join(lvals))
914 lvals = '%s%s' % (indent,em_normal.join(lvals))
915 else:
915 else:
916 lvals = ''
916 lvals = ''
917
917
918 level = '%s %s\n' % (link,call)
918 level = '%s %s\n' % (link,call)
919
919
920 if index is None:
920 if index is None:
921 frames.append(level)
921 frames.append(level)
922 else:
922 else:
923 frames.append('%s%s' % (level,''.join(
923 frames.append('%s%s' % (level,''.join(
924 _format_traceback_lines(lnum,index,lines,Colors,lvals,
924 _format_traceback_lines(lnum,index,lines,Colors,lvals,
925 col_scheme))))
925 col_scheme))))
926
926
927 # Get (safely) a string form of the exception info
927 # Get (safely) a string form of the exception info
928 try:
928 try:
929 etype_str,evalue_str = map(str,(etype,evalue))
929 etype_str,evalue_str = map(str,(etype,evalue))
930 except:
930 except:
931 # User exception is improperly defined.
931 # User exception is improperly defined.
932 etype,evalue = str,sys.exc_info()[:2]
932 etype,evalue = str,sys.exc_info()[:2]
933 etype_str,evalue_str = map(str,(etype,evalue))
933 etype_str,evalue_str = map(str,(etype,evalue))
934 # ... and format it
934 # ... and format it
935 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
935 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
936 ColorsNormal, evalue_str)]
936 ColorsNormal, evalue_str)]
937 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
937 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
938 try:
938 try:
939 names = [w for w in dir(evalue) if isinstance(w, basestring)]
939 names = [w for w in dir(evalue) if isinstance(w, basestring)]
940 except:
940 except:
941 # Every now and then, an object with funny inernals blows up
941 # Every now and then, an object with funny inernals blows up
942 # when dir() is called on it. We do the best we can to report
942 # when dir() is called on it. We do the best we can to report
943 # the problem and continue
943 # the problem and continue
944 _m = '%sException reporting error (object with broken dir())%s:'
944 _m = '%sException reporting error (object with broken dir())%s:'
945 exception.append(_m % (Colors.excName,ColorsNormal))
945 exception.append(_m % (Colors.excName,ColorsNormal))
946 etype_str,evalue_str = map(str,sys.exc_info()[:2])
946 etype_str,evalue_str = map(str,sys.exc_info()[:2])
947 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
947 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
948 ColorsNormal, evalue_str))
948 ColorsNormal, evalue_str))
949 names = []
949 names = []
950 for name in names:
950 for name in names:
951 value = text_repr(getattr(evalue, name))
951 value = text_repr(getattr(evalue, name))
952 exception.append('\n%s%s = %s' % (indent, name, value))
952 exception.append('\n%s%s = %s' % (indent, name, value))
953
953
954 # vds: >>
954 # vds: >>
955 if records:
955 if records:
956 filepath, lnum = records[-1][1:3]
956 filepath, lnum = records[-1][1:3]
957 #print "file:", str(file), "linenb", str(lnum) # dbg
957 #print "file:", str(file), "linenb", str(lnum) # dbg
958 filepath = os.path.abspath(filepath)
958 filepath = os.path.abspath(filepath)
959 ipinst = ipapi.get()
959 ipinst = ipapi.get()
960 if ipinst is not None:
960 if ipinst is not None:
961 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
961 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
962 # vds: <<
962 # vds: <<
963
963
964 # return all our info assembled as a single string
964 # return all our info assembled as a single string
965 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
965 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
966 return [head] + frames + [''.join(exception[0])]
966 return [head] + frames + [''.join(exception[0])]
967
967
968 def debugger(self,force=False):
968 def debugger(self,force=False):
969 """Call up the pdb debugger if desired, always clean up the tb
969 """Call up the pdb debugger if desired, always clean up the tb
970 reference.
970 reference.
971
971
972 Keywords:
972 Keywords:
973
973
974 - force(False): by default, this routine checks the instance call_pdb
974 - force(False): by default, this routine checks the instance call_pdb
975 flag and does not actually invoke the debugger if the flag is false.
975 flag and does not actually invoke the debugger if the flag is false.
976 The 'force' option forces the debugger to activate even if the flag
976 The 'force' option forces the debugger to activate even if the flag
977 is false.
977 is false.
978
978
979 If the call_pdb flag is set, the pdb interactive debugger is
979 If the call_pdb flag is set, the pdb interactive debugger is
980 invoked. In all cases, the self.tb reference to the current traceback
980 invoked. In all cases, the self.tb reference to the current traceback
981 is deleted to prevent lingering references which hamper memory
981 is deleted to prevent lingering references which hamper memory
982 management.
982 management.
983
983
984 Note that each call to pdb() does an 'import readline', so if your app
984 Note that each call to pdb() does an 'import readline', so if your app
985 requires a special setup for the readline completers, you'll have to
985 requires a special setup for the readline completers, you'll have to
986 fix that by hand after invoking the exception handler."""
986 fix that by hand after invoking the exception handler."""
987
987
988 if force or self.call_pdb:
988 if force or self.call_pdb:
989 if self.pdb is None:
989 if self.pdb is None:
990 self.pdb = debugger.Pdb(
990 self.pdb = debugger.Pdb(
991 self.color_scheme_table.active_scheme_name)
991 self.color_scheme_table.active_scheme_name)
992 # the system displayhook may have changed, restore the original
992 # the system displayhook may have changed, restore the original
993 # for pdb
993 # for pdb
994 display_trap = DisplayTrap(hook=sys.__displayhook__)
994 display_trap = DisplayTrap(hook=sys.__displayhook__)
995 with display_trap:
995 with display_trap:
996 self.pdb.reset()
996 self.pdb.reset()
997 # Find the right frame so we don't pop up inside ipython itself
997 # Find the right frame so we don't pop up inside ipython itself
998 if hasattr(self,'tb') and self.tb is not None:
998 if hasattr(self,'tb') and self.tb is not None:
999 etb = self.tb
999 etb = self.tb
1000 else:
1000 else:
1001 etb = self.tb = sys.last_traceback
1001 etb = self.tb = sys.last_traceback
1002 while self.tb is not None and self.tb.tb_next is not None:
1002 while self.tb is not None and self.tb.tb_next is not None:
1003 self.tb = self.tb.tb_next
1003 self.tb = self.tb.tb_next
1004 if etb and etb.tb_next:
1004 if etb and etb.tb_next:
1005 etb = etb.tb_next
1005 etb = etb.tb_next
1006 self.pdb.botframe = etb.tb_frame
1006 self.pdb.botframe = etb.tb_frame
1007 self.pdb.interaction(self.tb.tb_frame, self.tb)
1007 self.pdb.interaction(self.tb.tb_frame, self.tb)
1008
1008
1009 if hasattr(self,'tb'):
1009 if hasattr(self,'tb'):
1010 del self.tb
1010 del self.tb
1011
1011
1012 def handler(self, info=None):
1012 def handler(self, info=None):
1013 (etype, evalue, etb) = info or sys.exc_info()
1013 (etype, evalue, etb) = info or sys.exc_info()
1014 self.tb = etb
1014 self.tb = etb
1015 ostream = self.ostream
1015 ostream = self.ostream
1016 ostream.flush()
1016 ostream.flush()
1017 ostream.write(self.text(etype, evalue, etb))
1017 ostream.write(self.text(etype, evalue, etb))
1018 ostream.write('\n')
1018 ostream.write('\n')
1019 ostream.flush()
1019 ostream.flush()
1020
1020
1021 # Changed so an instance can just be called as VerboseTB_inst() and print
1021 # Changed so an instance can just be called as VerboseTB_inst() and print
1022 # out the right info on its own.
1022 # out the right info on its own.
1023 def __call__(self, etype=None, evalue=None, etb=None):
1023 def __call__(self, etype=None, evalue=None, etb=None):
1024 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1024 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1025 if etb is None:
1025 if etb is None:
1026 self.handler()
1026 self.handler()
1027 else:
1027 else:
1028 self.handler((etype, evalue, etb))
1028 self.handler((etype, evalue, etb))
1029 try:
1029 try:
1030 self.debugger()
1030 self.debugger()
1031 except KeyboardInterrupt:
1031 except KeyboardInterrupt:
1032 print "\nKeyboardInterrupt"
1032 print "\nKeyboardInterrupt"
1033
1033
1034 #----------------------------------------------------------------------------
1034 #----------------------------------------------------------------------------
1035 class FormattedTB(VerboseTB, ListTB):
1035 class FormattedTB(VerboseTB, ListTB):
1036 """Subclass ListTB but allow calling with a traceback.
1036 """Subclass ListTB but allow calling with a traceback.
1037
1037
1038 It can thus be used as a sys.excepthook for Python > 2.1.
1038 It can thus be used as a sys.excepthook for Python > 2.1.
1039
1039
1040 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1040 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1041
1041
1042 Allows a tb_offset to be specified. This is useful for situations where
1042 Allows a tb_offset to be specified. This is useful for situations where
1043 one needs to remove a number of topmost frames from the traceback (such as
1043 one needs to remove a number of topmost frames from the traceback (such as
1044 occurs with python programs that themselves execute other python code,
1044 occurs with python programs that themselves execute other python code,
1045 like Python shells). """
1045 like Python shells). """
1046
1046
1047 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1047 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1048 ostream=None,
1048 ostream=None,
1049 tb_offset=0, long_header=False, include_vars=False,
1049 tb_offset=0, long_header=False, include_vars=False,
1050 check_cache=None):
1050 check_cache=None):
1051
1051
1052 # NEVER change the order of this list. Put new modes at the end:
1052 # NEVER change the order of this list. Put new modes at the end:
1053 self.valid_modes = ['Plain','Context','Verbose']
1053 self.valid_modes = ['Plain','Context','Verbose']
1054 self.verbose_modes = self.valid_modes[1:3]
1054 self.verbose_modes = self.valid_modes[1:3]
1055
1055
1056 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1056 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1057 ostream=ostream, tb_offset=tb_offset,
1057 ostream=ostream, tb_offset=tb_offset,
1058 long_header=long_header, include_vars=include_vars,
1058 long_header=long_header, include_vars=include_vars,
1059 check_cache=check_cache)
1059 check_cache=check_cache)
1060
1060
1061 # Different types of tracebacks are joined with different separators to
1061 # Different types of tracebacks are joined with different separators to
1062 # form a single string. They are taken from this dict
1062 # form a single string. They are taken from this dict
1063 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1063 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1064 # set_mode also sets the tb_join_char attribute
1064 # set_mode also sets the tb_join_char attribute
1065 self.set_mode(mode)
1065 self.set_mode(mode)
1066
1066
1067 def _extract_tb(self,tb):
1067 def _extract_tb(self,tb):
1068 if tb:
1068 if tb:
1069 return traceback.extract_tb(tb)
1069 return traceback.extract_tb(tb)
1070 else:
1070 else:
1071 return None
1071 return None
1072
1072
1073 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1073 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1074 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1074 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1075 mode = self.mode
1075 mode = self.mode
1076 if mode in self.verbose_modes:
1076 if mode in self.verbose_modes:
1077 # Verbose modes need a full traceback
1077 # Verbose modes need a full traceback
1078 return VerboseTB.structured_traceback(
1078 return VerboseTB.structured_traceback(
1079 self, etype, value, tb, tb_offset, context
1079 self, etype, value, tb, tb_offset, context
1080 )
1080 )
1081 else:
1081 else:
1082 # We must check the source cache because otherwise we can print
1082 # We must check the source cache because otherwise we can print
1083 # out-of-date source code.
1083 # out-of-date source code.
1084 self.check_cache()
1084 self.check_cache()
1085 # Now we can extract and format the exception
1085 # Now we can extract and format the exception
1086 elist = self._extract_tb(tb)
1086 elist = self._extract_tb(tb)
1087 return ListTB.structured_traceback(
1087 return ListTB.structured_traceback(
1088 self, etype, value, elist, tb_offset, context
1088 self, etype, value, elist, tb_offset, context
1089 )
1089 )
1090
1090
1091 def stb2text(self, stb):
1091 def stb2text(self, stb):
1092 """Convert a structured traceback (a list) to a string."""
1092 """Convert a structured traceback (a list) to a string."""
1093 return self.tb_join_char.join(stb)
1093 return self.tb_join_char.join(stb)
1094
1094
1095
1095
1096 def set_mode(self,mode=None):
1096 def set_mode(self,mode=None):
1097 """Switch to the desired mode.
1097 """Switch to the desired mode.
1098
1098
1099 If mode is not specified, cycles through the available modes."""
1099 If mode is not specified, cycles through the available modes."""
1100
1100
1101 if not mode:
1101 if not mode:
1102 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1102 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1103 len(self.valid_modes)
1103 len(self.valid_modes)
1104 self.mode = self.valid_modes[new_idx]
1104 self.mode = self.valid_modes[new_idx]
1105 elif mode not in self.valid_modes:
1105 elif mode not in self.valid_modes:
1106 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1106 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1107 'Valid modes: '+str(self.valid_modes))
1107 'Valid modes: '+str(self.valid_modes))
1108 else:
1108 else:
1109 self.mode = mode
1109 self.mode = mode
1110 # include variable details only in 'Verbose' mode
1110 # include variable details only in 'Verbose' mode
1111 self.include_vars = (self.mode == self.valid_modes[2])
1111 self.include_vars = (self.mode == self.valid_modes[2])
1112 # Set the join character for generating text tracebacks
1112 # Set the join character for generating text tracebacks
1113 self.tb_join_char = self._join_chars[self.mode]
1113 self.tb_join_char = self._join_chars[self.mode]
1114
1114
1115 # some convenient shorcuts
1115 # some convenient shorcuts
1116 def plain(self):
1116 def plain(self):
1117 self.set_mode(self.valid_modes[0])
1117 self.set_mode(self.valid_modes[0])
1118
1118
1119 def context(self):
1119 def context(self):
1120 self.set_mode(self.valid_modes[1])
1120 self.set_mode(self.valid_modes[1])
1121
1121
1122 def verbose(self):
1122 def verbose(self):
1123 self.set_mode(self.valid_modes[2])
1123 self.set_mode(self.valid_modes[2])
1124
1124
1125 #----------------------------------------------------------------------------
1125 #----------------------------------------------------------------------------
1126 class AutoFormattedTB(FormattedTB):
1126 class AutoFormattedTB(FormattedTB):
1127 """A traceback printer which can be called on the fly.
1127 """A traceback printer which can be called on the fly.
1128
1128
1129 It will find out about exceptions by itself.
1129 It will find out about exceptions by itself.
1130
1130
1131 A brief example:
1131 A brief example:
1132
1132
1133 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1133 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1134 try:
1134 try:
1135 ...
1135 ...
1136 except:
1136 except:
1137 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1137 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1138 """
1138 """
1139
1139
1140 def __call__(self,etype=None,evalue=None,etb=None,
1140 def __call__(self,etype=None,evalue=None,etb=None,
1141 out=None,tb_offset=None):
1141 out=None,tb_offset=None):
1142 """Print out a formatted exception traceback.
1142 """Print out a formatted exception traceback.
1143
1143
1144 Optional arguments:
1144 Optional arguments:
1145 - out: an open file-like object to direct output to.
1145 - out: an open file-like object to direct output to.
1146
1146
1147 - tb_offset: the number of frames to skip over in the stack, on a
1147 - tb_offset: the number of frames to skip over in the stack, on a
1148 per-call basis (this overrides temporarily the instance's tb_offset
1148 per-call basis (this overrides temporarily the instance's tb_offset
1149 given at initialization time. """
1149 given at initialization time. """
1150
1150
1151
1151
1152 if out is None:
1152 if out is None:
1153 out = self.ostream
1153 out = self.ostream
1154 out.flush()
1154 out.flush()
1155 out.write(self.text(etype, evalue, etb, tb_offset))
1155 out.write(self.text(etype, evalue, etb, tb_offset))
1156 out.write('\n')
1156 out.write('\n')
1157 out.flush()
1157 out.flush()
1158 # FIXME: we should remove the auto pdb behavior from here and leave
1158 # FIXME: we should remove the auto pdb behavior from here and leave
1159 # that to the clients.
1159 # that to the clients.
1160 try:
1160 try:
1161 self.debugger()
1161 self.debugger()
1162 except KeyboardInterrupt:
1162 except KeyboardInterrupt:
1163 print "\nKeyboardInterrupt"
1163 print "\nKeyboardInterrupt"
1164
1164
1165 def structured_traceback(self, etype=None, value=None, tb=None,
1165 def structured_traceback(self, etype=None, value=None, tb=None,
1166 tb_offset=None, context=5):
1166 tb_offset=None, context=5):
1167 if etype is None:
1167 if etype is None:
1168 etype,value,tb = sys.exc_info()
1168 etype,value,tb = sys.exc_info()
1169 self.tb = tb
1169 self.tb = tb
1170 return FormattedTB.structured_traceback(
1170 return FormattedTB.structured_traceback(
1171 self, etype, value, tb, tb_offset, context)
1171 self, etype, value, tb, tb_offset, context)
1172
1172
1173 #---------------------------------------------------------------------------
1173 #---------------------------------------------------------------------------
1174
1174
1175 # A simple class to preserve Nathan's original functionality.
1175 # A simple class to preserve Nathan's original functionality.
1176 class ColorTB(FormattedTB):
1176 class ColorTB(FormattedTB):
1177 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1177 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1178 def __init__(self,color_scheme='Linux',call_pdb=0):
1178 def __init__(self,color_scheme='Linux',call_pdb=0):
1179 FormattedTB.__init__(self,color_scheme=color_scheme,
1179 FormattedTB.__init__(self,color_scheme=color_scheme,
1180 call_pdb=call_pdb)
1180 call_pdb=call_pdb)
1181
1181
1182
1182
1183 class SyntaxTB(ListTB):
1183 class SyntaxTB(ListTB):
1184 """Extension which holds some state: the last exception value"""
1184 """Extension which holds some state: the last exception value"""
1185
1185
1186 def __init__(self,color_scheme = 'NoColor'):
1186 def __init__(self,color_scheme = 'NoColor'):
1187 ListTB.__init__(self,color_scheme)
1187 ListTB.__init__(self,color_scheme)
1188 self.last_syntax_error = None
1188 self.last_syntax_error = None
1189
1189
1190 def __call__(self, etype, value, elist):
1190 def __call__(self, etype, value, elist):
1191 self.last_syntax_error = value
1191 self.last_syntax_error = value
1192 ListTB.__call__(self,etype,value,elist)
1192 ListTB.__call__(self,etype,value,elist)
1193
1193
1194 def clear_err_state(self):
1194 def clear_err_state(self):
1195 """Return the current error state and clear it"""
1195 """Return the current error state and clear it"""
1196 e = self.last_syntax_error
1196 e = self.last_syntax_error
1197 self.last_syntax_error = None
1197 self.last_syntax_error = None
1198 return e
1198 return e
1199
1199
1200 def stb2text(self, stb):
1200 def stb2text(self, stb):
1201 """Convert a structured traceback (a list) to a string."""
1201 """Convert a structured traceback (a list) to a string."""
1202 return ''.join(stb)
1202 return ''.join(stb)
1203
1203
1204
1204
1205 #----------------------------------------------------------------------------
1205 #----------------------------------------------------------------------------
1206 # module testing (minimal)
1206 # module testing (minimal)
1207 if __name__ == "__main__":
1207 if __name__ == "__main__":
1208 def spam(c, (d, e)):
1208 def spam(c, (d, e)):
1209 x = c + d
1209 x = c + d
1210 y = c * d
1210 y = c * d
1211 foo(x, y)
1211 foo(x, y)
1212
1212
1213 def foo(a, b, bar=1):
1213 def foo(a, b, bar=1):
1214 eggs(a, b + bar)
1214 eggs(a, b + bar)
1215
1215
1216 def eggs(f, g, z=globals()):
1216 def eggs(f, g, z=globals()):
1217 h = f + g
1217 h = f + g
1218 i = f - g
1218 i = f - g
1219 return h / i
1219 return h / i
1220
1220
1221 print ''
1221 print ''
1222 print '*** Before ***'
1222 print '*** Before ***'
1223 try:
1223 try:
1224 print spam(1, (2, 3))
1224 print spam(1, (2, 3))
1225 except:
1225 except:
1226 traceback.print_exc()
1226 traceback.print_exc()
1227 print ''
1227 print ''
1228
1228
1229 handler = ColorTB()
1229 handler = ColorTB()
1230 print '*** ColorTB ***'
1230 print '*** ColorTB ***'
1231 try:
1231 try:
1232 print spam(1, (2, 3))
1232 print spam(1, (2, 3))
1233 except:
1233 except:
1234 handler(*sys.exc_info())
1234 handler(*sys.exc_info())
1235 print ''
1235 print ''
1236
1236
1237 handler = VerboseTB()
1237 handler = VerboseTB()
1238 print '*** VerboseTB ***'
1238 print '*** VerboseTB ***'
1239 try:
1239 try:
1240 print spam(1, (2, 3))
1240 print spam(1, (2, 3))
1241 except:
1241 except:
1242 handler(*sys.exc_info())
1242 handler(*sys.exc_info())
1243 print ''
1243 print ''
1244
1244
@@ -1,234 +1,234 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 %store magic for lightweight persistence.
3 %store magic for lightweight persistence.
4
4
5 Stores variables, aliases and macros in IPython's database.
5 Stores variables, aliases and macros in IPython's database.
6
6
7 To automatically restore stored variables at startup, add this to your
7 To automatically restore stored variables at startup, add this to your
8 :file:`ipython_config.py` file::
8 :file:`ipython_config.py` file::
9
9
10 c.StoreMagic.autorestore = True
10 c.StoreMagic.autorestore = True
11 """
11 """
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (c) 2012, The IPython Development Team.
13 # Copyright (c) 2012, The IPython Development Team.
14 #
14 #
15 # Distributed under the terms of the Modified BSD License.
15 # Distributed under the terms of the Modified BSD License.
16 #
16 #
17 # The full license is in the file COPYING.txt, distributed with this software.
17 # The full license is in the file COPYING.txt, distributed with this software.
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Imports
21 # Imports
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 # Stdlib
24 # Stdlib
25 import inspect, os, sys, textwrap
25 import inspect, os, sys, textwrap
26
26
27 # Our own
27 # Our own
28 from IPython.core.error import UsageError
28 from IPython.core.error import UsageError
29 from IPython.core.fakemodule import FakeModule
29 from IPython.core.fakemodule import FakeModule
30 from IPython.core.magic import Magics, magics_class, line_magic
30 from IPython.core.magic import Magics, magics_class, line_magic
31 from IPython.core.plugin import Plugin
31 from IPython.core.plugin import Plugin
32 from IPython.testing.skipdoctest import skip_doctest
32 from IPython.testing.skipdoctest import skip_doctest
33 from IPython.utils.traitlets import Bool, Instance
33 from IPython.utils.traitlets import Bool, Instance
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Functions and classes
36 # Functions and classes
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38
38
39 def restore_aliases(ip):
39 def restore_aliases(ip):
40 staliases = ip.db.get('stored_aliases', {})
40 staliases = ip.db.get('stored_aliases', {})
41 for k,v in staliases.items():
41 for k,v in staliases.items():
42 #print "restore alias",k,v # dbg
42 #print "restore alias",k,v # dbg
43 #self.alias_table[k] = v
43 #self.alias_table[k] = v
44 ip.alias_manager.define_alias(k,v)
44 ip.alias_manager.define_alias(k,v)
45
45
46
46
47 def refresh_variables(ip):
47 def refresh_variables(ip):
48 db = ip.db
48 db = ip.db
49 for key in db.keys('autorestore/*'):
49 for key in db.keys('autorestore/*'):
50 # strip autorestore
50 # strip autorestore
51 justkey = os.path.basename(key)
51 justkey = os.path.basename(key)
52 try:
52 try:
53 obj = db[key]
53 obj = db[key]
54 except KeyError:
54 except KeyError:
55 print "Unable to restore variable '%s', ignoring (use %%store -d to forget!)" % justkey
55 print "Unable to restore variable '%s', ignoring (use %%store -d to forget!)" % justkey
56 print "The error was:", sys.exc_info()[0]
56 print "The error was:", sys.exc_info()[0]
57 else:
57 else:
58 #print "restored",justkey,"=",obj #dbg
58 #print "restored",justkey,"=",obj #dbg
59 ip.user_ns[justkey] = obj
59 ip.user_ns[justkey] = obj
60
60
61
61
62 def restore_dhist(ip):
62 def restore_dhist(ip):
63 ip.user_ns['_dh'] = ip.db.get('dhist',[])
63 ip.user_ns['_dh'] = ip.db.get('dhist',[])
64
64
65
65
66 def restore_data(ip):
66 def restore_data(ip):
67 refresh_variables(ip)
67 refresh_variables(ip)
68 restore_aliases(ip)
68 restore_aliases(ip)
69 restore_dhist(ip)
69 restore_dhist(ip)
70
70
71
71
72 @magics_class
72 @magics_class
73 class StoreMagics(Magics):
73 class StoreMagics(Magics):
74 """Lightweight persistence for python variables.
74 """Lightweight persistence for python variables.
75
75
76 Provides the %store magic."""
76 Provides the %store magic."""
77
77
78 @skip_doctest
78 @skip_doctest
79 @line_magic
79 @line_magic
80 def store(self, parameter_s=''):
80 def store(self, parameter_s=''):
81 """Lightweight persistence for python variables.
81 """Lightweight persistence for python variables.
82
82
83 Example::
83 Example::
84
84
85 In [1]: l = ['hello',10,'world']
85 In [1]: l = ['hello',10,'world']
86 In [2]: %store l
86 In [2]: %store l
87 In [3]: exit
87 In [3]: exit
88
88
89 (IPython session is closed and started again...)
89 (IPython session is closed and started again...)
90
90
91 ville@badger:~$ ipython
91 ville@badger:~$ ipython
92 In [1]: l
92 In [1]: l
93 Out[1]: ['hello', 10, 'world']
93 Out[1]: ['hello', 10, 'world']
94
94
95 Usage:
95 Usage:
96
96
97 * ``%store`` - Show list of all variables and their current
97 * ``%store`` - Show list of all variables and their current
98 values
98 values
99 * ``%store spam`` - Store the *current* value of the variable spam
99 * ``%store spam`` - Store the *current* value of the variable spam
100 to disk
100 to disk
101 * ``%store -d spam`` - Remove the variable and its value from storage
101 * ``%store -d spam`` - Remove the variable and its value from storage
102 * ``%store -z`` - Remove all variables from storage
102 * ``%store -z`` - Remove all variables from storage
103 * ``%store -r`` - Refresh all variables from store (delete
103 * ``%store -r`` - Refresh all variables from store (delete
104 current vals)
104 current vals)
105 * ``%store foo >a.txt`` - Store value of foo to new file a.txt
105 * ``%store foo >a.txt`` - Store value of foo to new file a.txt
106 * ``%store foo >>a.txt`` - Append value of foo to file a.txt
106 * ``%store foo >>a.txt`` - Append value of foo to file a.txt
107
107
108 It should be noted that if you change the value of a variable, you
108 It should be noted that if you change the value of a variable, you
109 need to %store it again if you want to persist the new value.
109 need to %store it again if you want to persist the new value.
110
110
111 Note also that the variables will need to be pickleable; most basic
111 Note also that the variables will need to be pickleable; most basic
112 python types can be safely %store'd.
112 python types can be safely %store'd.
113
113
114 Also aliases can be %store'd across sessions.
114 Also aliases can be %store'd across sessions.
115 """
115 """
116
116
117 opts,argsl = self.parse_options(parameter_s,'drz',mode='string')
117 opts,argsl = self.parse_options(parameter_s,'drz',mode='string')
118 args = argsl.split(None,1)
118 args = argsl.split(None,1)
119 ip = self.shell
119 ip = self.shell
120 db = ip.db
120 db = ip.db
121 # delete
121 # delete
122 if opts.has_key('d'):
122 if 'd' in opts:
123 try:
123 try:
124 todel = args[0]
124 todel = args[0]
125 except IndexError:
125 except IndexError:
126 raise UsageError('You must provide the variable to forget')
126 raise UsageError('You must provide the variable to forget')
127 else:
127 else:
128 try:
128 try:
129 del db['autorestore/' + todel]
129 del db['autorestore/' + todel]
130 except:
130 except:
131 raise UsageError("Can't delete variable '%s'" % todel)
131 raise UsageError("Can't delete variable '%s'" % todel)
132 # reset
132 # reset
133 elif opts.has_key('z'):
133 elif 'z' in opts:
134 for k in db.keys('autorestore/*'):
134 for k in db.keys('autorestore/*'):
135 del db[k]
135 del db[k]
136
136
137 elif opts.has_key('r'):
137 elif 'r' in opts:
138 refresh_variables(ip)
138 refresh_variables(ip)
139
139
140
140
141 # run without arguments -> list variables & values
141 # run without arguments -> list variables & values
142 elif not args:
142 elif not args:
143 vars = self.db.keys('autorestore/*')
143 vars = self.db.keys('autorestore/*')
144 vars.sort()
144 vars.sort()
145 if vars:
145 if vars:
146 size = max(map(len, vars))
146 size = max(map(len, vars))
147 else:
147 else:
148 size = 0
148 size = 0
149
149
150 print 'Stored variables and their in-db values:'
150 print 'Stored variables and their in-db values:'
151 fmt = '%-'+str(size)+'s -> %s'
151 fmt = '%-'+str(size)+'s -> %s'
152 get = db.get
152 get = db.get
153 for var in vars:
153 for var in vars:
154 justkey = os.path.basename(var)
154 justkey = os.path.basename(var)
155 # print 30 first characters from every var
155 # print 30 first characters from every var
156 print fmt % (justkey, repr(get(var, '<unavailable>'))[:50])
156 print fmt % (justkey, repr(get(var, '<unavailable>'))[:50])
157
157
158 # default action - store the variable
158 # default action - store the variable
159 else:
159 else:
160 # %store foo >file.txt or >>file.txt
160 # %store foo >file.txt or >>file.txt
161 if len(args) > 1 and args[1].startswith('>'):
161 if len(args) > 1 and args[1].startswith('>'):
162 fnam = os.path.expanduser(args[1].lstrip('>').lstrip())
162 fnam = os.path.expanduser(args[1].lstrip('>').lstrip())
163 if args[1].startswith('>>'):
163 if args[1].startswith('>>'):
164 fil = open(fnam, 'a')
164 fil = open(fnam, 'a')
165 else:
165 else:
166 fil = open(fnam, 'w')
166 fil = open(fnam, 'w')
167 obj = ip.ev(args[0])
167 obj = ip.ev(args[0])
168 print "Writing '%s' (%s) to file '%s'." % (args[0],
168 print "Writing '%s' (%s) to file '%s'." % (args[0],
169 obj.__class__.__name__, fnam)
169 obj.__class__.__name__, fnam)
170
170
171
171
172 if not isinstance (obj, basestring):
172 if not isinstance (obj, basestring):
173 from pprint import pprint
173 from pprint import pprint
174 pprint(obj, fil)
174 pprint(obj, fil)
175 else:
175 else:
176 fil.write(obj)
176 fil.write(obj)
177 if not obj.endswith('\n'):
177 if not obj.endswith('\n'):
178 fil.write('\n')
178 fil.write('\n')
179
179
180 fil.close()
180 fil.close()
181 return
181 return
182
182
183 # %store foo
183 # %store foo
184 try:
184 try:
185 obj = ip.user_ns[args[0]]
185 obj = ip.user_ns[args[0]]
186 except KeyError:
186 except KeyError:
187 # it might be an alias
187 # it might be an alias
188 # This needs to be refactored to use the new AliasManager stuff.
188 # This needs to be refactored to use the new AliasManager stuff.
189 if args[0] in self.alias_manager:
189 if args[0] in self.alias_manager:
190 name = args[0]
190 name = args[0]
191 nargs, cmd = self.alias_manager.alias_table[ name ]
191 nargs, cmd = self.alias_manager.alias_table[ name ]
192 staliases = db.get('stored_aliases',{})
192 staliases = db.get('stored_aliases',{})
193 staliases[ name ] = cmd
193 staliases[ name ] = cmd
194 db['stored_aliases'] = staliases
194 db['stored_aliases'] = staliases
195 print "Alias stored: %s (%s)" % (name, cmd)
195 print "Alias stored: %s (%s)" % (name, cmd)
196 return
196 return
197 else:
197 else:
198 raise UsageError("Unknown variable '%s'" % args[0])
198 raise UsageError("Unknown variable '%s'" % args[0])
199
199
200 else:
200 else:
201 if isinstance(inspect.getmodule(obj), FakeModule):
201 if isinstance(inspect.getmodule(obj), FakeModule):
202 print textwrap.dedent("""\
202 print textwrap.dedent("""\
203 Warning:%s is %s
203 Warning:%s is %s
204 Proper storage of interactively declared classes (or instances
204 Proper storage of interactively declared classes (or instances
205 of those classes) is not possible! Only instances
205 of those classes) is not possible! Only instances
206 of classes in real modules on file system can be %%store'd.
206 of classes in real modules on file system can be %%store'd.
207 """ % (args[0], obj) )
207 """ % (args[0], obj) )
208 return
208 return
209 #pickled = pickle.dumps(obj)
209 #pickled = pickle.dumps(obj)
210 self.db[ 'autorestore/' + args[0] ] = obj
210 self.db[ 'autorestore/' + args[0] ] = obj
211 print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__)
211 print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__)
212
212
213
213
214 class StoreMagic(Plugin):
214 class StoreMagic(Plugin):
215 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
215 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
216 autorestore = Bool(False, config=True)
216 autorestore = Bool(False, config=True)
217
217
218 def __init__(self, shell, config):
218 def __init__(self, shell, config):
219 super(StoreMagic, self).__init__(shell=shell, config=config)
219 super(StoreMagic, self).__init__(shell=shell, config=config)
220 shell.register_magics(StoreMagics)
220 shell.register_magics(StoreMagics)
221
221
222 if self.autorestore:
222 if self.autorestore:
223 restore_data(shell)
223 restore_data(shell)
224
224
225
225
226 _loaded = False
226 _loaded = False
227
227
228 def load_ipython_extension(ip):
228 def load_ipython_extension(ip):
229 """Load the extension in IPython."""
229 """Load the extension in IPython."""
230 global _loaded
230 global _loaded
231 if not _loaded:
231 if not _loaded:
232 plugin = StoreMagic(shell=ip, config=ip.config)
232 plugin = StoreMagic(shell=ip, config=ip.config)
233 ip.plugin_manager.register_plugin('storemagic', plugin)
233 ip.plugin_manager.register_plugin('storemagic', plugin)
234 _loaded = True
234 _loaded = True
@@ -1,1903 +1,1903 b''
1 """Pexpect is a Python module for spawning child applications and controlling
1 """Pexpect is a Python module for spawning child applications and controlling
2 them automatically. Pexpect can be used for automating interactive applications
2 them automatically. Pexpect can be used for automating interactive applications
3 such as ssh, ftp, passwd, telnet, etc. It can be used to a automate setup
3 such as ssh, ftp, passwd, telnet, etc. It can be used to a automate setup
4 scripts for duplicating software package installations on different servers. It
4 scripts for duplicating software package installations on different servers. It
5 can be used for automated software testing. Pexpect is in the spirit of Don
5 can be used for automated software testing. Pexpect is in the spirit of Don
6 Libes' Expect, but Pexpect is pure Python. Other Expect-like modules for Python
6 Libes' Expect, but Pexpect is pure Python. Other Expect-like modules for Python
7 require TCL and Expect or require C extensions to be compiled. Pexpect does not
7 require TCL and Expect or require C extensions to be compiled. Pexpect does not
8 use C, Expect, or TCL extensions. It should work on any platform that supports
8 use C, Expect, or TCL extensions. It should work on any platform that supports
9 the standard Python pty module. The Pexpect interface focuses on ease of use so
9 the standard Python pty module. The Pexpect interface focuses on ease of use so
10 that simple tasks are easy.
10 that simple tasks are easy.
11
11
12 There are two main interfaces to the Pexpect system; these are the function,
12 There are two main interfaces to the Pexpect system; these are the function,
13 run() and the class, spawn. The spawn class is more powerful. The run()
13 run() and the class, spawn. The spawn class is more powerful. The run()
14 function is simpler than spawn, and is good for quickly calling program. When
14 function is simpler than spawn, and is good for quickly calling program. When
15 you call the run() function it executes a given program and then returns the
15 you call the run() function it executes a given program and then returns the
16 output. This is a handy replacement for os.system().
16 output. This is a handy replacement for os.system().
17
17
18 For example::
18 For example::
19
19
20 pexpect.run('ls -la')
20 pexpect.run('ls -la')
21
21
22 The spawn class is the more powerful interface to the Pexpect system. You can
22 The spawn class is the more powerful interface to the Pexpect system. You can
23 use this to spawn a child program then interact with it by sending input and
23 use this to spawn a child program then interact with it by sending input and
24 expecting responses (waiting for patterns in the child's output).
24 expecting responses (waiting for patterns in the child's output).
25
25
26 For example::
26 For example::
27
27
28 child = pexpect.spawn('scp foo myname@host.example.com:.')
28 child = pexpect.spawn('scp foo myname@host.example.com:.')
29 child.expect ('Password:')
29 child.expect ('Password:')
30 child.sendline (mypassword)
30 child.sendline (mypassword)
31
31
32 This works even for commands that ask for passwords or other input outside of
32 This works even for commands that ask for passwords or other input outside of
33 the normal stdio streams. For example, ssh reads input directly from the TTY
33 the normal stdio streams. For example, ssh reads input directly from the TTY
34 device which bypasses stdin.
34 device which bypasses stdin.
35
35
36 Credits: Noah Spurrier, Richard Holden, Marco Molteni, Kimberley Burchett,
36 Credits: Noah Spurrier, Richard Holden, Marco Molteni, Kimberley Burchett,
37 Robert Stone, Hartmut Goebel, Chad Schroeder, Erick Tryzelaar, Dave Kirby, Ids
37 Robert Stone, Hartmut Goebel, Chad Schroeder, Erick Tryzelaar, Dave Kirby, Ids
38 vander Molen, George Todd, Noel Taylor, Nicolas D. Cesar, Alexander Gattin,
38 vander Molen, George Todd, Noel Taylor, Nicolas D. Cesar, Alexander Gattin,
39 Jacques-Etienne Baudoux, Geoffrey Marshall, Francisco Lourenco, Glen Mabey,
39 Jacques-Etienne Baudoux, Geoffrey Marshall, Francisco Lourenco, Glen Mabey,
40 Karthik Gurusamy, Fernando Perez, Corey Minyard, Jon Cohen, Guillaume
40 Karthik Gurusamy, Fernando Perez, Corey Minyard, Jon Cohen, Guillaume
41 Chazarain, Andrew Ryan, Nick Craig-Wood, Andrew Stone, Jorgen Grahn, John
41 Chazarain, Andrew Ryan, Nick Craig-Wood, Andrew Stone, Jorgen Grahn, John
42 Spiegel, Jan Grant, Shane Kerr and Thomas Kluyver. Let me know if I forgot anyone.
42 Spiegel, Jan Grant, Shane Kerr and Thomas Kluyver. Let me know if I forgot anyone.
43
43
44 Pexpect is free, open source, and all that good stuff.
44 Pexpect is free, open source, and all that good stuff.
45
45
46 Permission is hereby granted, free of charge, to any person obtaining a copy of
46 Permission is hereby granted, free of charge, to any person obtaining a copy of
47 this software and associated documentation files (the "Software"), to deal in
47 this software and associated documentation files (the "Software"), to deal in
48 the Software without restriction, including without limitation the rights to
48 the Software without restriction, including without limitation the rights to
49 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
49 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
50 of the Software, and to permit persons to whom the Software is furnished to do
50 of the Software, and to permit persons to whom the Software is furnished to do
51 so, subject to the following conditions:
51 so, subject to the following conditions:
52
52
53 The above copyright notice and this permission notice shall be included in all
53 The above copyright notice and this permission notice shall be included in all
54 copies or substantial portions of the Software.
54 copies or substantial portions of the Software.
55
55
56 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
56 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
57 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
57 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
58 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
58 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
59 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
59 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
60 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
60 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
61 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
61 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
62 SOFTWARE.
62 SOFTWARE.
63
63
64 Pexpect Copyright (c) 2008-2011 Noah Spurrier
64 Pexpect Copyright (c) 2008-2011 Noah Spurrier
65 http://pexpect.sourceforge.net/
65 http://pexpect.sourceforge.net/
66 """
66 """
67
67
68 try:
68 try:
69 import os, sys, time
69 import os, sys, time
70 import select
70 import select
71 import re
71 import re
72 import struct
72 import struct
73 import resource
73 import resource
74 import types
74 import types
75 import pty
75 import pty
76 import tty
76 import tty
77 import termios
77 import termios
78 import fcntl
78 import fcntl
79 import errno
79 import errno
80 import traceback
80 import traceback
81 import signal
81 import signal
82 except ImportError as e:
82 except ImportError as e:
83 raise ImportError (str(e) + """
83 raise ImportError (str(e) + """
84
84
85 A critical module was not found. Probably this operating system does not
85 A critical module was not found. Probably this operating system does not
86 support it. Pexpect is intended for UNIX-like operating systems.""")
86 support it. Pexpect is intended for UNIX-like operating systems.""")
87
87
88 __version__ = '2.6.dev'
88 __version__ = '2.6.dev'
89 version = __version__
89 version = __version__
90 version_info = (2,6,'dev')
90 version_info = (2,6,'dev')
91 __all__ = ['ExceptionPexpect', 'EOF', 'TIMEOUT', 'spawn', 'spawnb', 'run', 'which',
91 __all__ = ['ExceptionPexpect', 'EOF', 'TIMEOUT', 'spawn', 'spawnb', 'run', 'which',
92 'split_command_line', '__version__']
92 'split_command_line', '__version__']
93
93
94 # Exception classes used by this module.
94 # Exception classes used by this module.
95 class ExceptionPexpect(Exception):
95 class ExceptionPexpect(Exception):
96
96
97 """Base class for all exceptions raised by this module.
97 """Base class for all exceptions raised by this module.
98 """
98 """
99
99
100 def __init__(self, value):
100 def __init__(self, value):
101
101
102 self.value = value
102 self.value = value
103
103
104 def __str__(self):
104 def __str__(self):
105
105
106 return str(self.value)
106 return str(self.value)
107
107
108 def get_trace(self):
108 def get_trace(self):
109
109
110 """This returns an abbreviated stack trace with lines that only concern
110 """This returns an abbreviated stack trace with lines that only concern
111 the caller. In other words, the stack trace inside the Pexpect module
111 the caller. In other words, the stack trace inside the Pexpect module
112 is not included. """
112 is not included. """
113
113
114 tblist = traceback.extract_tb(sys.exc_info()[2])
114 tblist = traceback.extract_tb(sys.exc_info()[2])
115 #tblist = filter(self.__filter_not_pexpect, tblist)
115 #tblist = filter(self.__filter_not_pexpect, tblist)
116 tblist = [item for item in tblist if self.__filter_not_pexpect(item)]
116 tblist = [item for item in tblist if self.__filter_not_pexpect(item)]
117 tblist = traceback.format_list(tblist)
117 tblist = traceback.format_list(tblist)
118 return ''.join(tblist)
118 return ''.join(tblist)
119
119
120 def __filter_not_pexpect(self, trace_list_item):
120 def __filter_not_pexpect(self, trace_list_item):
121
121
122 """This returns True if list item 0 the string 'pexpect.py' in it. """
122 """This returns True if list item 0 the string 'pexpect.py' in it. """
123
123
124 if trace_list_item[0].find('pexpect.py') == -1:
124 if trace_list_item[0].find('pexpect.py') == -1:
125 return True
125 return True
126 else:
126 else:
127 return False
127 return False
128
128
129 class EOF(ExceptionPexpect):
129 class EOF(ExceptionPexpect):
130
130
131 """Raised when EOF is read from a child. This usually means the child has exited."""
131 """Raised when EOF is read from a child. This usually means the child has exited."""
132
132
133 class TIMEOUT(ExceptionPexpect):
133 class TIMEOUT(ExceptionPexpect):
134
134
135 """Raised when a read time exceeds the timeout. """
135 """Raised when a read time exceeds the timeout. """
136
136
137 ##class TIMEOUT_PATTERN(TIMEOUT):
137 ##class TIMEOUT_PATTERN(TIMEOUT):
138 ## """Raised when the pattern match time exceeds the timeout.
138 ## """Raised when the pattern match time exceeds the timeout.
139 ## This is different than a read TIMEOUT because the child process may
139 ## This is different than a read TIMEOUT because the child process may
140 ## give output, thus never give a TIMEOUT, but the output
140 ## give output, thus never give a TIMEOUT, but the output
141 ## may never match a pattern.
141 ## may never match a pattern.
142 ## """
142 ## """
143 ##class MAXBUFFER(ExceptionPexpect):
143 ##class MAXBUFFER(ExceptionPexpect):
144 ## """Raised when a scan buffer fills before matching an expected pattern."""
144 ## """Raised when a scan buffer fills before matching an expected pattern."""
145
145
146 PY3 = (sys.version_info[0] >= 3)
146 PY3 = (sys.version_info[0] >= 3)
147
147
148 def _cast_bytes(s, enc):
148 def _cast_bytes(s, enc):
149 if isinstance(s, unicode):
149 if isinstance(s, unicode):
150 return s.encode(enc)
150 return s.encode(enc)
151 return s
151 return s
152
152
153 def _cast_unicode(s, enc):
153 def _cast_unicode(s, enc):
154 if isinstance(s, bytes):
154 if isinstance(s, bytes):
155 return s.decode(enc)
155 return s.decode(enc)
156 return s
156 return s
157
157
158 re_type = type(re.compile(''))
158 re_type = type(re.compile(''))
159
159
160 def run (command, timeout=-1, withexitstatus=False, events=None, extra_args=None,
160 def run (command, timeout=-1, withexitstatus=False, events=None, extra_args=None,
161 logfile=None, cwd=None, env=None, encoding='utf-8'):
161 logfile=None, cwd=None, env=None, encoding='utf-8'):
162
162
163 """
163 """
164 This function runs the given command; waits for it to finish; then
164 This function runs the given command; waits for it to finish; then
165 returns all output as a string. STDERR is included in output. If the full
165 returns all output as a string. STDERR is included in output. If the full
166 path to the command is not given then the path is searched.
166 path to the command is not given then the path is searched.
167
167
168 Note that lines are terminated by CR/LF (\\r\\n) combination even on
168 Note that lines are terminated by CR/LF (\\r\\n) combination even on
169 UNIX-like systems because this is the standard for pseudo ttys. If you set
169 UNIX-like systems because this is the standard for pseudo ttys. If you set
170 'withexitstatus' to true, then run will return a tuple of (command_output,
170 'withexitstatus' to true, then run will return a tuple of (command_output,
171 exitstatus). If 'withexitstatus' is false then this returns just
171 exitstatus). If 'withexitstatus' is false then this returns just
172 command_output.
172 command_output.
173
173
174 The run() function can often be used instead of creating a spawn instance.
174 The run() function can often be used instead of creating a spawn instance.
175 For example, the following code uses spawn::
175 For example, the following code uses spawn::
176
176
177 from pexpect import *
177 from pexpect import *
178 child = spawn('scp foo myname@host.example.com:.')
178 child = spawn('scp foo myname@host.example.com:.')
179 child.expect ('(?i)password')
179 child.expect ('(?i)password')
180 child.sendline (mypassword)
180 child.sendline (mypassword)
181
181
182 The previous code can be replace with the following::
182 The previous code can be replace with the following::
183
183
184 from pexpect import *
184 from pexpect import *
185 run ('scp foo myname@host.example.com:.', events={'(?i)password': mypassword})
185 run ('scp foo myname@host.example.com:.', events={'(?i)password': mypassword})
186
186
187 Examples
187 Examples
188 ========
188 ========
189
189
190 Start the apache daemon on the local machine::
190 Start the apache daemon on the local machine::
191
191
192 from pexpect import *
192 from pexpect import *
193 run ("/usr/local/apache/bin/apachectl start")
193 run ("/usr/local/apache/bin/apachectl start")
194
194
195 Check in a file using SVN::
195 Check in a file using SVN::
196
196
197 from pexpect import *
197 from pexpect import *
198 run ("svn ci -m 'automatic commit' my_file.py")
198 run ("svn ci -m 'automatic commit' my_file.py")
199
199
200 Run a command and capture exit status::
200 Run a command and capture exit status::
201
201
202 from pexpect import *
202 from pexpect import *
203 (command_output, exitstatus) = run ('ls -l /bin', withexitstatus=1)
203 (command_output, exitstatus) = run ('ls -l /bin', withexitstatus=1)
204
204
205 Tricky Examples
205 Tricky Examples
206 ===============
206 ===============
207
207
208 The following will run SSH and execute 'ls -l' on the remote machine. The
208 The following will run SSH and execute 'ls -l' on the remote machine. The
209 password 'secret' will be sent if the '(?i)password' pattern is ever seen::
209 password 'secret' will be sent if the '(?i)password' pattern is ever seen::
210
210
211 run ("ssh username@machine.example.com 'ls -l'", events={'(?i)password':'secret\\n'})
211 run ("ssh username@machine.example.com 'ls -l'", events={'(?i)password':'secret\\n'})
212
212
213 This will start mencoder to rip a video from DVD. This will also display
213 This will start mencoder to rip a video from DVD. This will also display
214 progress ticks every 5 seconds as it runs. For example::
214 progress ticks every 5 seconds as it runs. For example::
215
215
216 from pexpect import *
216 from pexpect import *
217 def print_ticks(d):
217 def print_ticks(d):
218 print d['event_count'],
218 print d['event_count'],
219 run ("mencoder dvd://1 -o video.avi -oac copy -ovc copy", events={TIMEOUT:print_ticks}, timeout=5)
219 run ("mencoder dvd://1 -o video.avi -oac copy -ovc copy", events={TIMEOUT:print_ticks}, timeout=5)
220
220
221 The 'events' argument should be a dictionary of patterns and responses.
221 The 'events' argument should be a dictionary of patterns and responses.
222 Whenever one of the patterns is seen in the command out run() will send the
222 Whenever one of the patterns is seen in the command out run() will send the
223 associated response string. Note that you should put newlines in your
223 associated response string. Note that you should put newlines in your
224 string if Enter is necessary. The responses may also contain callback
224 string if Enter is necessary. The responses may also contain callback
225 functions. Any callback is function that takes a dictionary as an argument.
225 functions. Any callback is function that takes a dictionary as an argument.
226 The dictionary contains all the locals from the run() function, so you can
226 The dictionary contains all the locals from the run() function, so you can
227 access the child spawn object or any other variable defined in run()
227 access the child spawn object or any other variable defined in run()
228 (event_count, child, and extra_args are the most useful). A callback may
228 (event_count, child, and extra_args are the most useful). A callback may
229 return True to stop the current run process otherwise run() continues until
229 return True to stop the current run process otherwise run() continues until
230 the next event. A callback may also return a string which will be sent to
230 the next event. A callback may also return a string which will be sent to
231 the child. 'extra_args' is not used by directly run(). It provides a way to
231 the child. 'extra_args' is not used by directly run(). It provides a way to
232 pass data to a callback function through run() through the locals
232 pass data to a callback function through run() through the locals
233 dictionary passed to a callback."""
233 dictionary passed to a callback."""
234
234
235 if timeout == -1:
235 if timeout == -1:
236 child = spawn(command, maxread=2000, logfile=logfile, cwd=cwd, env=env,
236 child = spawn(command, maxread=2000, logfile=logfile, cwd=cwd, env=env,
237 encoding=encoding)
237 encoding=encoding)
238 else:
238 else:
239 child = spawn(command, timeout=timeout, maxread=2000, logfile=logfile,
239 child = spawn(command, timeout=timeout, maxread=2000, logfile=logfile,
240 cwd=cwd, env=env, encoding=encoding)
240 cwd=cwd, env=env, encoding=encoding)
241 if events is not None:
241 if events is not None:
242 patterns = events.keys()
242 patterns = events.keys()
243 responses = events.values()
243 responses = events.values()
244 else:
244 else:
245 patterns=None # We assume that EOF or TIMEOUT will save us.
245 patterns=None # We assume that EOF or TIMEOUT will save us.
246 responses=None
246 responses=None
247 child_result_list = []
247 child_result_list = []
248 event_count = 0
248 event_count = 0
249 while 1:
249 while 1:
250 try:
250 try:
251 index = child.expect (patterns)
251 index = child.expect (patterns)
252 if isinstance(child.after, basestring):
252 if isinstance(child.after, basestring):
253 child_result_list.append(child.before + child.after)
253 child_result_list.append(child.before + child.after)
254 else: # child.after may have been a TIMEOUT or EOF, so don't cat those.
254 else: # child.after may have been a TIMEOUT or EOF, so don't cat those.
255 child_result_list.append(child.before)
255 child_result_list.append(child.before)
256 if isinstance(responses[index], basestring):
256 if isinstance(responses[index], basestring):
257 child.send(responses[index])
257 child.send(responses[index])
258 elif type(responses[index]) is types.FunctionType:
258 elif type(responses[index]) is types.FunctionType:
259 callback_result = responses[index](locals())
259 callback_result = responses[index](locals())
260 sys.stdout.flush()
260 sys.stdout.flush()
261 if isinstance(callback_result, basestring):
261 if isinstance(callback_result, basestring):
262 child.send(callback_result)
262 child.send(callback_result)
263 elif callback_result:
263 elif callback_result:
264 break
264 break
265 else:
265 else:
266 raise TypeError ('The callback must be a string or function type.')
266 raise TypeError ('The callback must be a string or function type.')
267 event_count = event_count + 1
267 event_count = event_count + 1
268 except TIMEOUT as e:
268 except TIMEOUT as e:
269 child_result_list.append(child.before)
269 child_result_list.append(child.before)
270 break
270 break
271 except EOF as e:
271 except EOF as e:
272 child_result_list.append(child.before)
272 child_result_list.append(child.before)
273 break
273 break
274 child_result = child._empty_buffer.join(child_result_list)
274 child_result = child._empty_buffer.join(child_result_list)
275 if withexitstatus:
275 if withexitstatus:
276 child.close()
276 child.close()
277 return (child_result, child.exitstatus)
277 return (child_result, child.exitstatus)
278 else:
278 else:
279 return child_result
279 return child_result
280
280
281 class spawnb(object):
281 class spawnb(object):
282 """Use this class to start and control child applications with a pure-bytes
282 """Use this class to start and control child applications with a pure-bytes
283 interface."""
283 interface."""
284
284
285 _buffer_type = bytes
285 _buffer_type = bytes
286 def _cast_buffer_type(self, s):
286 def _cast_buffer_type(self, s):
287 return _cast_bytes(s, self.encoding)
287 return _cast_bytes(s, self.encoding)
288 _empty_buffer = b''
288 _empty_buffer = b''
289 _pty_newline = b'\r\n'
289 _pty_newline = b'\r\n'
290
290
291 # Some code needs this to exist, but it's mainly for the spawn subclass.
291 # Some code needs this to exist, but it's mainly for the spawn subclass.
292 encoding = 'utf-8'
292 encoding = 'utf-8'
293
293
294 def __init__(self, command, args=[], timeout=30, maxread=2000, searchwindowsize=None,
294 def __init__(self, command, args=[], timeout=30, maxread=2000, searchwindowsize=None,
295 logfile=None, cwd=None, env=None):
295 logfile=None, cwd=None, env=None):
296
296
297 """This is the constructor. The command parameter may be a string that
297 """This is the constructor. The command parameter may be a string that
298 includes a command and any arguments to the command. For example::
298 includes a command and any arguments to the command. For example::
299
299
300 child = pexpect.spawn ('/usr/bin/ftp')
300 child = pexpect.spawn ('/usr/bin/ftp')
301 child = pexpect.spawn ('/usr/bin/ssh user@example.com')
301 child = pexpect.spawn ('/usr/bin/ssh user@example.com')
302 child = pexpect.spawn ('ls -latr /tmp')
302 child = pexpect.spawn ('ls -latr /tmp')
303
303
304 You may also construct it with a list of arguments like so::
304 You may also construct it with a list of arguments like so::
305
305
306 child = pexpect.spawn ('/usr/bin/ftp', [])
306 child = pexpect.spawn ('/usr/bin/ftp', [])
307 child = pexpect.spawn ('/usr/bin/ssh', ['user@example.com'])
307 child = pexpect.spawn ('/usr/bin/ssh', ['user@example.com'])
308 child = pexpect.spawn ('ls', ['-latr', '/tmp'])
308 child = pexpect.spawn ('ls', ['-latr', '/tmp'])
309
309
310 After this the child application will be created and will be ready to
310 After this the child application will be created and will be ready to
311 talk to. For normal use, see expect() and send() and sendline().
311 talk to. For normal use, see expect() and send() and sendline().
312
312
313 Remember that Pexpect does NOT interpret shell meta characters such as
313 Remember that Pexpect does NOT interpret shell meta characters such as
314 redirect, pipe, or wild cards (>, |, or *). This is a common mistake.
314 redirect, pipe, or wild cards (>, |, or *). This is a common mistake.
315 If you want to run a command and pipe it through another command then
315 If you want to run a command and pipe it through another command then
316 you must also start a shell. For example::
316 you must also start a shell. For example::
317
317
318 child = pexpect.spawn('/bin/bash -c "ls -l | grep LOG > log_list.txt"')
318 child = pexpect.spawn('/bin/bash -c "ls -l | grep LOG > log_list.txt"')
319 child.expect(pexpect.EOF)
319 child.expect(pexpect.EOF)
320
320
321 The second form of spawn (where you pass a list of arguments) is useful
321 The second form of spawn (where you pass a list of arguments) is useful
322 in situations where you wish to spawn a command and pass it its own
322 in situations where you wish to spawn a command and pass it its own
323 argument list. This can make syntax more clear. For example, the
323 argument list. This can make syntax more clear. For example, the
324 following is equivalent to the previous example::
324 following is equivalent to the previous example::
325
325
326 shell_cmd = 'ls -l | grep LOG > log_list.txt'
326 shell_cmd = 'ls -l | grep LOG > log_list.txt'
327 child = pexpect.spawn('/bin/bash', ['-c', shell_cmd])
327 child = pexpect.spawn('/bin/bash', ['-c', shell_cmd])
328 child.expect(pexpect.EOF)
328 child.expect(pexpect.EOF)
329
329
330 The maxread attribute sets the read buffer size. This is maximum number
330 The maxread attribute sets the read buffer size. This is maximum number
331 of bytes that Pexpect will try to read from a TTY at one time. Setting
331 of bytes that Pexpect will try to read from a TTY at one time. Setting
332 the maxread size to 1 will turn off buffering. Setting the maxread
332 the maxread size to 1 will turn off buffering. Setting the maxread
333 value higher may help performance in cases where large amounts of
333 value higher may help performance in cases where large amounts of
334 output are read back from the child. This feature is useful in
334 output are read back from the child. This feature is useful in
335 conjunction with searchwindowsize.
335 conjunction with searchwindowsize.
336
336
337 The searchwindowsize attribute sets the how far back in the incomming
337 The searchwindowsize attribute sets the how far back in the incomming
338 seach buffer Pexpect will search for pattern matches. Every time
338 seach buffer Pexpect will search for pattern matches. Every time
339 Pexpect reads some data from the child it will append the data to the
339 Pexpect reads some data from the child it will append the data to the
340 incomming buffer. The default is to search from the beginning of the
340 incomming buffer. The default is to search from the beginning of the
341 imcomming buffer each time new data is read from the child. But this is
341 imcomming buffer each time new data is read from the child. But this is
342 very inefficient if you are running a command that generates a large
342 very inefficient if you are running a command that generates a large
343 amount of data where you want to match The searchwindowsize does not
343 amount of data where you want to match The searchwindowsize does not
344 effect the size of the incomming data buffer. You will still have
344 effect the size of the incomming data buffer. You will still have
345 access to the full buffer after expect() returns.
345 access to the full buffer after expect() returns.
346
346
347 The logfile member turns on or off logging. All input and output will
347 The logfile member turns on or off logging. All input and output will
348 be copied to the given file object. Set logfile to None to stop
348 be copied to the given file object. Set logfile to None to stop
349 logging. This is the default. Set logfile to sys.stdout to echo
349 logging. This is the default. Set logfile to sys.stdout to echo
350 everything to standard output. The logfile is flushed after each write.
350 everything to standard output. The logfile is flushed after each write.
351
351
352 Example log input and output to a file::
352 Example log input and output to a file::
353
353
354 child = pexpect.spawn('some_command')
354 child = pexpect.spawn('some_command')
355 fout = open('mylog.txt','w')
355 fout = open('mylog.txt','w')
356 child.logfile = fout
356 child.logfile = fout
357
357
358 Example log to stdout::
358 Example log to stdout::
359
359
360 child = pexpect.spawn('some_command')
360 child = pexpect.spawn('some_command')
361 child.logfile = sys.stdout
361 child.logfile = sys.stdout
362
362
363 The logfile_read and logfile_send members can be used to separately log
363 The logfile_read and logfile_send members can be used to separately log
364 the input from the child and output sent to the child. Sometimes you
364 the input from the child and output sent to the child. Sometimes you
365 don't want to see everything you write to the child. You only want to
365 don't want to see everything you write to the child. You only want to
366 log what the child sends back. For example::
366 log what the child sends back. For example::
367
367
368 child = pexpect.spawn('some_command')
368 child = pexpect.spawn('some_command')
369 child.logfile_read = sys.stdout
369 child.logfile_read = sys.stdout
370
370
371 To separately log output sent to the child use logfile_send::
371 To separately log output sent to the child use logfile_send::
372
372
373 self.logfile_send = fout
373 self.logfile_send = fout
374
374
375 The delaybeforesend helps overcome a weird behavior that many users
375 The delaybeforesend helps overcome a weird behavior that many users
376 were experiencing. The typical problem was that a user would expect() a
376 were experiencing. The typical problem was that a user would expect() a
377 "Password:" prompt and then immediately call sendline() to send the
377 "Password:" prompt and then immediately call sendline() to send the
378 password. The user would then see that their password was echoed back
378 password. The user would then see that their password was echoed back
379 to them. Passwords don't normally echo. The problem is caused by the
379 to them. Passwords don't normally echo. The problem is caused by the
380 fact that most applications print out the "Password" prompt and then
380 fact that most applications print out the "Password" prompt and then
381 turn off stdin echo, but if you send your password before the
381 turn off stdin echo, but if you send your password before the
382 application turned off echo, then you get your password echoed.
382 application turned off echo, then you get your password echoed.
383 Normally this wouldn't be a problem when interacting with a human at a
383 Normally this wouldn't be a problem when interacting with a human at a
384 real keyboard. If you introduce a slight delay just before writing then
384 real keyboard. If you introduce a slight delay just before writing then
385 this seems to clear up the problem. This was such a common problem for
385 this seems to clear up the problem. This was such a common problem for
386 many users that I decided that the default pexpect behavior should be
386 many users that I decided that the default pexpect behavior should be
387 to sleep just before writing to the child application. 1/20th of a
387 to sleep just before writing to the child application. 1/20th of a
388 second (50 ms) seems to be enough to clear up the problem. You can set
388 second (50 ms) seems to be enough to clear up the problem. You can set
389 delaybeforesend to 0 to return to the old behavior. Most Linux machines
389 delaybeforesend to 0 to return to the old behavior. Most Linux machines
390 don't like this to be below 0.03. I don't know why.
390 don't like this to be below 0.03. I don't know why.
391
391
392 Note that spawn is clever about finding commands on your path.
392 Note that spawn is clever about finding commands on your path.
393 It uses the same logic that "which" uses to find executables.
393 It uses the same logic that "which" uses to find executables.
394
394
395 If you wish to get the exit status of the child you must call the
395 If you wish to get the exit status of the child you must call the
396 close() method. The exit or signal status of the child will be stored
396 close() method. The exit or signal status of the child will be stored
397 in self.exitstatus or self.signalstatus. If the child exited normally
397 in self.exitstatus or self.signalstatus. If the child exited normally
398 then exitstatus will store the exit return code and signalstatus will
398 then exitstatus will store the exit return code and signalstatus will
399 be None. If the child was terminated abnormally with a signal then
399 be None. If the child was terminated abnormally with a signal then
400 signalstatus will store the signal value and exitstatus will be None.
400 signalstatus will store the signal value and exitstatus will be None.
401 If you need more detail you can also read the self.status member which
401 If you need more detail you can also read the self.status member which
402 stores the status returned by os.waitpid. You can interpret this using
402 stores the status returned by os.waitpid. You can interpret this using
403 os.WIFEXITED/os.WEXITSTATUS or os.WIFSIGNALED/os.TERMSIG. """
403 os.WIFEXITED/os.WEXITSTATUS or os.WIFSIGNALED/os.TERMSIG. """
404
404
405 self.STDIN_FILENO = pty.STDIN_FILENO
405 self.STDIN_FILENO = pty.STDIN_FILENO
406 self.STDOUT_FILENO = pty.STDOUT_FILENO
406 self.STDOUT_FILENO = pty.STDOUT_FILENO
407 self.STDERR_FILENO = pty.STDERR_FILENO
407 self.STDERR_FILENO = pty.STDERR_FILENO
408 self.stdin = sys.stdin
408 self.stdin = sys.stdin
409 self.stdout = sys.stdout
409 self.stdout = sys.stdout
410 self.stderr = sys.stderr
410 self.stderr = sys.stderr
411
411
412 self.searcher = None
412 self.searcher = None
413 self.ignorecase = False
413 self.ignorecase = False
414 self.before = None
414 self.before = None
415 self.after = None
415 self.after = None
416 self.match = None
416 self.match = None
417 self.match_index = None
417 self.match_index = None
418 self.terminated = True
418 self.terminated = True
419 self.exitstatus = None
419 self.exitstatus = None
420 self.signalstatus = None
420 self.signalstatus = None
421 self.status = None # status returned by os.waitpid
421 self.status = None # status returned by os.waitpid
422 self.flag_eof = False
422 self.flag_eof = False
423 self.pid = None
423 self.pid = None
424 self.child_fd = -1 # initially closed
424 self.child_fd = -1 # initially closed
425 self.timeout = timeout
425 self.timeout = timeout
426 self.delimiter = EOF
426 self.delimiter = EOF
427 self.logfile = logfile
427 self.logfile = logfile
428 self.logfile_read = None # input from child (read_nonblocking)
428 self.logfile_read = None # input from child (read_nonblocking)
429 self.logfile_send = None # output to send (send, sendline)
429 self.logfile_send = None # output to send (send, sendline)
430 self.maxread = maxread # max bytes to read at one time into buffer
430 self.maxread = maxread # max bytes to read at one time into buffer
431 self.buffer = self._empty_buffer # This is the read buffer. See maxread.
431 self.buffer = self._empty_buffer # This is the read buffer. See maxread.
432 self.searchwindowsize = searchwindowsize # Anything before searchwindowsize point is preserved, but not searched.
432 self.searchwindowsize = searchwindowsize # Anything before searchwindowsize point is preserved, but not searched.
433 # Most Linux machines don't like delaybeforesend to be below 0.03 (30 ms).
433 # Most Linux machines don't like delaybeforesend to be below 0.03 (30 ms).
434 self.delaybeforesend = 0.05 # Sets sleep time used just before sending data to child. Time in seconds.
434 self.delaybeforesend = 0.05 # Sets sleep time used just before sending data to child. Time in seconds.
435 self.delayafterclose = 0.1 # Sets delay in close() method to allow kernel time to update process status. Time in seconds.
435 self.delayafterclose = 0.1 # Sets delay in close() method to allow kernel time to update process status. Time in seconds.
436 self.delayafterterminate = 0.1 # Sets delay in terminate() method to allow kernel time to update process status. Time in seconds.
436 self.delayafterterminate = 0.1 # Sets delay in terminate() method to allow kernel time to update process status. Time in seconds.
437 self.softspace = False # File-like object.
437 self.softspace = False # File-like object.
438 self.name = '<' + repr(self) + '>' # File-like object.
438 self.name = '<' + repr(self) + '>' # File-like object.
439 self.closed = True # File-like object.
439 self.closed = True # File-like object.
440 self.cwd = cwd
440 self.cwd = cwd
441 self.env = env
441 self.env = env
442 self.__irix_hack = (sys.platform.lower().find('irix')>=0) # This flags if we are running on irix
442 self.__irix_hack = (sys.platform.lower().find('irix')>=0) # This flags if we are running on irix
443 # Solaris uses internal __fork_pty(). All others use pty.fork().
443 # Solaris uses internal __fork_pty(). All others use pty.fork().
444 if 'solaris' in sys.platform.lower() or 'sunos5' in sys.platform.lower():
444 if 'solaris' in sys.platform.lower() or 'sunos5' in sys.platform.lower():
445 self.use_native_pty_fork = False
445 self.use_native_pty_fork = False
446 else:
446 else:
447 self.use_native_pty_fork = True
447 self.use_native_pty_fork = True
448
448
449
449
450 # allow dummy instances for subclasses that may not use command or args.
450 # allow dummy instances for subclasses that may not use command or args.
451 if command is None:
451 if command is None:
452 self.command = None
452 self.command = None
453 self.args = None
453 self.args = None
454 self.name = '<pexpect factory incomplete>'
454 self.name = '<pexpect factory incomplete>'
455 else:
455 else:
456 self._spawn (command, args)
456 self._spawn (command, args)
457
457
458 def __del__(self):
458 def __del__(self):
459
459
460 """This makes sure that no system resources are left open. Python only
460 """This makes sure that no system resources are left open. Python only
461 garbage collects Python objects. OS file descriptors are not Python
461 garbage collects Python objects. OS file descriptors are not Python
462 objects, so they must be handled explicitly. If the child file
462 objects, so they must be handled explicitly. If the child file
463 descriptor was opened outside of this class (passed to the constructor)
463 descriptor was opened outside of this class (passed to the constructor)
464 then this does not close it. """
464 then this does not close it. """
465
465
466 if not self.closed:
466 if not self.closed:
467 # It is possible for __del__ methods to execute during the
467 # It is possible for __del__ methods to execute during the
468 # teardown of the Python VM itself. Thus self.close() may
468 # teardown of the Python VM itself. Thus self.close() may
469 # trigger an exception because os.close may be None.
469 # trigger an exception because os.close may be None.
470 # -- Fernando Perez
470 # -- Fernando Perez
471 try:
471 try:
472 self.close()
472 self.close()
473 except:
473 except:
474 pass
474 pass
475
475
476 def __str__(self):
476 def __str__(self):
477
477
478 """This returns a human-readable string that represents the state of
478 """This returns a human-readable string that represents the state of
479 the object. """
479 the object. """
480
480
481 s = []
481 s = []
482 s.append(repr(self))
482 s.append(repr(self))
483 s.append('version: ' + __version__)
483 s.append('version: ' + __version__)
484 s.append('command: ' + str(self.command))
484 s.append('command: ' + str(self.command))
485 s.append('args: ' + str(self.args))
485 s.append('args: ' + str(self.args))
486 s.append('searcher: ' + str(self.searcher))
486 s.append('searcher: ' + str(self.searcher))
487 s.append('buffer (last 100 chars): ' + str(self.buffer)[-100:])
487 s.append('buffer (last 100 chars): ' + str(self.buffer)[-100:])
488 s.append('before (last 100 chars): ' + str(self.before)[-100:])
488 s.append('before (last 100 chars): ' + str(self.before)[-100:])
489 s.append('after: ' + str(self.after))
489 s.append('after: ' + str(self.after))
490 s.append('match: ' + str(self.match))
490 s.append('match: ' + str(self.match))
491 s.append('match_index: ' + str(self.match_index))
491 s.append('match_index: ' + str(self.match_index))
492 s.append('exitstatus: ' + str(self.exitstatus))
492 s.append('exitstatus: ' + str(self.exitstatus))
493 s.append('flag_eof: ' + str(self.flag_eof))
493 s.append('flag_eof: ' + str(self.flag_eof))
494 s.append('pid: ' + str(self.pid))
494 s.append('pid: ' + str(self.pid))
495 s.append('child_fd: ' + str(self.child_fd))
495 s.append('child_fd: ' + str(self.child_fd))
496 s.append('closed: ' + str(self.closed))
496 s.append('closed: ' + str(self.closed))
497 s.append('timeout: ' + str(self.timeout))
497 s.append('timeout: ' + str(self.timeout))
498 s.append('delimiter: ' + str(self.delimiter))
498 s.append('delimiter: ' + str(self.delimiter))
499 s.append('logfile: ' + str(self.logfile))
499 s.append('logfile: ' + str(self.logfile))
500 s.append('logfile_read: ' + str(self.logfile_read))
500 s.append('logfile_read: ' + str(self.logfile_read))
501 s.append('logfile_send: ' + str(self.logfile_send))
501 s.append('logfile_send: ' + str(self.logfile_send))
502 s.append('maxread: ' + str(self.maxread))
502 s.append('maxread: ' + str(self.maxread))
503 s.append('ignorecase: ' + str(self.ignorecase))
503 s.append('ignorecase: ' + str(self.ignorecase))
504 s.append('searchwindowsize: ' + str(self.searchwindowsize))
504 s.append('searchwindowsize: ' + str(self.searchwindowsize))
505 s.append('delaybeforesend: ' + str(self.delaybeforesend))
505 s.append('delaybeforesend: ' + str(self.delaybeforesend))
506 s.append('delayafterclose: ' + str(self.delayafterclose))
506 s.append('delayafterclose: ' + str(self.delayafterclose))
507 s.append('delayafterterminate: ' + str(self.delayafterterminate))
507 s.append('delayafterterminate: ' + str(self.delayafterterminate))
508 return '\n'.join(s)
508 return '\n'.join(s)
509
509
510 def _spawn(self,command,args=[]):
510 def _spawn(self,command,args=[]):
511
511
512 """This starts the given command in a child process. This does all the
512 """This starts the given command in a child process. This does all the
513 fork/exec type of stuff for a pty. This is called by __init__. If args
513 fork/exec type of stuff for a pty. This is called by __init__. If args
514 is empty then command will be parsed (split on spaces) and args will be
514 is empty then command will be parsed (split on spaces) and args will be
515 set to parsed arguments. """
515 set to parsed arguments. """
516
516
517 # The pid and child_fd of this object get set by this method.
517 # The pid and child_fd of this object get set by this method.
518 # Note that it is difficult for this method to fail.
518 # Note that it is difficult for this method to fail.
519 # You cannot detect if the child process cannot start.
519 # You cannot detect if the child process cannot start.
520 # So the only way you can tell if the child process started
520 # So the only way you can tell if the child process started
521 # or not is to try to read from the file descriptor. If you get
521 # or not is to try to read from the file descriptor. If you get
522 # EOF immediately then it means that the child is already dead.
522 # EOF immediately then it means that the child is already dead.
523 # That may not necessarily be bad because you may haved spawned a child
523 # That may not necessarily be bad because you may haved spawned a child
524 # that performs some task; creates no stdout output; and then dies.
524 # that performs some task; creates no stdout output; and then dies.
525
525
526 # If command is an int type then it may represent a file descriptor.
526 # If command is an int type then it may represent a file descriptor.
527 if type(command) == type(0):
527 if type(command) == type(0):
528 raise ExceptionPexpect ('Command is an int type. If this is a file descriptor then maybe you want to use fdpexpect.fdspawn which takes an existing file descriptor instead of a command string.')
528 raise ExceptionPexpect ('Command is an int type. If this is a file descriptor then maybe you want to use fdpexpect.fdspawn which takes an existing file descriptor instead of a command string.')
529
529
530 if type (args) != type([]):
530 if type (args) != type([]):
531 raise TypeError ('The argument, args, must be a list.')
531 raise TypeError ('The argument, args, must be a list.')
532
532
533 if args == []:
533 if args == []:
534 self.args = split_command_line(command)
534 self.args = split_command_line(command)
535 self.command = self.args[0]
535 self.command = self.args[0]
536 else:
536 else:
537 self.args = args[:] # work with a copy
537 self.args = args[:] # work with a copy
538 self.args.insert (0, command)
538 self.args.insert (0, command)
539 self.command = command
539 self.command = command
540
540
541 command_with_path = which(self.command)
541 command_with_path = which(self.command)
542 if command_with_path is None:
542 if command_with_path is None:
543 raise ExceptionPexpect ('The command was not found or was not executable: %s.' % self.command)
543 raise ExceptionPexpect ('The command was not found or was not executable: %s.' % self.command)
544 self.command = command_with_path
544 self.command = command_with_path
545 self.args[0] = self.command
545 self.args[0] = self.command
546
546
547 self.name = '<' + ' '.join (self.args) + '>'
547 self.name = '<' + ' '.join (self.args) + '>'
548
548
549 assert self.pid is None, 'The pid member should be None.'
549 assert self.pid is None, 'The pid member should be None.'
550 assert self.command is not None, 'The command member should not be None.'
550 assert self.command is not None, 'The command member should not be None.'
551
551
552 if self.use_native_pty_fork:
552 if self.use_native_pty_fork:
553 try:
553 try:
554 self.pid, self.child_fd = pty.fork()
554 self.pid, self.child_fd = pty.fork()
555 except OSError as e:
555 except OSError as e:
556 raise ExceptionPexpect('Error! pty.fork() failed: ' + str(e))
556 raise ExceptionPexpect('Error! pty.fork() failed: ' + str(e))
557 else: # Use internal __fork_pty
557 else: # Use internal __fork_pty
558 self.pid, self.child_fd = self.__fork_pty()
558 self.pid, self.child_fd = self.__fork_pty()
559
559
560 if self.pid == 0: # Child
560 if self.pid == 0: # Child
561 try:
561 try:
562 self.child_fd = sys.stdout.fileno() # used by setwinsize()
562 self.child_fd = sys.stdout.fileno() # used by setwinsize()
563 self.setwinsize(24, 80)
563 self.setwinsize(24, 80)
564 except:
564 except:
565 # Some platforms do not like setwinsize (Cygwin).
565 # Some platforms do not like setwinsize (Cygwin).
566 # This will cause problem when running applications that
566 # This will cause problem when running applications that
567 # are very picky about window size.
567 # are very picky about window size.
568 # This is a serious limitation, but not a show stopper.
568 # This is a serious limitation, but not a show stopper.
569 pass
569 pass
570 # Do not allow child to inherit open file descriptors from parent.
570 # Do not allow child to inherit open file descriptors from parent.
571 max_fd = resource.getrlimit(resource.RLIMIT_NOFILE)[0]
571 max_fd = resource.getrlimit(resource.RLIMIT_NOFILE)[0]
572 for i in range (3, max_fd):
572 for i in range (3, max_fd):
573 try:
573 try:
574 os.close (i)
574 os.close (i)
575 except OSError:
575 except OSError:
576 pass
576 pass
577
577
578 # I don't know why this works, but ignoring SIGHUP fixes a
578 # I don't know why this works, but ignoring SIGHUP fixes a
579 # problem when trying to start a Java daemon with sudo
579 # problem when trying to start a Java daemon with sudo
580 # (specifically, Tomcat).
580 # (specifically, Tomcat).
581 signal.signal(signal.SIGHUP, signal.SIG_IGN)
581 signal.signal(signal.SIGHUP, signal.SIG_IGN)
582
582
583 if self.cwd is not None:
583 if self.cwd is not None:
584 os.chdir(self.cwd)
584 os.chdir(self.cwd)
585 if self.env is None:
585 if self.env is None:
586 os.execv(self.command, self.args)
586 os.execv(self.command, self.args)
587 else:
587 else:
588 os.execvpe(self.command, self.args, self.env)
588 os.execvpe(self.command, self.args, self.env)
589
589
590 # Parent
590 # Parent
591 self.terminated = False
591 self.terminated = False
592 self.closed = False
592 self.closed = False
593
593
594 def __fork_pty(self):
594 def __fork_pty(self):
595
595
596 """This implements a substitute for the forkpty system call. This
596 """This implements a substitute for the forkpty system call. This
597 should be more portable than the pty.fork() function. Specifically,
597 should be more portable than the pty.fork() function. Specifically,
598 this should work on Solaris.
598 this should work on Solaris.
599
599
600 Modified 10.06.05 by Geoff Marshall: Implemented __fork_pty() method to
600 Modified 10.06.05 by Geoff Marshall: Implemented __fork_pty() method to
601 resolve the issue with Python's pty.fork() not supporting Solaris,
601 resolve the issue with Python's pty.fork() not supporting Solaris,
602 particularly ssh. Based on patch to posixmodule.c authored by Noah
602 particularly ssh. Based on patch to posixmodule.c authored by Noah
603 Spurrier::
603 Spurrier::
604
604
605 http://mail.python.org/pipermail/python-dev/2003-May/035281.html
605 http://mail.python.org/pipermail/python-dev/2003-May/035281.html
606
606
607 """
607 """
608
608
609 parent_fd, child_fd = os.openpty()
609 parent_fd, child_fd = os.openpty()
610 if parent_fd < 0 or child_fd < 0:
610 if parent_fd < 0 or child_fd < 0:
611 raise ExceptionPexpect("Error! Could not open pty with os.openpty().")
611 raise ExceptionPexpect("Error! Could not open pty with os.openpty().")
612
612
613 pid = os.fork()
613 pid = os.fork()
614 if pid < 0:
614 if pid < 0:
615 raise ExceptionPexpect("Error! Failed os.fork().")
615 raise ExceptionPexpect("Error! Failed os.fork().")
616 elif pid == 0:
616 elif pid == 0:
617 # Child.
617 # Child.
618 os.close(parent_fd)
618 os.close(parent_fd)
619 self.__pty_make_controlling_tty(child_fd)
619 self.__pty_make_controlling_tty(child_fd)
620
620
621 os.dup2(child_fd, 0)
621 os.dup2(child_fd, 0)
622 os.dup2(child_fd, 1)
622 os.dup2(child_fd, 1)
623 os.dup2(child_fd, 2)
623 os.dup2(child_fd, 2)
624
624
625 if child_fd > 2:
625 if child_fd > 2:
626 os.close(child_fd)
626 os.close(child_fd)
627 else:
627 else:
628 # Parent.
628 # Parent.
629 os.close(child_fd)
629 os.close(child_fd)
630
630
631 return pid, parent_fd
631 return pid, parent_fd
632
632
633 def __pty_make_controlling_tty(self, tty_fd):
633 def __pty_make_controlling_tty(self, tty_fd):
634
634
635 """This makes the pseudo-terminal the controlling tty. This should be
635 """This makes the pseudo-terminal the controlling tty. This should be
636 more portable than the pty.fork() function. Specifically, this should
636 more portable than the pty.fork() function. Specifically, this should
637 work on Solaris. """
637 work on Solaris. """
638
638
639 child_name = os.ttyname(tty_fd)
639 child_name = os.ttyname(tty_fd)
640
640
641 # Disconnect from controlling tty. Harmless if not already connected.
641 # Disconnect from controlling tty. Harmless if not already connected.
642 try:
642 try:
643 fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY);
643 fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY);
644 if fd >= 0:
644 if fd >= 0:
645 os.close(fd)
645 os.close(fd)
646 except:
646 except:
647 # Already disconnected. This happens if running inside cron.
647 # Already disconnected. This happens if running inside cron.
648 pass
648 pass
649
649
650 os.setsid()
650 os.setsid()
651
651
652 # Verify we are disconnected from controlling tty
652 # Verify we are disconnected from controlling tty
653 # by attempting to open it again.
653 # by attempting to open it again.
654 try:
654 try:
655 fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY);
655 fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY);
656 if fd >= 0:
656 if fd >= 0:
657 os.close(fd)
657 os.close(fd)
658 raise ExceptionPexpect("Error! Failed to disconnect from controlling tty. It is still possible to open /dev/tty.")
658 raise ExceptionPexpect("Error! Failed to disconnect from controlling tty. It is still possible to open /dev/tty.")
659 except:
659 except:
660 # Good! We are disconnected from a controlling tty.
660 # Good! We are disconnected from a controlling tty.
661 pass
661 pass
662
662
663 # Verify we can open child pty.
663 # Verify we can open child pty.
664 fd = os.open(child_name, os.O_RDWR);
664 fd = os.open(child_name, os.O_RDWR);
665 if fd < 0:
665 if fd < 0:
666 raise ExceptionPexpect("Error! Could not open child pty, " + child_name)
666 raise ExceptionPexpect("Error! Could not open child pty, " + child_name)
667 else:
667 else:
668 os.close(fd)
668 os.close(fd)
669
669
670 # Verify we now have a controlling tty.
670 # Verify we now have a controlling tty.
671 fd = os.open("/dev/tty", os.O_WRONLY)
671 fd = os.open("/dev/tty", os.O_WRONLY)
672 if fd < 0:
672 if fd < 0:
673 raise ExceptionPexpect("Error! Could not open controlling tty, /dev/tty")
673 raise ExceptionPexpect("Error! Could not open controlling tty, /dev/tty")
674 else:
674 else:
675 os.close(fd)
675 os.close(fd)
676
676
677 def fileno (self): # File-like object.
677 def fileno (self): # File-like object.
678
678
679 """This returns the file descriptor of the pty for the child.
679 """This returns the file descriptor of the pty for the child.
680 """
680 """
681
681
682 return self.child_fd
682 return self.child_fd
683
683
684 def close (self, force=True): # File-like object.
684 def close (self, force=True): # File-like object.
685
685
686 """This closes the connection with the child application. Note that
686 """This closes the connection with the child application. Note that
687 calling close() more than once is valid. This emulates standard Python
687 calling close() more than once is valid. This emulates standard Python
688 behavior with files. Set force to True if you want to make sure that
688 behavior with files. Set force to True if you want to make sure that
689 the child is terminated (SIGKILL is sent if the child ignores SIGHUP
689 the child is terminated (SIGKILL is sent if the child ignores SIGHUP
690 and SIGINT). """
690 and SIGINT). """
691
691
692 if not self.closed:
692 if not self.closed:
693 self.flush()
693 self.flush()
694 os.close (self.child_fd)
694 os.close (self.child_fd)
695 time.sleep(self.delayafterclose) # Give kernel time to update process status.
695 time.sleep(self.delayafterclose) # Give kernel time to update process status.
696 if self.isalive():
696 if self.isalive():
697 if not self.terminate(force):
697 if not self.terminate(force):
698 raise ExceptionPexpect ('close() could not terminate the child using terminate()')
698 raise ExceptionPexpect ('close() could not terminate the child using terminate()')
699 self.child_fd = -1
699 self.child_fd = -1
700 self.closed = True
700 self.closed = True
701 #self.pid = None
701 #self.pid = None
702
702
703 def flush (self): # File-like object.
703 def flush (self): # File-like object.
704
704
705 """This does nothing. It is here to support the interface for a
705 """This does nothing. It is here to support the interface for a
706 File-like object. """
706 File-like object. """
707
707
708 pass
708 pass
709
709
710 def isatty (self): # File-like object.
710 def isatty (self): # File-like object.
711
711
712 """This returns True if the file descriptor is open and connected to a
712 """This returns True if the file descriptor is open and connected to a
713 tty(-like) device, else False. """
713 tty(-like) device, else False. """
714
714
715 return os.isatty(self.child_fd)
715 return os.isatty(self.child_fd)
716
716
717 def waitnoecho (self, timeout=-1):
717 def waitnoecho (self, timeout=-1):
718
718
719 """This waits until the terminal ECHO flag is set False. This returns
719 """This waits until the terminal ECHO flag is set False. This returns
720 True if the echo mode is off. This returns False if the ECHO flag was
720 True if the echo mode is off. This returns False if the ECHO flag was
721 not set False before the timeout. This can be used to detect when the
721 not set False before the timeout. This can be used to detect when the
722 child is waiting for a password. Usually a child application will turn
722 child is waiting for a password. Usually a child application will turn
723 off echo mode when it is waiting for the user to enter a password. For
723 off echo mode when it is waiting for the user to enter a password. For
724 example, instead of expecting the "password:" prompt you can wait for
724 example, instead of expecting the "password:" prompt you can wait for
725 the child to set ECHO off::
725 the child to set ECHO off::
726
726
727 p = pexpect.spawn ('ssh user@example.com')
727 p = pexpect.spawn ('ssh user@example.com')
728 p.waitnoecho()
728 p.waitnoecho()
729 p.sendline(mypassword)
729 p.sendline(mypassword)
730
730
731 If timeout==-1 then this method will use the value in self.timeout.
731 If timeout==-1 then this method will use the value in self.timeout.
732 If timeout==None then this method to block until ECHO flag is False.
732 If timeout==None then this method to block until ECHO flag is False.
733 """
733 """
734
734
735 if timeout == -1:
735 if timeout == -1:
736 timeout = self.timeout
736 timeout = self.timeout
737 if timeout is not None:
737 if timeout is not None:
738 end_time = time.time() + timeout
738 end_time = time.time() + timeout
739 while True:
739 while True:
740 if not self.getecho():
740 if not self.getecho():
741 return True
741 return True
742 if timeout < 0 and timeout is not None:
742 if timeout < 0 and timeout is not None:
743 return False
743 return False
744 if timeout is not None:
744 if timeout is not None:
745 timeout = end_time - time.time()
745 timeout = end_time - time.time()
746 time.sleep(0.1)
746 time.sleep(0.1)
747
747
748 def getecho (self):
748 def getecho (self):
749
749
750 """This returns the terminal echo mode. This returns True if echo is
750 """This returns the terminal echo mode. This returns True if echo is
751 on or False if echo is off. Child applications that are expecting you
751 on or False if echo is off. Child applications that are expecting you
752 to enter a password often set ECHO False. See waitnoecho(). """
752 to enter a password often set ECHO False. See waitnoecho(). """
753
753
754 attr = termios.tcgetattr(self.child_fd)
754 attr = termios.tcgetattr(self.child_fd)
755 if attr[3] & termios.ECHO:
755 if attr[3] & termios.ECHO:
756 return True
756 return True
757 return False
757 return False
758
758
759 def setecho (self, state):
759 def setecho (self, state):
760
760
761 """This sets the terminal echo mode on or off. Note that anything the
761 """This sets the terminal echo mode on or off. Note that anything the
762 child sent before the echo will be lost, so you should be sure that
762 child sent before the echo will be lost, so you should be sure that
763 your input buffer is empty before you call setecho(). For example, the
763 your input buffer is empty before you call setecho(). For example, the
764 following will work as expected::
764 following will work as expected::
765
765
766 p = pexpect.spawn('cat')
766 p = pexpect.spawn('cat')
767 p.sendline ('1234') # We will see this twice (once from tty echo and again from cat).
767 p.sendline ('1234') # We will see this twice (once from tty echo and again from cat).
768 p.expect (['1234'])
768 p.expect (['1234'])
769 p.expect (['1234'])
769 p.expect (['1234'])
770 p.setecho(False) # Turn off tty echo
770 p.setecho(False) # Turn off tty echo
771 p.sendline ('abcd') # We will set this only once (echoed by cat).
771 p.sendline ('abcd') # We will set this only once (echoed by cat).
772 p.sendline ('wxyz') # We will set this only once (echoed by cat)
772 p.sendline ('wxyz') # We will set this only once (echoed by cat)
773 p.expect (['abcd'])
773 p.expect (['abcd'])
774 p.expect (['wxyz'])
774 p.expect (['wxyz'])
775
775
776 The following WILL NOT WORK because the lines sent before the setecho
776 The following WILL NOT WORK because the lines sent before the setecho
777 will be lost::
777 will be lost::
778
778
779 p = pexpect.spawn('cat')
779 p = pexpect.spawn('cat')
780 p.sendline ('1234') # We will see this twice (once from tty echo and again from cat).
780 p.sendline ('1234') # We will see this twice (once from tty echo and again from cat).
781 p.setecho(False) # Turn off tty echo
781 p.setecho(False) # Turn off tty echo
782 p.sendline ('abcd') # We will set this only once (echoed by cat).
782 p.sendline ('abcd') # We will set this only once (echoed by cat).
783 p.sendline ('wxyz') # We will set this only once (echoed by cat)
783 p.sendline ('wxyz') # We will set this only once (echoed by cat)
784 p.expect (['1234'])
784 p.expect (['1234'])
785 p.expect (['1234'])
785 p.expect (['1234'])
786 p.expect (['abcd'])
786 p.expect (['abcd'])
787 p.expect (['wxyz'])
787 p.expect (['wxyz'])
788 """
788 """
789
789
790 self.child_fd
790 self.child_fd
791 attr = termios.tcgetattr(self.child_fd)
791 attr = termios.tcgetattr(self.child_fd)
792 if state:
792 if state:
793 attr[3] = attr[3] | termios.ECHO
793 attr[3] = attr[3] | termios.ECHO
794 else:
794 else:
795 attr[3] = attr[3] & ~termios.ECHO
795 attr[3] = attr[3] & ~termios.ECHO
796 # I tried TCSADRAIN and TCSAFLUSH, but these were inconsistent
796 # I tried TCSADRAIN and TCSAFLUSH, but these were inconsistent
797 # and blocked on some platforms. TCSADRAIN is probably ideal if it worked.
797 # and blocked on some platforms. TCSADRAIN is probably ideal if it worked.
798 termios.tcsetattr(self.child_fd, termios.TCSANOW, attr)
798 termios.tcsetattr(self.child_fd, termios.TCSANOW, attr)
799
799
800 def read_nonblocking (self, size = 1, timeout = -1):
800 def read_nonblocking (self, size = 1, timeout = -1):
801
801
802 """This reads at most size bytes from the child application. It
802 """This reads at most size bytes from the child application. It
803 includes a timeout. If the read does not complete within the timeout
803 includes a timeout. If the read does not complete within the timeout
804 period then a TIMEOUT exception is raised. If the end of file is read
804 period then a TIMEOUT exception is raised. If the end of file is read
805 then an EOF exception will be raised. If a log file was set using
805 then an EOF exception will be raised. If a log file was set using
806 setlog() then all data will also be written to the log file.
806 setlog() then all data will also be written to the log file.
807
807
808 If timeout is None then the read may block indefinitely. If timeout is -1
808 If timeout is None then the read may block indefinitely. If timeout is -1
809 then the self.timeout value is used. If timeout is 0 then the child is
809 then the self.timeout value is used. If timeout is 0 then the child is
810 polled and if there was no data immediately ready then this will raise
810 polled and if there was no data immediately ready then this will raise
811 a TIMEOUT exception.
811 a TIMEOUT exception.
812
812
813 The timeout refers only to the amount of time to read at least one
813 The timeout refers only to the amount of time to read at least one
814 character. This is not effected by the 'size' parameter, so if you call
814 character. This is not effected by the 'size' parameter, so if you call
815 read_nonblocking(size=100, timeout=30) and only one character is
815 read_nonblocking(size=100, timeout=30) and only one character is
816 available right away then one character will be returned immediately.
816 available right away then one character will be returned immediately.
817 It will not wait for 30 seconds for another 99 characters to come in.
817 It will not wait for 30 seconds for another 99 characters to come in.
818
818
819 This is a wrapper around os.read(). It uses select.select() to
819 This is a wrapper around os.read(). It uses select.select() to
820 implement the timeout. """
820 implement the timeout. """
821
821
822 if self.closed:
822 if self.closed:
823 raise ValueError ('I/O operation on closed file in read_nonblocking().')
823 raise ValueError ('I/O operation on closed file in read_nonblocking().')
824
824
825 if timeout == -1:
825 if timeout == -1:
826 timeout = self.timeout
826 timeout = self.timeout
827
827
828 # Note that some systems such as Solaris do not give an EOF when
828 # Note that some systems such as Solaris do not give an EOF when
829 # the child dies. In fact, you can still try to read
829 # the child dies. In fact, you can still try to read
830 # from the child_fd -- it will block forever or until TIMEOUT.
830 # from the child_fd -- it will block forever or until TIMEOUT.
831 # For this case, I test isalive() before doing any reading.
831 # For this case, I test isalive() before doing any reading.
832 # If isalive() is false, then I pretend that this is the same as EOF.
832 # If isalive() is false, then I pretend that this is the same as EOF.
833 if not self.isalive():
833 if not self.isalive():
834 r,w,e = self.__select([self.child_fd], [], [], 0) # timeout of 0 means "poll"
834 r,w,e = self.__select([self.child_fd], [], [], 0) # timeout of 0 means "poll"
835 if not r:
835 if not r:
836 self.flag_eof = True
836 self.flag_eof = True
837 raise EOF ('End Of File (EOF) in read_nonblocking(). Braindead platform.')
837 raise EOF ('End Of File (EOF) in read_nonblocking(). Braindead platform.')
838 elif self.__irix_hack:
838 elif self.__irix_hack:
839 # This is a hack for Irix. It seems that Irix requires a long delay before checking isalive.
839 # This is a hack for Irix. It seems that Irix requires a long delay before checking isalive.
840 # This adds a 2 second delay, but only when the child is terminated.
840 # This adds a 2 second delay, but only when the child is terminated.
841 r, w, e = self.__select([self.child_fd], [], [], 2)
841 r, w, e = self.__select([self.child_fd], [], [], 2)
842 if not r and not self.isalive():
842 if not r and not self.isalive():
843 self.flag_eof = True
843 self.flag_eof = True
844 raise EOF ('End Of File (EOF) in read_nonblocking(). Pokey platform.')
844 raise EOF ('End Of File (EOF) in read_nonblocking(). Pokey platform.')
845
845
846 r,w,e = self.__select([self.child_fd], [], [], timeout)
846 r,w,e = self.__select([self.child_fd], [], [], timeout)
847
847
848 if not r:
848 if not r:
849 if not self.isalive():
849 if not self.isalive():
850 # Some platforms, such as Irix, will claim that their processes are alive;
850 # Some platforms, such as Irix, will claim that their processes are alive;
851 # then timeout on the select; and then finally admit that they are not alive.
851 # then timeout on the select; and then finally admit that they are not alive.
852 self.flag_eof = True
852 self.flag_eof = True
853 raise EOF ('End of File (EOF) in read_nonblocking(). Very pokey platform.')
853 raise EOF ('End of File (EOF) in read_nonblocking(). Very pokey platform.')
854 else:
854 else:
855 raise TIMEOUT ('Timeout exceeded in read_nonblocking().')
855 raise TIMEOUT ('Timeout exceeded in read_nonblocking().')
856
856
857 if self.child_fd in r:
857 if self.child_fd in r:
858 try:
858 try:
859 s = os.read(self.child_fd, size)
859 s = os.read(self.child_fd, size)
860 except OSError as e: # Linux does this
860 except OSError as e: # Linux does this
861 self.flag_eof = True
861 self.flag_eof = True
862 raise EOF ('End Of File (EOF) in read_nonblocking(). Exception style platform.')
862 raise EOF ('End Of File (EOF) in read_nonblocking(). Exception style platform.')
863 if s == b'': # BSD style
863 if s == b'': # BSD style
864 self.flag_eof = True
864 self.flag_eof = True
865 raise EOF ('End Of File (EOF) in read_nonblocking(). Empty string style platform.')
865 raise EOF ('End Of File (EOF) in read_nonblocking(). Empty string style platform.')
866
866
867 s2 = self._cast_buffer_type(s)
867 s2 = self._cast_buffer_type(s)
868 if self.logfile is not None:
868 if self.logfile is not None:
869 self.logfile.write(s2)
869 self.logfile.write(s2)
870 self.logfile.flush()
870 self.logfile.flush()
871 if self.logfile_read is not None:
871 if self.logfile_read is not None:
872 self.logfile_read.write(s2)
872 self.logfile_read.write(s2)
873 self.logfile_read.flush()
873 self.logfile_read.flush()
874
874
875 return s
875 return s
876
876
877 raise ExceptionPexpect ('Reached an unexpected state in read_nonblocking().')
877 raise ExceptionPexpect ('Reached an unexpected state in read_nonblocking().')
878
878
879 def read (self, size = -1): # File-like object.
879 def read (self, size = -1): # File-like object.
880 """This reads at most "size" bytes from the file (less if the read hits
880 """This reads at most "size" bytes from the file (less if the read hits
881 EOF before obtaining size bytes). If the size argument is negative or
881 EOF before obtaining size bytes). If the size argument is negative or
882 omitted, read all data until EOF is reached. The bytes are returned as
882 omitted, read all data until EOF is reached. The bytes are returned as
883 a string object. An empty string is returned when EOF is encountered
883 a string object. An empty string is returned when EOF is encountered
884 immediately. """
884 immediately. """
885
885
886 if size == 0:
886 if size == 0:
887 return self._empty_buffer
887 return self._empty_buffer
888 if size < 0:
888 if size < 0:
889 self.expect (self.delimiter) # delimiter default is EOF
889 self.expect (self.delimiter) # delimiter default is EOF
890 return self.before
890 return self.before
891
891
892 # I could have done this more directly by not using expect(), but
892 # I could have done this more directly by not using expect(), but
893 # I deliberately decided to couple read() to expect() so that
893 # I deliberately decided to couple read() to expect() so that
894 # I would catch any bugs early and ensure consistant behavior.
894 # I would catch any bugs early and ensure consistant behavior.
895 # It's a little less efficient, but there is less for me to
895 # It's a little less efficient, but there is less for me to
896 # worry about if I have to later modify read() or expect().
896 # worry about if I have to later modify read() or expect().
897 # Note, it's OK if size==-1 in the regex. That just means it
897 # Note, it's OK if size==-1 in the regex. That just means it
898 # will never match anything in which case we stop only on EOF.
898 # will never match anything in which case we stop only on EOF.
899 if self._buffer_type is bytes:
899 if self._buffer_type is bytes:
900 pat = (u'.{%d}' % size).encode('ascii')
900 pat = (u'.{%d}' % size).encode('ascii')
901 else:
901 else:
902 pat = u'.{%d}' % size
902 pat = u'.{%d}' % size
903 cre = re.compile(pat, re.DOTALL)
903 cre = re.compile(pat, re.DOTALL)
904 index = self.expect ([cre, self.delimiter]) # delimiter default is EOF
904 index = self.expect ([cre, self.delimiter]) # delimiter default is EOF
905 if index == 0:
905 if index == 0:
906 return self.after ### self.before should be ''. Should I assert this?
906 return self.after ### self.before should be ''. Should I assert this?
907 return self.before
907 return self.before
908
908
909 def readline(self, size = -1):
909 def readline(self, size = -1):
910 """This reads and returns one entire line. A trailing newline is kept
910 """This reads and returns one entire line. A trailing newline is kept
911 in the string, but may be absent when a file ends with an incomplete
911 in the string, but may be absent when a file ends with an incomplete
912 line. Note: This readline() looks for a \\r\\n pair even on UNIX
912 line. Note: This readline() looks for a \\r\\n pair even on UNIX
913 because this is what the pseudo tty device returns. So contrary to what
913 because this is what the pseudo tty device returns. So contrary to what
914 you may expect you will receive the newline as \\r\\n. An empty string
914 you may expect you will receive the newline as \\r\\n. An empty string
915 is returned when EOF is hit immediately. Currently, the size argument is
915 is returned when EOF is hit immediately. Currently, the size argument is
916 mostly ignored, so this behavior is not standard for a file-like
916 mostly ignored, so this behavior is not standard for a file-like
917 object. If size is 0 then an empty string is returned. """
917 object. If size is 0 then an empty string is returned. """
918
918
919 if size == 0:
919 if size == 0:
920 return self._empty_buffer
920 return self._empty_buffer
921 index = self.expect ([self._pty_newline, self.delimiter]) # delimiter default is EOF
921 index = self.expect ([self._pty_newline, self.delimiter]) # delimiter default is EOF
922 if index == 0:
922 if index == 0:
923 return self.before + self._pty_newline
923 return self.before + self._pty_newline
924 return self.before
924 return self.before
925
925
926 def __iter__ (self): # File-like object.
926 def __iter__ (self): # File-like object.
927
927
928 """This is to support iterators over a file-like object.
928 """This is to support iterators over a file-like object.
929 """
929 """
930
930
931 return self
931 return self
932
932
933 def __next__ (self): # File-like object.
933 def __next__ (self): # File-like object.
934
934
935 """This is to support iterators over a file-like object.
935 """This is to support iterators over a file-like object.
936 """
936 """
937
937
938 result = self.readline()
938 result = self.readline()
939 if result == self._empty_buffer:
939 if result == self._empty_buffer:
940 raise StopIteration
940 raise StopIteration
941 return result
941 return result
942
942
943 if not PY3:
943 if not PY3:
944 next = __next__ # File-like object.
944 next = __next__ # File-like object.
945
945
946 def readlines (self, sizehint = -1): # File-like object.
946 def readlines (self, sizehint = -1): # File-like object.
947
947
948 """This reads until EOF using readline() and returns a list containing
948 """This reads until EOF using readline() and returns a list containing
949 the lines thus read. The optional "sizehint" argument is ignored. """
949 the lines thus read. The optional "sizehint" argument is ignored. """
950
950
951 lines = []
951 lines = []
952 while True:
952 while True:
953 line = self.readline()
953 line = self.readline()
954 if not line:
954 if not line:
955 break
955 break
956 lines.append(line)
956 lines.append(line)
957 return lines
957 return lines
958
958
959 def write(self, s): # File-like object.
959 def write(self, s): # File-like object.
960
960
961 """This is similar to send() except that there is no return value.
961 """This is similar to send() except that there is no return value.
962 """
962 """
963
963
964 self.send (s)
964 self.send (s)
965
965
966 def writelines (self, sequence): # File-like object.
966 def writelines (self, sequence): # File-like object.
967
967
968 """This calls write() for each element in the sequence. The sequence
968 """This calls write() for each element in the sequence. The sequence
969 can be any iterable object producing strings, typically a list of
969 can be any iterable object producing strings, typically a list of
970 strings. This does not add line separators There is no return value.
970 strings. This does not add line separators There is no return value.
971 """
971 """
972
972
973 for s in sequence:
973 for s in sequence:
974 self.write (s)
974 self.write (s)
975
975
976 def send(self, s):
976 def send(self, s):
977
977
978 """This sends a string to the child process. This returns the number of
978 """This sends a string to the child process. This returns the number of
979 bytes written. If a log file was set then the data is also written to
979 bytes written. If a log file was set then the data is also written to
980 the log. """
980 the log. """
981
981
982 time.sleep(self.delaybeforesend)
982 time.sleep(self.delaybeforesend)
983
983
984 s2 = self._cast_buffer_type(s)
984 s2 = self._cast_buffer_type(s)
985 if self.logfile is not None:
985 if self.logfile is not None:
986 self.logfile.write(s2)
986 self.logfile.write(s2)
987 self.logfile.flush()
987 self.logfile.flush()
988 if self.logfile_send is not None:
988 if self.logfile_send is not None:
989 self.logfile_send.write(s2)
989 self.logfile_send.write(s2)
990 self.logfile_send.flush()
990 self.logfile_send.flush()
991 c = os.write (self.child_fd, _cast_bytes(s, self.encoding))
991 c = os.write (self.child_fd, _cast_bytes(s, self.encoding))
992 return c
992 return c
993
993
994 def sendline(self, s=''):
994 def sendline(self, s=''):
995
995
996 """This is like send(), but it adds a line feed (os.linesep). This
996 """This is like send(), but it adds a line feed (os.linesep). This
997 returns the number of bytes written. """
997 returns the number of bytes written. """
998
998
999 n = self.send (s)
999 n = self.send (s)
1000 n = n + self.send (os.linesep)
1000 n = n + self.send (os.linesep)
1001 return n
1001 return n
1002
1002
1003 def sendcontrol(self, char):
1003 def sendcontrol(self, char):
1004
1004
1005 """This sends a control character to the child such as Ctrl-C or
1005 """This sends a control character to the child such as Ctrl-C or
1006 Ctrl-D. For example, to send a Ctrl-G (ASCII 7)::
1006 Ctrl-D. For example, to send a Ctrl-G (ASCII 7)::
1007
1007
1008 child.sendcontrol('g')
1008 child.sendcontrol('g')
1009
1009
1010 See also, sendintr() and sendeof().
1010 See also, sendintr() and sendeof().
1011 """
1011 """
1012
1012
1013 char = char.lower()
1013 char = char.lower()
1014 a = ord(char)
1014 a = ord(char)
1015 if a>=97 and a<=122:
1015 if a>=97 and a<=122:
1016 a = a - ord('a') + 1
1016 a = a - ord('a') + 1
1017 return self.send (chr(a))
1017 return self.send (chr(a))
1018 d = {'@':0, '`':0,
1018 d = {'@':0, '`':0,
1019 '[':27, '{':27,
1019 '[':27, '{':27,
1020 '\\':28, '|':28,
1020 '\\':28, '|':28,
1021 ']':29, '}': 29,
1021 ']':29, '}': 29,
1022 '^':30, '~':30,
1022 '^':30, '~':30,
1023 '_':31,
1023 '_':31,
1024 '?':127}
1024 '?':127}
1025 if char not in d:
1025 if char not in d:
1026 return 0
1026 return 0
1027 return self.send (chr(d[char]))
1027 return self.send (chr(d[char]))
1028
1028
1029 def sendeof(self):
1029 def sendeof(self):
1030
1030
1031 """This sends an EOF to the child. This sends a character which causes
1031 """This sends an EOF to the child. This sends a character which causes
1032 the pending parent output buffer to be sent to the waiting child
1032 the pending parent output buffer to be sent to the waiting child
1033 program without waiting for end-of-line. If it is the first character
1033 program without waiting for end-of-line. If it is the first character
1034 of the line, the read() in the user program returns 0, which signifies
1034 of the line, the read() in the user program returns 0, which signifies
1035 end-of-file. This means to work as expected a sendeof() has to be
1035 end-of-file. This means to work as expected a sendeof() has to be
1036 called at the beginning of a line. This method does not send a newline.
1036 called at the beginning of a line. This method does not send a newline.
1037 It is the responsibility of the caller to ensure the eof is sent at the
1037 It is the responsibility of the caller to ensure the eof is sent at the
1038 beginning of a line. """
1038 beginning of a line. """
1039
1039
1040 ### Hmmm... how do I send an EOF?
1040 ### Hmmm... how do I send an EOF?
1041 ###C if ((m = write(pty, *buf, p - *buf)) < 0)
1041 ###C if ((m = write(pty, *buf, p - *buf)) < 0)
1042 ###C return (errno == EWOULDBLOCK) ? n : -1;
1042 ###C return (errno == EWOULDBLOCK) ? n : -1;
1043 #fd = sys.stdin.fileno()
1043 #fd = sys.stdin.fileno()
1044 #old = termios.tcgetattr(fd) # remember current state
1044 #old = termios.tcgetattr(fd) # remember current state
1045 #attr = termios.tcgetattr(fd)
1045 #attr = termios.tcgetattr(fd)
1046 #attr[3] = attr[3] | termios.ICANON # ICANON must be set to recognize EOF
1046 #attr[3] = attr[3] | termios.ICANON # ICANON must be set to recognize EOF
1047 #try: # use try/finally to ensure state gets restored
1047 #try: # use try/finally to ensure state gets restored
1048 # termios.tcsetattr(fd, termios.TCSADRAIN, attr)
1048 # termios.tcsetattr(fd, termios.TCSADRAIN, attr)
1049 # if hasattr(termios, 'CEOF'):
1049 # if hasattr(termios, 'CEOF'):
1050 # os.write (self.child_fd, '%c' % termios.CEOF)
1050 # os.write (self.child_fd, '%c' % termios.CEOF)
1051 # else:
1051 # else:
1052 # # Silly platform does not define CEOF so assume CTRL-D
1052 # # Silly platform does not define CEOF so assume CTRL-D
1053 # os.write (self.child_fd, '%c' % 4)
1053 # os.write (self.child_fd, '%c' % 4)
1054 #finally: # restore state
1054 #finally: # restore state
1055 # termios.tcsetattr(fd, termios.TCSADRAIN, old)
1055 # termios.tcsetattr(fd, termios.TCSADRAIN, old)
1056 if hasattr(termios, 'VEOF'):
1056 if hasattr(termios, 'VEOF'):
1057 char = termios.tcgetattr(self.child_fd)[6][termios.VEOF]
1057 char = termios.tcgetattr(self.child_fd)[6][termios.VEOF]
1058 else:
1058 else:
1059 # platform does not define VEOF so assume CTRL-D
1059 # platform does not define VEOF so assume CTRL-D
1060 char = chr(4)
1060 char = chr(4)
1061 self.send(char)
1061 self.send(char)
1062
1062
1063 def sendintr(self):
1063 def sendintr(self):
1064
1064
1065 """This sends a SIGINT to the child. It does not require
1065 """This sends a SIGINT to the child. It does not require
1066 the SIGINT to be the first character on a line. """
1066 the SIGINT to be the first character on a line. """
1067
1067
1068 if hasattr(termios, 'VINTR'):
1068 if hasattr(termios, 'VINTR'):
1069 char = termios.tcgetattr(self.child_fd)[6][termios.VINTR]
1069 char = termios.tcgetattr(self.child_fd)[6][termios.VINTR]
1070 else:
1070 else:
1071 # platform does not define VINTR so assume CTRL-C
1071 # platform does not define VINTR so assume CTRL-C
1072 char = chr(3)
1072 char = chr(3)
1073 self.send (char)
1073 self.send (char)
1074
1074
1075 def eof (self):
1075 def eof (self):
1076
1076
1077 """This returns True if the EOF exception was ever raised.
1077 """This returns True if the EOF exception was ever raised.
1078 """
1078 """
1079
1079
1080 return self.flag_eof
1080 return self.flag_eof
1081
1081
1082 def terminate(self, force=False):
1082 def terminate(self, force=False):
1083
1083
1084 """This forces a child process to terminate. It starts nicely with
1084 """This forces a child process to terminate. It starts nicely with
1085 SIGHUP and SIGINT. If "force" is True then moves onto SIGKILL. This
1085 SIGHUP and SIGINT. If "force" is True then moves onto SIGKILL. This
1086 returns True if the child was terminated. This returns False if the
1086 returns True if the child was terminated. This returns False if the
1087 child could not be terminated. """
1087 child could not be terminated. """
1088
1088
1089 if not self.isalive():
1089 if not self.isalive():
1090 return True
1090 return True
1091 try:
1091 try:
1092 self.kill(signal.SIGHUP)
1092 self.kill(signal.SIGHUP)
1093 time.sleep(self.delayafterterminate)
1093 time.sleep(self.delayafterterminate)
1094 if not self.isalive():
1094 if not self.isalive():
1095 return True
1095 return True
1096 self.kill(signal.SIGCONT)
1096 self.kill(signal.SIGCONT)
1097 time.sleep(self.delayafterterminate)
1097 time.sleep(self.delayafterterminate)
1098 if not self.isalive():
1098 if not self.isalive():
1099 return True
1099 return True
1100 self.kill(signal.SIGINT)
1100 self.kill(signal.SIGINT)
1101 time.sleep(self.delayafterterminate)
1101 time.sleep(self.delayafterterminate)
1102 if not self.isalive():
1102 if not self.isalive():
1103 return True
1103 return True
1104 if force:
1104 if force:
1105 self.kill(signal.SIGKILL)
1105 self.kill(signal.SIGKILL)
1106 time.sleep(self.delayafterterminate)
1106 time.sleep(self.delayafterterminate)
1107 if not self.isalive():
1107 if not self.isalive():
1108 return True
1108 return True
1109 else:
1109 else:
1110 return False
1110 return False
1111 return False
1111 return False
1112 except OSError as e:
1112 except OSError as e:
1113 # I think there are kernel timing issues that sometimes cause
1113 # I think there are kernel timing issues that sometimes cause
1114 # this to happen. I think isalive() reports True, but the
1114 # this to happen. I think isalive() reports True, but the
1115 # process is dead to the kernel.
1115 # process is dead to the kernel.
1116 # Make one last attempt to see if the kernel is up to date.
1116 # Make one last attempt to see if the kernel is up to date.
1117 time.sleep(self.delayafterterminate)
1117 time.sleep(self.delayafterterminate)
1118 if not self.isalive():
1118 if not self.isalive():
1119 return True
1119 return True
1120 else:
1120 else:
1121 return False
1121 return False
1122
1122
1123 def wait(self):
1123 def wait(self):
1124
1124
1125 """This waits until the child exits. This is a blocking call. This will
1125 """This waits until the child exits. This is a blocking call. This will
1126 not read any data from the child, so this will block forever if the
1126 not read any data from the child, so this will block forever if the
1127 child has unread output and has terminated. In other words, the child
1127 child has unread output and has terminated. In other words, the child
1128 may have printed output then called exit(); but, technically, the child
1128 may have printed output then called exit(); but, technically, the child
1129 is still alive until its output is read. """
1129 is still alive until its output is read. """
1130
1130
1131 if self.isalive():
1131 if self.isalive():
1132 pid, status = os.waitpid(self.pid, 0)
1132 pid, status = os.waitpid(self.pid, 0)
1133 else:
1133 else:
1134 raise ExceptionPexpect ('Cannot wait for dead child process.')
1134 raise ExceptionPexpect ('Cannot wait for dead child process.')
1135 self.exitstatus = os.WEXITSTATUS(status)
1135 self.exitstatus = os.WEXITSTATUS(status)
1136 if os.WIFEXITED (status):
1136 if os.WIFEXITED (status):
1137 self.status = status
1137 self.status = status
1138 self.exitstatus = os.WEXITSTATUS(status)
1138 self.exitstatus = os.WEXITSTATUS(status)
1139 self.signalstatus = None
1139 self.signalstatus = None
1140 self.terminated = True
1140 self.terminated = True
1141 elif os.WIFSIGNALED (status):
1141 elif os.WIFSIGNALED (status):
1142 self.status = status
1142 self.status = status
1143 self.exitstatus = None
1143 self.exitstatus = None
1144 self.signalstatus = os.WTERMSIG(status)
1144 self.signalstatus = os.WTERMSIG(status)
1145 self.terminated = True
1145 self.terminated = True
1146 elif os.WIFSTOPPED (status):
1146 elif os.WIFSTOPPED (status):
1147 raise ExceptionPexpect ('Wait was called for a child process that is stopped. This is not supported. Is some other process attempting job control with our child pid?')
1147 raise ExceptionPexpect ('Wait was called for a child process that is stopped. This is not supported. Is some other process attempting job control with our child pid?')
1148 return self.exitstatus
1148 return self.exitstatus
1149
1149
1150 def isalive(self):
1150 def isalive(self):
1151
1151
1152 """This tests if the child process is running or not. This is
1152 """This tests if the child process is running or not. This is
1153 non-blocking. If the child was terminated then this will read the
1153 non-blocking. If the child was terminated then this will read the
1154 exitstatus or signalstatus of the child. This returns True if the child
1154 exitstatus or signalstatus of the child. This returns True if the child
1155 process appears to be running or False if not. It can take literally
1155 process appears to be running or False if not. It can take literally
1156 SECONDS for Solaris to return the right status. """
1156 SECONDS for Solaris to return the right status. """
1157
1157
1158 if self.terminated:
1158 if self.terminated:
1159 return False
1159 return False
1160
1160
1161 if self.flag_eof:
1161 if self.flag_eof:
1162 # This is for Linux, which requires the blocking form of waitpid to get
1162 # This is for Linux, which requires the blocking form of waitpid to get
1163 # status of a defunct process. This is super-lame. The flag_eof would have
1163 # status of a defunct process. This is super-lame. The flag_eof would have
1164 # been set in read_nonblocking(), so this should be safe.
1164 # been set in read_nonblocking(), so this should be safe.
1165 waitpid_options = 0
1165 waitpid_options = 0
1166 else:
1166 else:
1167 waitpid_options = os.WNOHANG
1167 waitpid_options = os.WNOHANG
1168
1168
1169 try:
1169 try:
1170 pid, status = os.waitpid(self.pid, waitpid_options)
1170 pid, status = os.waitpid(self.pid, waitpid_options)
1171 except OSError as e: # No child processes
1171 except OSError as e: # No child processes
1172 if e.errno == errno.ECHILD:
1172 if e.errno == errno.ECHILD:
1173 raise ExceptionPexpect ('isalive() encountered condition where "terminated" is 0, but there was no child process. Did someone else call waitpid() on our process?')
1173 raise ExceptionPexpect ('isalive() encountered condition where "terminated" is 0, but there was no child process. Did someone else call waitpid() on our process?')
1174 else:
1174 else:
1175 raise e
1175 raise e
1176
1176
1177 # I have to do this twice for Solaris. I can't even believe that I figured this out...
1177 # I have to do this twice for Solaris. I can't even believe that I figured this out...
1178 # If waitpid() returns 0 it means that no child process wishes to
1178 # If waitpid() returns 0 it means that no child process wishes to
1179 # report, and the value of status is undefined.
1179 # report, and the value of status is undefined.
1180 if pid == 0:
1180 if pid == 0:
1181 try:
1181 try:
1182 pid, status = os.waitpid(self.pid, waitpid_options) ### os.WNOHANG) # Solaris!
1182 pid, status = os.waitpid(self.pid, waitpid_options) ### os.WNOHANG) # Solaris!
1183 except OSError as e: # This should never happen...
1183 except OSError as e: # This should never happen...
1184 if e[0] == errno.ECHILD:
1184 if e[0] == errno.ECHILD:
1185 raise ExceptionPexpect ('isalive() encountered condition that should never happen. There was no child process. Did someone else call waitpid() on our process?')
1185 raise ExceptionPexpect ('isalive() encountered condition that should never happen. There was no child process. Did someone else call waitpid() on our process?')
1186 else:
1186 else:
1187 raise e
1187 raise e
1188
1188
1189 # If pid is still 0 after two calls to waitpid() then
1189 # If pid is still 0 after two calls to waitpid() then
1190 # the process really is alive. This seems to work on all platforms, except
1190 # the process really is alive. This seems to work on all platforms, except
1191 # for Irix which seems to require a blocking call on waitpid or select, so I let read_nonblocking
1191 # for Irix which seems to require a blocking call on waitpid or select, so I let read_nonblocking
1192 # take care of this situation (unfortunately, this requires waiting through the timeout).
1192 # take care of this situation (unfortunately, this requires waiting through the timeout).
1193 if pid == 0:
1193 if pid == 0:
1194 return True
1194 return True
1195
1195
1196 if pid == 0:
1196 if pid == 0:
1197 return True
1197 return True
1198
1198
1199 if os.WIFEXITED (status):
1199 if os.WIFEXITED (status):
1200 self.status = status
1200 self.status = status
1201 self.exitstatus = os.WEXITSTATUS(status)
1201 self.exitstatus = os.WEXITSTATUS(status)
1202 self.signalstatus = None
1202 self.signalstatus = None
1203 self.terminated = True
1203 self.terminated = True
1204 elif os.WIFSIGNALED (status):
1204 elif os.WIFSIGNALED (status):
1205 self.status = status
1205 self.status = status
1206 self.exitstatus = None
1206 self.exitstatus = None
1207 self.signalstatus = os.WTERMSIG(status)
1207 self.signalstatus = os.WTERMSIG(status)
1208 self.terminated = True
1208 self.terminated = True
1209 elif os.WIFSTOPPED (status):
1209 elif os.WIFSTOPPED (status):
1210 raise ExceptionPexpect ('isalive() encountered condition where child process is stopped. This is not supported. Is some other process attempting job control with our child pid?')
1210 raise ExceptionPexpect ('isalive() encountered condition where child process is stopped. This is not supported. Is some other process attempting job control with our child pid?')
1211 return False
1211 return False
1212
1212
1213 def kill(self, sig):
1213 def kill(self, sig):
1214
1214
1215 """This sends the given signal to the child application. In keeping
1215 """This sends the given signal to the child application. In keeping
1216 with UNIX tradition it has a misleading name. It does not necessarily
1216 with UNIX tradition it has a misleading name. It does not necessarily
1217 kill the child unless you send the right signal. """
1217 kill the child unless you send the right signal. """
1218
1218
1219 # Same as os.kill, but the pid is given for you.
1219 # Same as os.kill, but the pid is given for you.
1220 if self.isalive():
1220 if self.isalive():
1221 os.kill(self.pid, sig)
1221 os.kill(self.pid, sig)
1222
1222
1223 def compile_pattern_list(self, patterns):
1223 def compile_pattern_list(self, patterns):
1224
1224
1225 """This compiles a pattern-string or a list of pattern-strings.
1225 """This compiles a pattern-string or a list of pattern-strings.
1226 Patterns must be a StringType, EOF, TIMEOUT, SRE_Pattern, or a list of
1226 Patterns must be a StringType, EOF, TIMEOUT, SRE_Pattern, or a list of
1227 those. Patterns may also be None which results in an empty list (you
1227 those. Patterns may also be None which results in an empty list (you
1228 might do this if waiting for an EOF or TIMEOUT condition without
1228 might do this if waiting for an EOF or TIMEOUT condition without
1229 expecting any pattern).
1229 expecting any pattern).
1230
1230
1231 This is used by expect() when calling expect_list(). Thus expect() is
1231 This is used by expect() when calling expect_list(). Thus expect() is
1232 nothing more than::
1232 nothing more than::
1233
1233
1234 cpl = self.compile_pattern_list(pl)
1234 cpl = self.compile_pattern_list(pl)
1235 return self.expect_list(cpl, timeout)
1235 return self.expect_list(cpl, timeout)
1236
1236
1237 If you are using expect() within a loop it may be more
1237 If you are using expect() within a loop it may be more
1238 efficient to compile the patterns first and then call expect_list().
1238 efficient to compile the patterns first and then call expect_list().
1239 This avoid calls in a loop to compile_pattern_list()::
1239 This avoid calls in a loop to compile_pattern_list()::
1240
1240
1241 cpl = self.compile_pattern_list(my_pattern)
1241 cpl = self.compile_pattern_list(my_pattern)
1242 while some_condition:
1242 while some_condition:
1243 ...
1243 ...
1244 i = self.expect_list(clp, timeout)
1244 i = self.expect_list(clp, timeout)
1245 ...
1245 ...
1246 """
1246 """
1247
1247
1248 if patterns is None:
1248 if patterns is None:
1249 return []
1249 return []
1250 if not isinstance(patterns, list):
1250 if not isinstance(patterns, list):
1251 patterns = [patterns]
1251 patterns = [patterns]
1252
1252
1253 compile_flags = re.DOTALL # Allow dot to match \n
1253 compile_flags = re.DOTALL # Allow dot to match \n
1254 if self.ignorecase:
1254 if self.ignorecase:
1255 compile_flags = compile_flags | re.IGNORECASE
1255 compile_flags = compile_flags | re.IGNORECASE
1256 compiled_pattern_list = []
1256 compiled_pattern_list = []
1257 for p in patterns:
1257 for p in patterns:
1258 if isinstance(p, (bytes, unicode)):
1258 if isinstance(p, (bytes, unicode)):
1259 p = self._cast_buffer_type(p)
1259 p = self._cast_buffer_type(p)
1260 compiled_pattern_list.append(re.compile(p, compile_flags))
1260 compiled_pattern_list.append(re.compile(p, compile_flags))
1261 elif p is EOF:
1261 elif p is EOF:
1262 compiled_pattern_list.append(EOF)
1262 compiled_pattern_list.append(EOF)
1263 elif p is TIMEOUT:
1263 elif p is TIMEOUT:
1264 compiled_pattern_list.append(TIMEOUT)
1264 compiled_pattern_list.append(TIMEOUT)
1265 elif type(p) is re_type:
1265 elif type(p) is re_type:
1266 p = self._prepare_regex_pattern(p)
1266 p = self._prepare_regex_pattern(p)
1267 compiled_pattern_list.append(p)
1267 compiled_pattern_list.append(p)
1268 else:
1268 else:
1269 raise TypeError ('Argument must be one of StringTypes, EOF, TIMEOUT, SRE_Pattern, or a list of those type. %s' % str(type(p)))
1269 raise TypeError ('Argument must be one of StringTypes, EOF, TIMEOUT, SRE_Pattern, or a list of those type. %s' % str(type(p)))
1270
1270
1271 return compiled_pattern_list
1271 return compiled_pattern_list
1272
1272
1273 def _prepare_regex_pattern(self, p):
1273 def _prepare_regex_pattern(self, p):
1274 "Recompile unicode regexes as bytes regexes. Overridden in subclass."
1274 "Recompile unicode regexes as bytes regexes. Overridden in subclass."
1275 if isinstance(p.pattern, unicode):
1275 if isinstance(p.pattern, unicode):
1276 p = re.compile(p.pattern.encode('utf-8'), p.flags &~ re.UNICODE)
1276 p = re.compile(p.pattern.encode('utf-8'), p.flags &~ re.UNICODE)
1277 return p
1277 return p
1278
1278
1279 def expect(self, pattern, timeout = -1, searchwindowsize=-1):
1279 def expect(self, pattern, timeout = -1, searchwindowsize=-1):
1280
1280
1281 """This seeks through the stream until a pattern is matched. The
1281 """This seeks through the stream until a pattern is matched. The
1282 pattern is overloaded and may take several types. The pattern can be a
1282 pattern is overloaded and may take several types. The pattern can be a
1283 StringType, EOF, a compiled re, or a list of any of those types.
1283 StringType, EOF, a compiled re, or a list of any of those types.
1284 Strings will be compiled to re types. This returns the index into the
1284 Strings will be compiled to re types. This returns the index into the
1285 pattern list. If the pattern was not a list this returns index 0 on a
1285 pattern list. If the pattern was not a list this returns index 0 on a
1286 successful match. This may raise exceptions for EOF or TIMEOUT. To
1286 successful match. This may raise exceptions for EOF or TIMEOUT. To
1287 avoid the EOF or TIMEOUT exceptions add EOF or TIMEOUT to the pattern
1287 avoid the EOF or TIMEOUT exceptions add EOF or TIMEOUT to the pattern
1288 list. That will cause expect to match an EOF or TIMEOUT condition
1288 list. That will cause expect to match an EOF or TIMEOUT condition
1289 instead of raising an exception.
1289 instead of raising an exception.
1290
1290
1291 If you pass a list of patterns and more than one matches, the first match
1291 If you pass a list of patterns and more than one matches, the first match
1292 in the stream is chosen. If more than one pattern matches at that point,
1292 in the stream is chosen. If more than one pattern matches at that point,
1293 the leftmost in the pattern list is chosen. For example::
1293 the leftmost in the pattern list is chosen. For example::
1294
1294
1295 # the input is 'foobar'
1295 # the input is 'foobar'
1296 index = p.expect (['bar', 'foo', 'foobar'])
1296 index = p.expect (['bar', 'foo', 'foobar'])
1297 # returns 1 ('foo') even though 'foobar' is a "better" match
1297 # returns 1 ('foo') even though 'foobar' is a "better" match
1298
1298
1299 Please note, however, that buffering can affect this behavior, since
1299 Please note, however, that buffering can affect this behavior, since
1300 input arrives in unpredictable chunks. For example::
1300 input arrives in unpredictable chunks. For example::
1301
1301
1302 # the input is 'foobar'
1302 # the input is 'foobar'
1303 index = p.expect (['foobar', 'foo'])
1303 index = p.expect (['foobar', 'foo'])
1304 # returns 0 ('foobar') if all input is available at once,
1304 # returns 0 ('foobar') if all input is available at once,
1305 # but returs 1 ('foo') if parts of the final 'bar' arrive late
1305 # but returs 1 ('foo') if parts of the final 'bar' arrive late
1306
1306
1307 After a match is found the instance attributes 'before', 'after' and
1307 After a match is found the instance attributes 'before', 'after' and
1308 'match' will be set. You can see all the data read before the match in
1308 'match' will be set. You can see all the data read before the match in
1309 'before'. You can see the data that was matched in 'after'. The
1309 'before'. You can see the data that was matched in 'after'. The
1310 re.MatchObject used in the re match will be in 'match'. If an error
1310 re.MatchObject used in the re match will be in 'match'. If an error
1311 occurred then 'before' will be set to all the data read so far and
1311 occurred then 'before' will be set to all the data read so far and
1312 'after' and 'match' will be None.
1312 'after' and 'match' will be None.
1313
1313
1314 If timeout is -1 then timeout will be set to the self.timeout value.
1314 If timeout is -1 then timeout will be set to the self.timeout value.
1315
1315
1316 A list entry may be EOF or TIMEOUT instead of a string. This will
1316 A list entry may be EOF or TIMEOUT instead of a string. This will
1317 catch these exceptions and return the index of the list entry instead
1317 catch these exceptions and return the index of the list entry instead
1318 of raising the exception. The attribute 'after' will be set to the
1318 of raising the exception. The attribute 'after' will be set to the
1319 exception type. The attribute 'match' will be None. This allows you to
1319 exception type. The attribute 'match' will be None. This allows you to
1320 write code like this::
1320 write code like this::
1321
1321
1322 index = p.expect (['good', 'bad', pexpect.EOF, pexpect.TIMEOUT])
1322 index = p.expect (['good', 'bad', pexpect.EOF, pexpect.TIMEOUT])
1323 if index == 0:
1323 if index == 0:
1324 do_something()
1324 do_something()
1325 elif index == 1:
1325 elif index == 1:
1326 do_something_else()
1326 do_something_else()
1327 elif index == 2:
1327 elif index == 2:
1328 do_some_other_thing()
1328 do_some_other_thing()
1329 elif index == 3:
1329 elif index == 3:
1330 do_something_completely_different()
1330 do_something_completely_different()
1331
1331
1332 instead of code like this::
1332 instead of code like this::
1333
1333
1334 try:
1334 try:
1335 index = p.expect (['good', 'bad'])
1335 index = p.expect (['good', 'bad'])
1336 if index == 0:
1336 if index == 0:
1337 do_something()
1337 do_something()
1338 elif index == 1:
1338 elif index == 1:
1339 do_something_else()
1339 do_something_else()
1340 except EOF:
1340 except EOF:
1341 do_some_other_thing()
1341 do_some_other_thing()
1342 except TIMEOUT:
1342 except TIMEOUT:
1343 do_something_completely_different()
1343 do_something_completely_different()
1344
1344
1345 These two forms are equivalent. It all depends on what you want. You
1345 These two forms are equivalent. It all depends on what you want. You
1346 can also just expect the EOF if you are waiting for all output of a
1346 can also just expect the EOF if you are waiting for all output of a
1347 child to finish. For example::
1347 child to finish. For example::
1348
1348
1349 p = pexpect.spawn('/bin/ls')
1349 p = pexpect.spawn('/bin/ls')
1350 p.expect (pexpect.EOF)
1350 p.expect (pexpect.EOF)
1351 print p.before
1351 print p.before
1352
1352
1353 If you are trying to optimize for speed then see expect_list().
1353 If you are trying to optimize for speed then see expect_list().
1354 """
1354 """
1355
1355
1356 compiled_pattern_list = self.compile_pattern_list(pattern)
1356 compiled_pattern_list = self.compile_pattern_list(pattern)
1357 return self.expect_list(compiled_pattern_list, timeout, searchwindowsize)
1357 return self.expect_list(compiled_pattern_list, timeout, searchwindowsize)
1358
1358
1359 def expect_list(self, pattern_list, timeout = -1, searchwindowsize = -1):
1359 def expect_list(self, pattern_list, timeout = -1, searchwindowsize = -1):
1360
1360
1361 """This takes a list of compiled regular expressions and returns the
1361 """This takes a list of compiled regular expressions and returns the
1362 index into the pattern_list that matched the child output. The list may
1362 index into the pattern_list that matched the child output. The list may
1363 also contain EOF or TIMEOUT (which are not compiled regular
1363 also contain EOF or TIMEOUT (which are not compiled regular
1364 expressions). This method is similar to the expect() method except that
1364 expressions). This method is similar to the expect() method except that
1365 expect_list() does not recompile the pattern list on every call. This
1365 expect_list() does not recompile the pattern list on every call. This
1366 may help if you are trying to optimize for speed, otherwise just use
1366 may help if you are trying to optimize for speed, otherwise just use
1367 the expect() method. This is called by expect(). If timeout==-1 then
1367 the expect() method. This is called by expect(). If timeout==-1 then
1368 the self.timeout value is used. If searchwindowsize==-1 then the
1368 the self.timeout value is used. If searchwindowsize==-1 then the
1369 self.searchwindowsize value is used. """
1369 self.searchwindowsize value is used. """
1370
1370
1371 return self.expect_loop(searcher_re(pattern_list), timeout, searchwindowsize)
1371 return self.expect_loop(searcher_re(pattern_list), timeout, searchwindowsize)
1372
1372
1373 def expect_exact(self, pattern_list, timeout = -1, searchwindowsize = -1):
1373 def expect_exact(self, pattern_list, timeout = -1, searchwindowsize = -1):
1374
1374
1375 """This is similar to expect(), but uses plain string matching instead
1375 """This is similar to expect(), but uses plain string matching instead
1376 of compiled regular expressions in 'pattern_list'. The 'pattern_list'
1376 of compiled regular expressions in 'pattern_list'. The 'pattern_list'
1377 may be a string; a list or other sequence of strings; or TIMEOUT and
1377 may be a string; a list or other sequence of strings; or TIMEOUT and
1378 EOF.
1378 EOF.
1379
1379
1380 This call might be faster than expect() for two reasons: string
1380 This call might be faster than expect() for two reasons: string
1381 searching is faster than RE matching and it is possible to limit the
1381 searching is faster than RE matching and it is possible to limit the
1382 search to just the end of the input buffer.
1382 search to just the end of the input buffer.
1383
1383
1384 This method is also useful when you don't want to have to worry about
1384 This method is also useful when you don't want to have to worry about
1385 escaping regular expression characters that you want to match."""
1385 escaping regular expression characters that you want to match."""
1386
1386
1387 if isinstance(pattern_list, (bytes, unicode)) or pattern_list in (TIMEOUT, EOF):
1387 if isinstance(pattern_list, (bytes, unicode)) or pattern_list in (TIMEOUT, EOF):
1388 pattern_list = [pattern_list]
1388 pattern_list = [pattern_list]
1389 return self.expect_loop(searcher_string(pattern_list), timeout, searchwindowsize)
1389 return self.expect_loop(searcher_string(pattern_list), timeout, searchwindowsize)
1390
1390
1391 def expect_loop(self, searcher, timeout = -1, searchwindowsize = -1):
1391 def expect_loop(self, searcher, timeout = -1, searchwindowsize = -1):
1392
1392
1393 """This is the common loop used inside expect. The 'searcher' should be
1393 """This is the common loop used inside expect. The 'searcher' should be
1394 an instance of searcher_re or searcher_string, which describes how and what
1394 an instance of searcher_re or searcher_string, which describes how and what
1395 to search for in the input.
1395 to search for in the input.
1396
1396
1397 See expect() for other arguments, return value and exceptions. """
1397 See expect() for other arguments, return value and exceptions. """
1398
1398
1399 self.searcher = searcher
1399 self.searcher = searcher
1400
1400
1401 if timeout == -1:
1401 if timeout == -1:
1402 timeout = self.timeout
1402 timeout = self.timeout
1403 if timeout is not None:
1403 if timeout is not None:
1404 end_time = time.time() + timeout
1404 end_time = time.time() + timeout
1405 if searchwindowsize == -1:
1405 if searchwindowsize == -1:
1406 searchwindowsize = self.searchwindowsize
1406 searchwindowsize = self.searchwindowsize
1407
1407
1408 try:
1408 try:
1409 incoming = self.buffer
1409 incoming = self.buffer
1410 freshlen = len(incoming)
1410 freshlen = len(incoming)
1411 while True: # Keep reading until exception or return.
1411 while True: # Keep reading until exception or return.
1412 index = searcher.search(incoming, freshlen, searchwindowsize)
1412 index = searcher.search(incoming, freshlen, searchwindowsize)
1413 if index >= 0:
1413 if index >= 0:
1414 self.buffer = incoming[searcher.end : ]
1414 self.buffer = incoming[searcher.end : ]
1415 self.before = incoming[ : searcher.start]
1415 self.before = incoming[ : searcher.start]
1416 self.after = incoming[searcher.start : searcher.end]
1416 self.after = incoming[searcher.start : searcher.end]
1417 self.match = searcher.match
1417 self.match = searcher.match
1418 self.match_index = index
1418 self.match_index = index
1419 return self.match_index
1419 return self.match_index
1420 # No match at this point
1420 # No match at this point
1421 if timeout is not None and timeout < 0:
1421 if timeout is not None and timeout < 0:
1422 raise TIMEOUT ('Timeout exceeded in expect_any().')
1422 raise TIMEOUT ('Timeout exceeded in expect_any().')
1423 # Still have time left, so read more data
1423 # Still have time left, so read more data
1424 c = self.read_nonblocking (self.maxread, timeout)
1424 c = self.read_nonblocking (self.maxread, timeout)
1425 freshlen = len(c)
1425 freshlen = len(c)
1426 time.sleep (0.0001)
1426 time.sleep (0.0001)
1427 incoming = incoming + c
1427 incoming = incoming + c
1428 if timeout is not None:
1428 if timeout is not None:
1429 timeout = end_time - time.time()
1429 timeout = end_time - time.time()
1430 except EOF as e:
1430 except EOF as e:
1431 self.buffer = self._empty_buffer
1431 self.buffer = self._empty_buffer
1432 self.before = incoming
1432 self.before = incoming
1433 self.after = EOF
1433 self.after = EOF
1434 index = searcher.eof_index
1434 index = searcher.eof_index
1435 if index >= 0:
1435 if index >= 0:
1436 self.match = EOF
1436 self.match = EOF
1437 self.match_index = index
1437 self.match_index = index
1438 return self.match_index
1438 return self.match_index
1439 else:
1439 else:
1440 self.match = None
1440 self.match = None
1441 self.match_index = None
1441 self.match_index = None
1442 raise EOF (str(e) + '\n' + str(self))
1442 raise EOF (str(e) + '\n' + str(self))
1443 except TIMEOUT as e:
1443 except TIMEOUT as e:
1444 self.buffer = incoming
1444 self.buffer = incoming
1445 self.before = incoming
1445 self.before = incoming
1446 self.after = TIMEOUT
1446 self.after = TIMEOUT
1447 index = searcher.timeout_index
1447 index = searcher.timeout_index
1448 if index >= 0:
1448 if index >= 0:
1449 self.match = TIMEOUT
1449 self.match = TIMEOUT
1450 self.match_index = index
1450 self.match_index = index
1451 return self.match_index
1451 return self.match_index
1452 else:
1452 else:
1453 self.match = None
1453 self.match = None
1454 self.match_index = None
1454 self.match_index = None
1455 raise TIMEOUT (str(e) + '\n' + str(self))
1455 raise TIMEOUT (str(e) + '\n' + str(self))
1456 except:
1456 except:
1457 self.before = incoming
1457 self.before = incoming
1458 self.after = None
1458 self.after = None
1459 self.match = None
1459 self.match = None
1460 self.match_index = None
1460 self.match_index = None
1461 raise
1461 raise
1462
1462
1463 def getwinsize(self):
1463 def getwinsize(self):
1464
1464
1465 """This returns the terminal window size of the child tty. The return
1465 """This returns the terminal window size of the child tty. The return
1466 value is a tuple of (rows, cols). """
1466 value is a tuple of (rows, cols). """
1467
1467
1468 TIOCGWINSZ = getattr(termios, 'TIOCGWINSZ', 1074295912L)
1468 TIOCGWINSZ = getattr(termios, 'TIOCGWINSZ', 1074295912L)
1469 s = struct.pack('HHHH', 0, 0, 0, 0)
1469 s = struct.pack('HHHH', 0, 0, 0, 0)
1470 x = fcntl.ioctl(self.fileno(), TIOCGWINSZ, s)
1470 x = fcntl.ioctl(self.fileno(), TIOCGWINSZ, s)
1471 return struct.unpack('HHHH', x)[0:2]
1471 return struct.unpack('HHHH', x)[0:2]
1472
1472
1473 def setwinsize(self, r, c):
1473 def setwinsize(self, r, c):
1474
1474
1475 """This sets the terminal window size of the child tty. This will cause
1475 """This sets the terminal window size of the child tty. This will cause
1476 a SIGWINCH signal to be sent to the child. This does not change the
1476 a SIGWINCH signal to be sent to the child. This does not change the
1477 physical window size. It changes the size reported to TTY-aware
1477 physical window size. It changes the size reported to TTY-aware
1478 applications like vi or curses -- applications that respond to the
1478 applications like vi or curses -- applications that respond to the
1479 SIGWINCH signal. """
1479 SIGWINCH signal. """
1480
1480
1481 # Check for buggy platforms. Some Python versions on some platforms
1481 # Check for buggy platforms. Some Python versions on some platforms
1482 # (notably OSF1 Alpha and RedHat 7.1) truncate the value for
1482 # (notably OSF1 Alpha and RedHat 7.1) truncate the value for
1483 # termios.TIOCSWINSZ. It is not clear why this happens.
1483 # termios.TIOCSWINSZ. It is not clear why this happens.
1484 # These platforms don't seem to handle the signed int very well;
1484 # These platforms don't seem to handle the signed int very well;
1485 # yet other platforms like OpenBSD have a large negative value for
1485 # yet other platforms like OpenBSD have a large negative value for
1486 # TIOCSWINSZ and they don't have a truncate problem.
1486 # TIOCSWINSZ and they don't have a truncate problem.
1487 # Newer versions of Linux have totally different values for TIOCSWINSZ.
1487 # Newer versions of Linux have totally different values for TIOCSWINSZ.
1488 # Note that this fix is a hack.
1488 # Note that this fix is a hack.
1489 TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561)
1489 TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561)
1490 if TIOCSWINSZ == 2148037735L: # L is not required in Python >= 2.2.
1490 if TIOCSWINSZ == 2148037735L: # L is not required in Python >= 2.2.
1491 TIOCSWINSZ = -2146929561 # Same bits, but with sign.
1491 TIOCSWINSZ = -2146929561 # Same bits, but with sign.
1492 # Note, assume ws_xpixel and ws_ypixel are zero.
1492 # Note, assume ws_xpixel and ws_ypixel are zero.
1493 s = struct.pack('HHHH', r, c, 0, 0)
1493 s = struct.pack('HHHH', r, c, 0, 0)
1494 fcntl.ioctl(self.fileno(), TIOCSWINSZ, s)
1494 fcntl.ioctl(self.fileno(), TIOCSWINSZ, s)
1495
1495
1496 def interact(self, escape_character = b'\x1d', input_filter = None, output_filter = None):
1496 def interact(self, escape_character = b'\x1d', input_filter = None, output_filter = None):
1497
1497
1498 """This gives control of the child process to the interactive user (the
1498 """This gives control of the child process to the interactive user (the
1499 human at the keyboard). Keystrokes are sent to the child process, and
1499 human at the keyboard). Keystrokes are sent to the child process, and
1500 the stdout and stderr output of the child process is printed. This
1500 the stdout and stderr output of the child process is printed. This
1501 simply echos the child stdout and child stderr to the real stdout and
1501 simply echos the child stdout and child stderr to the real stdout and
1502 it echos the real stdin to the child stdin. When the user types the
1502 it echos the real stdin to the child stdin. When the user types the
1503 escape_character this method will stop. The default for
1503 escape_character this method will stop. The default for
1504 escape_character is ^]. This should not be confused with ASCII 27 --
1504 escape_character is ^]. This should not be confused with ASCII 27 --
1505 the ESC character. ASCII 29 was chosen for historical merit because
1505 the ESC character. ASCII 29 was chosen for historical merit because
1506 this is the character used by 'telnet' as the escape character. The
1506 this is the character used by 'telnet' as the escape character. The
1507 escape_character will not be sent to the child process.
1507 escape_character will not be sent to the child process.
1508
1508
1509 You may pass in optional input and output filter functions. These
1509 You may pass in optional input and output filter functions. These
1510 functions should take a string and return a string. The output_filter
1510 functions should take a string and return a string. The output_filter
1511 will be passed all the output from the child process. The input_filter
1511 will be passed all the output from the child process. The input_filter
1512 will be passed all the keyboard input from the user. The input_filter
1512 will be passed all the keyboard input from the user. The input_filter
1513 is run BEFORE the check for the escape_character.
1513 is run BEFORE the check for the escape_character.
1514
1514
1515 Note that if you change the window size of the parent the SIGWINCH
1515 Note that if you change the window size of the parent the SIGWINCH
1516 signal will not be passed through to the child. If you want the child
1516 signal will not be passed through to the child. If you want the child
1517 window size to change when the parent's window size changes then do
1517 window size to change when the parent's window size changes then do
1518 something like the following example::
1518 something like the following example::
1519
1519
1520 import pexpect, struct, fcntl, termios, signal, sys
1520 import pexpect, struct, fcntl, termios, signal, sys
1521 def sigwinch_passthrough (sig, data):
1521 def sigwinch_passthrough (sig, data):
1522 s = struct.pack("HHHH", 0, 0, 0, 0)
1522 s = struct.pack("HHHH", 0, 0, 0, 0)
1523 a = struct.unpack('hhhh', fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ , s))
1523 a = struct.unpack('hhhh', fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ , s))
1524 global p
1524 global p
1525 p.setwinsize(a[0],a[1])
1525 p.setwinsize(a[0],a[1])
1526 p = pexpect.spawn('/bin/bash') # Note this is global and used in sigwinch_passthrough.
1526 p = pexpect.spawn('/bin/bash') # Note this is global and used in sigwinch_passthrough.
1527 signal.signal(signal.SIGWINCH, sigwinch_passthrough)
1527 signal.signal(signal.SIGWINCH, sigwinch_passthrough)
1528 p.interact()
1528 p.interact()
1529 """
1529 """
1530
1530
1531 # Flush the buffer.
1531 # Flush the buffer.
1532 if PY3: self.stdout.write(_cast_unicode(self.buffer, self.encoding))
1532 if PY3: self.stdout.write(_cast_unicode(self.buffer, self.encoding))
1533 else: self.stdout.write(self.buffer)
1533 else: self.stdout.write(self.buffer)
1534 self.stdout.flush()
1534 self.stdout.flush()
1535 self.buffer = self._empty_buffer
1535 self.buffer = self._empty_buffer
1536 mode = tty.tcgetattr(self.STDIN_FILENO)
1536 mode = tty.tcgetattr(self.STDIN_FILENO)
1537 tty.setraw(self.STDIN_FILENO)
1537 tty.setraw(self.STDIN_FILENO)
1538 try:
1538 try:
1539 self.__interact_copy(escape_character, input_filter, output_filter)
1539 self.__interact_copy(escape_character, input_filter, output_filter)
1540 finally:
1540 finally:
1541 tty.tcsetattr(self.STDIN_FILENO, tty.TCSAFLUSH, mode)
1541 tty.tcsetattr(self.STDIN_FILENO, tty.TCSAFLUSH, mode)
1542
1542
1543 def __interact_writen(self, fd, data):
1543 def __interact_writen(self, fd, data):
1544
1544
1545 """This is used by the interact() method.
1545 """This is used by the interact() method.
1546 """
1546 """
1547
1547
1548 while data != b'' and self.isalive():
1548 while data != b'' and self.isalive():
1549 n = os.write(fd, data)
1549 n = os.write(fd, data)
1550 data = data[n:]
1550 data = data[n:]
1551
1551
1552 def __interact_read(self, fd):
1552 def __interact_read(self, fd):
1553
1553
1554 """This is used by the interact() method.
1554 """This is used by the interact() method.
1555 """
1555 """
1556
1556
1557 return os.read(fd, 1000)
1557 return os.read(fd, 1000)
1558
1558
1559 def __interact_copy(self, escape_character = None, input_filter = None, output_filter = None):
1559 def __interact_copy(self, escape_character = None, input_filter = None, output_filter = None):
1560
1560
1561 """This is used by the interact() method.
1561 """This is used by the interact() method.
1562 """
1562 """
1563
1563
1564 while self.isalive():
1564 while self.isalive():
1565 r,w,e = self.__select([self.child_fd, self.STDIN_FILENO], [], [])
1565 r,w,e = self.__select([self.child_fd, self.STDIN_FILENO], [], [])
1566 if self.child_fd in r:
1566 if self.child_fd in r:
1567 data = self.__interact_read(self.child_fd)
1567 data = self.__interact_read(self.child_fd)
1568 if output_filter: data = output_filter(data)
1568 if output_filter: data = output_filter(data)
1569 if self.logfile is not None:
1569 if self.logfile is not None:
1570 self.logfile.write (data)
1570 self.logfile.write (data)
1571 self.logfile.flush()
1571 self.logfile.flush()
1572 os.write(self.STDOUT_FILENO, data)
1572 os.write(self.STDOUT_FILENO, data)
1573 if self.STDIN_FILENO in r:
1573 if self.STDIN_FILENO in r:
1574 data = self.__interact_read(self.STDIN_FILENO)
1574 data = self.__interact_read(self.STDIN_FILENO)
1575 if input_filter: data = input_filter(data)
1575 if input_filter: data = input_filter(data)
1576 i = data.rfind(escape_character)
1576 i = data.rfind(escape_character)
1577 if i != -1:
1577 if i != -1:
1578 data = data[:i]
1578 data = data[:i]
1579 self.__interact_writen(self.child_fd, data)
1579 self.__interact_writen(self.child_fd, data)
1580 break
1580 break
1581 self.__interact_writen(self.child_fd, data)
1581 self.__interact_writen(self.child_fd, data)
1582
1582
1583 def __select (self, iwtd, owtd, ewtd, timeout=None):
1583 def __select (self, iwtd, owtd, ewtd, timeout=None):
1584
1584
1585 """This is a wrapper around select.select() that ignores signals. If
1585 """This is a wrapper around select.select() that ignores signals. If
1586 select.select raises a select.error exception and errno is an EINTR
1586 select.select raises a select.error exception and errno is an EINTR
1587 error then it is ignored. Mainly this is used to ignore sigwinch
1587 error then it is ignored. Mainly this is used to ignore sigwinch
1588 (terminal resize). """
1588 (terminal resize). """
1589
1589
1590 # if select() is interrupted by a signal (errno==EINTR) then
1590 # if select() is interrupted by a signal (errno==EINTR) then
1591 # we loop back and enter the select() again.
1591 # we loop back and enter the select() again.
1592 if timeout is not None:
1592 if timeout is not None:
1593 end_time = time.time() + timeout
1593 end_time = time.time() + timeout
1594 while True:
1594 while True:
1595 try:
1595 try:
1596 return select.select (iwtd, owtd, ewtd, timeout)
1596 return select.select (iwtd, owtd, ewtd, timeout)
1597 except select.error as e:
1597 except select.error as e:
1598 if e.args[0] == errno.EINTR:
1598 if e.args[0] == errno.EINTR:
1599 # if we loop back we have to subtract the amount of time we already waited.
1599 # if we loop back we have to subtract the amount of time we already waited.
1600 if timeout is not None:
1600 if timeout is not None:
1601 timeout = end_time - time.time()
1601 timeout = end_time - time.time()
1602 if timeout < 0:
1602 if timeout < 0:
1603 return ([],[],[])
1603 return ([],[],[])
1604 else: # something else caused the select.error, so this really is an exception
1604 else: # something else caused the select.error, so this really is an exception
1605 raise
1605 raise
1606
1606
1607 class spawn(spawnb):
1607 class spawn(spawnb):
1608 """This is the main class interface for Pexpect. Use this class to start
1608 """This is the main class interface for Pexpect. Use this class to start
1609 and control child applications."""
1609 and control child applications."""
1610
1610
1611 _buffer_type = unicode
1611 _buffer_type = unicode
1612 def _cast_buffer_type(self, s):
1612 def _cast_buffer_type(self, s):
1613 return _cast_unicode(s, self.encoding)
1613 return _cast_unicode(s, self.encoding)
1614 _empty_buffer = u''
1614 _empty_buffer = u''
1615 _pty_newline = u'\r\n'
1615 _pty_newline = u'\r\n'
1616
1616
1617 def __init__(self, command, args=[], timeout=30, maxread=2000, searchwindowsize=None,
1617 def __init__(self, command, args=[], timeout=30, maxread=2000, searchwindowsize=None,
1618 logfile=None, cwd=None, env=None, encoding='utf-8'):
1618 logfile=None, cwd=None, env=None, encoding='utf-8'):
1619 super(spawn, self).__init__(command, args, timeout=timeout, maxread=maxread,
1619 super(spawn, self).__init__(command, args, timeout=timeout, maxread=maxread,
1620 searchwindowsize=searchwindowsize, logfile=logfile, cwd=cwd, env=env)
1620 searchwindowsize=searchwindowsize, logfile=logfile, cwd=cwd, env=env)
1621 self.encoding = encoding
1621 self.encoding = encoding
1622
1622
1623 def _prepare_regex_pattern(self, p):
1623 def _prepare_regex_pattern(self, p):
1624 "Recompile bytes regexes as unicode regexes."
1624 "Recompile bytes regexes as unicode regexes."
1625 if isinstance(p.pattern, bytes):
1625 if isinstance(p.pattern, bytes):
1626 p = re.compile(p.pattern.decode(self.encoding), p.flags)
1626 p = re.compile(p.pattern.decode(self.encoding), p.flags)
1627 return p
1627 return p
1628
1628
1629 def read_nonblocking(self, size=1, timeout=-1):
1629 def read_nonblocking(self, size=1, timeout=-1):
1630 return super(spawn, self).read_nonblocking(size=size, timeout=timeout)\
1630 return super(spawn, self).read_nonblocking(size=size, timeout=timeout)\
1631 .decode(self.encoding)
1631 .decode(self.encoding)
1632
1632
1633 read_nonblocking.__doc__ = spawnb.read_nonblocking.__doc__
1633 read_nonblocking.__doc__ = spawnb.read_nonblocking.__doc__
1634
1634
1635
1635
1636 ##############################################################################
1636 ##############################################################################
1637 # End of spawn class
1637 # End of spawn class
1638 ##############################################################################
1638 ##############################################################################
1639
1639
1640 class searcher_string (object):
1640 class searcher_string (object):
1641
1641
1642 """This is a plain string search helper for the spawn.expect_any() method.
1642 """This is a plain string search helper for the spawn.expect_any() method.
1643 This helper class is for speed. For more powerful regex patterns
1643 This helper class is for speed. For more powerful regex patterns
1644 see the helper class, searcher_re.
1644 see the helper class, searcher_re.
1645
1645
1646 Attributes:
1646 Attributes:
1647
1647
1648 eof_index - index of EOF, or -1
1648 eof_index - index of EOF, or -1
1649 timeout_index - index of TIMEOUT, or -1
1649 timeout_index - index of TIMEOUT, or -1
1650
1650
1651 After a successful match by the search() method the following attributes
1651 After a successful match by the search() method the following attributes
1652 are available:
1652 are available:
1653
1653
1654 start - index into the buffer, first byte of match
1654 start - index into the buffer, first byte of match
1655 end - index into the buffer, first byte after match
1655 end - index into the buffer, first byte after match
1656 match - the matching string itself
1656 match - the matching string itself
1657
1657
1658 """
1658 """
1659
1659
1660 def __init__(self, strings):
1660 def __init__(self, strings):
1661
1661
1662 """This creates an instance of searcher_string. This argument 'strings'
1662 """This creates an instance of searcher_string. This argument 'strings'
1663 may be a list; a sequence of strings; or the EOF or TIMEOUT types. """
1663 may be a list; a sequence of strings; or the EOF or TIMEOUT types. """
1664
1664
1665 self.eof_index = -1
1665 self.eof_index = -1
1666 self.timeout_index = -1
1666 self.timeout_index = -1
1667 self._strings = []
1667 self._strings = []
1668 for n, s in enumerate(strings):
1668 for n, s in enumerate(strings):
1669 if s is EOF:
1669 if s is EOF:
1670 self.eof_index = n
1670 self.eof_index = n
1671 continue
1671 continue
1672 if s is TIMEOUT:
1672 if s is TIMEOUT:
1673 self.timeout_index = n
1673 self.timeout_index = n
1674 continue
1674 continue
1675 self._strings.append((n, s))
1675 self._strings.append((n, s))
1676
1676
1677 def __str__(self):
1677 def __str__(self):
1678
1678
1679 """This returns a human-readable string that represents the state of
1679 """This returns a human-readable string that represents the state of
1680 the object."""
1680 the object."""
1681
1681
1682 ss = [ (ns[0],' %d: "%s"' % ns) for ns in self._strings ]
1682 ss = [ (ns[0],' %d: "%s"' % ns) for ns in self._strings ]
1683 ss.append((-1,'searcher_string:'))
1683 ss.append((-1,'searcher_string:'))
1684 if self.eof_index >= 0:
1684 if self.eof_index >= 0:
1685 ss.append ((self.eof_index,' %d: EOF' % self.eof_index))
1685 ss.append ((self.eof_index,' %d: EOF' % self.eof_index))
1686 if self.timeout_index >= 0:
1686 if self.timeout_index >= 0:
1687 ss.append ((self.timeout_index,' %d: TIMEOUT' % self.timeout_index))
1687 ss.append ((self.timeout_index,' %d: TIMEOUT' % self.timeout_index))
1688 ss.sort()
1688 ss.sort()
1689 return '\n'.join(a[1] for a in ss)
1689 return '\n'.join(a[1] for a in ss)
1690
1690
1691 def search(self, buffer, freshlen, searchwindowsize=None):
1691 def search(self, buffer, freshlen, searchwindowsize=None):
1692
1692
1693 """This searches 'buffer' for the first occurence of one of the search
1693 """This searches 'buffer' for the first occurence of one of the search
1694 strings. 'freshlen' must indicate the number of bytes at the end of
1694 strings. 'freshlen' must indicate the number of bytes at the end of
1695 'buffer' which have not been searched before. It helps to avoid
1695 'buffer' which have not been searched before. It helps to avoid
1696 searching the same, possibly big, buffer over and over again.
1696 searching the same, possibly big, buffer over and over again.
1697
1697
1698 See class spawn for the 'searchwindowsize' argument.
1698 See class spawn for the 'searchwindowsize' argument.
1699
1699
1700 If there is a match this returns the index of that string, and sets
1700 If there is a match this returns the index of that string, and sets
1701 'start', 'end' and 'match'. Otherwise, this returns -1. """
1701 'start', 'end' and 'match'. Otherwise, this returns -1. """
1702
1702
1703 absurd_match = len(buffer)
1703 absurd_match = len(buffer)
1704 first_match = absurd_match
1704 first_match = absurd_match
1705
1705
1706 # 'freshlen' helps a lot here. Further optimizations could
1706 # 'freshlen' helps a lot here. Further optimizations could
1707 # possibly include:
1707 # possibly include:
1708 #
1708 #
1709 # using something like the Boyer-Moore Fast String Searching
1709 # using something like the Boyer-Moore Fast String Searching
1710 # Algorithm; pre-compiling the search through a list of
1710 # Algorithm; pre-compiling the search through a list of
1711 # strings into something that can scan the input once to
1711 # strings into something that can scan the input once to
1712 # search for all N strings; realize that if we search for
1712 # search for all N strings; realize that if we search for
1713 # ['bar', 'baz'] and the input is '...foo' we need not bother
1713 # ['bar', 'baz'] and the input is '...foo' we need not bother
1714 # rescanning until we've read three more bytes.
1714 # rescanning until we've read three more bytes.
1715 #
1715 #
1716 # Sadly, I don't know enough about this interesting topic. /grahn
1716 # Sadly, I don't know enough about this interesting topic. /grahn
1717
1717
1718 for index, s in self._strings:
1718 for index, s in self._strings:
1719 if searchwindowsize is None:
1719 if searchwindowsize is None:
1720 # the match, if any, can only be in the fresh data,
1720 # the match, if any, can only be in the fresh data,
1721 # or at the very end of the old data
1721 # or at the very end of the old data
1722 offset = -(freshlen+len(s))
1722 offset = -(freshlen+len(s))
1723 else:
1723 else:
1724 # better obey searchwindowsize
1724 # better obey searchwindowsize
1725 offset = -searchwindowsize
1725 offset = -searchwindowsize
1726 n = buffer.find(s, offset)
1726 n = buffer.find(s, offset)
1727 if n >= 0 and n < first_match:
1727 if n >= 0 and n < first_match:
1728 first_match = n
1728 first_match = n
1729 best_index, best_match = index, s
1729 best_index, best_match = index, s
1730 if first_match == absurd_match:
1730 if first_match == absurd_match:
1731 return -1
1731 return -1
1732 self.match = best_match
1732 self.match = best_match
1733 self.start = first_match
1733 self.start = first_match
1734 self.end = self.start + len(self.match)
1734 self.end = self.start + len(self.match)
1735 return best_index
1735 return best_index
1736
1736
1737 class searcher_re (object):
1737 class searcher_re (object):
1738
1738
1739 """This is regular expression string search helper for the
1739 """This is regular expression string search helper for the
1740 spawn.expect_any() method. This helper class is for powerful
1740 spawn.expect_any() method. This helper class is for powerful
1741 pattern matching. For speed, see the helper class, searcher_string.
1741 pattern matching. For speed, see the helper class, searcher_string.
1742
1742
1743 Attributes:
1743 Attributes:
1744
1744
1745 eof_index - index of EOF, or -1
1745 eof_index - index of EOF, or -1
1746 timeout_index - index of TIMEOUT, or -1
1746 timeout_index - index of TIMEOUT, or -1
1747
1747
1748 After a successful match by the search() method the following attributes
1748 After a successful match by the search() method the following attributes
1749 are available:
1749 are available:
1750
1750
1751 start - index into the buffer, first byte of match
1751 start - index into the buffer, first byte of match
1752 end - index into the buffer, first byte after match
1752 end - index into the buffer, first byte after match
1753 match - the re.match object returned by a succesful re.search
1753 match - the re.match object returned by a succesful re.search
1754
1754
1755 """
1755 """
1756
1756
1757 def __init__(self, patterns):
1757 def __init__(self, patterns):
1758
1758
1759 """This creates an instance that searches for 'patterns' Where
1759 """This creates an instance that searches for 'patterns' Where
1760 'patterns' may be a list or other sequence of compiled regular
1760 'patterns' may be a list or other sequence of compiled regular
1761 expressions, or the EOF or TIMEOUT types."""
1761 expressions, or the EOF or TIMEOUT types."""
1762
1762
1763 self.eof_index = -1
1763 self.eof_index = -1
1764 self.timeout_index = -1
1764 self.timeout_index = -1
1765 self._searches = []
1765 self._searches = []
1766 for n, s in enumerate(patterns):
1766 for n, s in enumerate(patterns):
1767 if s is EOF:
1767 if s is EOF:
1768 self.eof_index = n
1768 self.eof_index = n
1769 continue
1769 continue
1770 if s is TIMEOUT:
1770 if s is TIMEOUT:
1771 self.timeout_index = n
1771 self.timeout_index = n
1772 continue
1772 continue
1773 self._searches.append((n, s))
1773 self._searches.append((n, s))
1774
1774
1775 def __str__(self):
1775 def __str__(self):
1776
1776
1777 """This returns a human-readable string that represents the state of
1777 """This returns a human-readable string that represents the state of
1778 the object."""
1778 the object."""
1779
1779
1780 ss = [ (n,' %d: re.compile("%s")' % (n,str(s.pattern))) for n,s in self._searches]
1780 ss = [ (n,' %d: re.compile("%s")' % (n,str(s.pattern))) for n,s in self._searches]
1781 ss.append((-1,'searcher_re:'))
1781 ss.append((-1,'searcher_re:'))
1782 if self.eof_index >= 0:
1782 if self.eof_index >= 0:
1783 ss.append ((self.eof_index,' %d: EOF' % self.eof_index))
1783 ss.append ((self.eof_index,' %d: EOF' % self.eof_index))
1784 if self.timeout_index >= 0:
1784 if self.timeout_index >= 0:
1785 ss.append ((self.timeout_index,' %d: TIMEOUT' % self.timeout_index))
1785 ss.append ((self.timeout_index,' %d: TIMEOUT' % self.timeout_index))
1786 ss.sort()
1786 ss.sort()
1787 return '\n'.join(a[1] for a in ss)
1787 return '\n'.join(a[1] for a in ss)
1788
1788
1789 def search(self, buffer, freshlen, searchwindowsize=None):
1789 def search(self, buffer, freshlen, searchwindowsize=None):
1790
1790
1791 """This searches 'buffer' for the first occurence of one of the regular
1791 """This searches 'buffer' for the first occurence of one of the regular
1792 expressions. 'freshlen' must indicate the number of bytes at the end of
1792 expressions. 'freshlen' must indicate the number of bytes at the end of
1793 'buffer' which have not been searched before.
1793 'buffer' which have not been searched before.
1794
1794
1795 See class spawn for the 'searchwindowsize' argument.
1795 See class spawn for the 'searchwindowsize' argument.
1796
1796
1797 If there is a match this returns the index of that string, and sets
1797 If there is a match this returns the index of that string, and sets
1798 'start', 'end' and 'match'. Otherwise, returns -1."""
1798 'start', 'end' and 'match'. Otherwise, returns -1."""
1799
1799
1800 absurd_match = len(buffer)
1800 absurd_match = len(buffer)
1801 first_match = absurd_match
1801 first_match = absurd_match
1802 # 'freshlen' doesn't help here -- we cannot predict the
1802 # 'freshlen' doesn't help here -- we cannot predict the
1803 # length of a match, and the re module provides no help.
1803 # length of a match, and the re module provides no help.
1804 if searchwindowsize is None:
1804 if searchwindowsize is None:
1805 searchstart = 0
1805 searchstart = 0
1806 else:
1806 else:
1807 searchstart = max(0, len(buffer)-searchwindowsize)
1807 searchstart = max(0, len(buffer)-searchwindowsize)
1808 for index, s in self._searches:
1808 for index, s in self._searches:
1809 match = s.search(buffer, searchstart)
1809 match = s.search(buffer, searchstart)
1810 if match is None:
1810 if match is None:
1811 continue
1811 continue
1812 n = match.start()
1812 n = match.start()
1813 if n < first_match:
1813 if n < first_match:
1814 first_match = n
1814 first_match = n
1815 the_match = match
1815 the_match = match
1816 best_index = index
1816 best_index = index
1817 if first_match == absurd_match:
1817 if first_match == absurd_match:
1818 return -1
1818 return -1
1819 self.start = first_match
1819 self.start = first_match
1820 self.match = the_match
1820 self.match = the_match
1821 self.end = self.match.end()
1821 self.end = self.match.end()
1822 return best_index
1822 return best_index
1823
1823
1824 def which (filename):
1824 def which (filename):
1825
1825
1826 """This takes a given filename; tries to find it in the environment path;
1826 """This takes a given filename; tries to find it in the environment path;
1827 then checks if it is executable. This returns the full path to the filename
1827 then checks if it is executable. This returns the full path to the filename
1828 if found and executable. Otherwise this returns None."""
1828 if found and executable. Otherwise this returns None."""
1829
1829
1830 # Special case where filename already contains a path.
1830 # Special case where filename already contains a path.
1831 if os.path.dirname(filename) != '':
1831 if os.path.dirname(filename) != '':
1832 if os.access (filename, os.X_OK):
1832 if os.access (filename, os.X_OK):
1833 return filename
1833 return filename
1834
1834
1835 if not os.environ.has_key('PATH') or os.environ['PATH'] == '':
1835 if 'PATH' not in os.environ or os.environ['PATH'] == '':
1836 p = os.defpath
1836 p = os.defpath
1837 else:
1837 else:
1838 p = os.environ['PATH']
1838 p = os.environ['PATH']
1839
1839
1840 pathlist = p.split(os.pathsep)
1840 pathlist = p.split(os.pathsep)
1841
1841
1842 for path in pathlist:
1842 for path in pathlist:
1843 f = os.path.join(path, filename)
1843 f = os.path.join(path, filename)
1844 if os.access(f, os.X_OK):
1844 if os.access(f, os.X_OK):
1845 return f
1845 return f
1846 return None
1846 return None
1847
1847
1848 def split_command_line(command_line):
1848 def split_command_line(command_line):
1849
1849
1850 """This splits a command line into a list of arguments. It splits arguments
1850 """This splits a command line into a list of arguments. It splits arguments
1851 on spaces, but handles embedded quotes, doublequotes, and escaped
1851 on spaces, but handles embedded quotes, doublequotes, and escaped
1852 characters. It's impossible to do this with a regular expression, so I
1852 characters. It's impossible to do this with a regular expression, so I
1853 wrote a little state machine to parse the command line. """
1853 wrote a little state machine to parse the command line. """
1854
1854
1855 arg_list = []
1855 arg_list = []
1856 arg = ''
1856 arg = ''
1857
1857
1858 # Constants to name the states we can be in.
1858 # Constants to name the states we can be in.
1859 state_basic = 0
1859 state_basic = 0
1860 state_esc = 1
1860 state_esc = 1
1861 state_singlequote = 2
1861 state_singlequote = 2
1862 state_doublequote = 3
1862 state_doublequote = 3
1863 state_whitespace = 4 # The state of consuming whitespace between commands.
1863 state_whitespace = 4 # The state of consuming whitespace between commands.
1864 state = state_basic
1864 state = state_basic
1865
1865
1866 for c in command_line:
1866 for c in command_line:
1867 if state == state_basic or state == state_whitespace:
1867 if state == state_basic or state == state_whitespace:
1868 if c == '\\': # Escape the next character
1868 if c == '\\': # Escape the next character
1869 state = state_esc
1869 state = state_esc
1870 elif c == r"'": # Handle single quote
1870 elif c == r"'": # Handle single quote
1871 state = state_singlequote
1871 state = state_singlequote
1872 elif c == r'"': # Handle double quote
1872 elif c == r'"': # Handle double quote
1873 state = state_doublequote
1873 state = state_doublequote
1874 elif c.isspace():
1874 elif c.isspace():
1875 # Add arg to arg_list if we aren't in the middle of whitespace.
1875 # Add arg to arg_list if we aren't in the middle of whitespace.
1876 if state == state_whitespace:
1876 if state == state_whitespace:
1877 None # Do nothing.
1877 None # Do nothing.
1878 else:
1878 else:
1879 arg_list.append(arg)
1879 arg_list.append(arg)
1880 arg = ''
1880 arg = ''
1881 state = state_whitespace
1881 state = state_whitespace
1882 else:
1882 else:
1883 arg = arg + c
1883 arg = arg + c
1884 state = state_basic
1884 state = state_basic
1885 elif state == state_esc:
1885 elif state == state_esc:
1886 arg = arg + c
1886 arg = arg + c
1887 state = state_basic
1887 state = state_basic
1888 elif state == state_singlequote:
1888 elif state == state_singlequote:
1889 if c == r"'":
1889 if c == r"'":
1890 state = state_basic
1890 state = state_basic
1891 else:
1891 else:
1892 arg = arg + c
1892 arg = arg + c
1893 elif state == state_doublequote:
1893 elif state == state_doublequote:
1894 if c == r'"':
1894 if c == r'"':
1895 state = state_basic
1895 state = state_basic
1896 else:
1896 else:
1897 arg = arg + c
1897 arg = arg + c
1898
1898
1899 if arg != '':
1899 if arg != '':
1900 arg_list.append(arg)
1900 arg_list.append(arg)
1901 return arg_list
1901 return arg_list
1902
1902
1903 # vi:set sr et ts=4 sw=4 ft=python :
1903 # vi:set sr et ts=4 sw=4 ft=python :
@@ -1,577 +1,577 b''
1 """ A FrontendWidget that emulates the interface of the console IPython and
1 """ A FrontendWidget that emulates the interface of the console IPython and
2 supports the additional functionality provided by the IPython kernel.
2 supports the additional functionality provided by the IPython kernel.
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Imports
6 # Imports
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8
8
9 # Standard library imports
9 # Standard library imports
10 from collections import namedtuple
10 from collections import namedtuple
11 import os.path
11 import os.path
12 import re
12 import re
13 from subprocess import Popen
13 from subprocess import Popen
14 import sys
14 import sys
15 import time
15 import time
16 from textwrap import dedent
16 from textwrap import dedent
17
17
18 # System library imports
18 # System library imports
19 from IPython.external.qt import QtCore, QtGui
19 from IPython.external.qt import QtCore, QtGui
20
20
21 # Local imports
21 # Local imports
22 from IPython.core.inputsplitter import IPythonInputSplitter, \
22 from IPython.core.inputsplitter import IPythonInputSplitter, \
23 transform_ipy_prompt
23 transform_ipy_prompt
24 from IPython.utils.traitlets import Bool, Unicode
24 from IPython.utils.traitlets import Bool, Unicode
25 from frontend_widget import FrontendWidget
25 from frontend_widget import FrontendWidget
26 import styles
26 import styles
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Constants
29 # Constants
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 # Default strings to build and display input and output prompts (and separators
32 # Default strings to build and display input and output prompts (and separators
33 # in between)
33 # in between)
34 default_in_prompt = 'In [<span class="in-prompt-number">%i</span>]: '
34 default_in_prompt = 'In [<span class="in-prompt-number">%i</span>]: '
35 default_out_prompt = 'Out[<span class="out-prompt-number">%i</span>]: '
35 default_out_prompt = 'Out[<span class="out-prompt-number">%i</span>]: '
36 default_input_sep = '\n'
36 default_input_sep = '\n'
37 default_output_sep = ''
37 default_output_sep = ''
38 default_output_sep2 = ''
38 default_output_sep2 = ''
39
39
40 # Base path for most payload sources.
40 # Base path for most payload sources.
41 zmq_shell_source = 'IPython.zmq.zmqshell.ZMQInteractiveShell'
41 zmq_shell_source = 'IPython.zmq.zmqshell.ZMQInteractiveShell'
42
42
43 if sys.platform.startswith('win'):
43 if sys.platform.startswith('win'):
44 default_editor = 'notepad'
44 default_editor = 'notepad'
45 else:
45 else:
46 default_editor = ''
46 default_editor = ''
47
47
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49 # IPythonWidget class
49 # IPythonWidget class
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51
51
52 class IPythonWidget(FrontendWidget):
52 class IPythonWidget(FrontendWidget):
53 """ A FrontendWidget for an IPython kernel.
53 """ A FrontendWidget for an IPython kernel.
54 """
54 """
55
55
56 # If set, the 'custom_edit_requested(str, int)' signal will be emitted when
56 # If set, the 'custom_edit_requested(str, int)' signal will be emitted when
57 # an editor is needed for a file. This overrides 'editor' and 'editor_line'
57 # an editor is needed for a file. This overrides 'editor' and 'editor_line'
58 # settings.
58 # settings.
59 custom_edit = Bool(False)
59 custom_edit = Bool(False)
60 custom_edit_requested = QtCore.Signal(object, object)
60 custom_edit_requested = QtCore.Signal(object, object)
61
61
62 editor = Unicode(default_editor, config=True,
62 editor = Unicode(default_editor, config=True,
63 help="""
63 help="""
64 A command for invoking a system text editor. If the string contains a
64 A command for invoking a system text editor. If the string contains a
65 {filename} format specifier, it will be used. Otherwise, the filename
65 {filename} format specifier, it will be used. Otherwise, the filename
66 will be appended to the end the command.
66 will be appended to the end the command.
67 """)
67 """)
68
68
69 editor_line = Unicode(config=True,
69 editor_line = Unicode(config=True,
70 help="""
70 help="""
71 The editor command to use when a specific line number is requested. The
71 The editor command to use when a specific line number is requested. The
72 string should contain two format specifiers: {line} and {filename}. If
72 string should contain two format specifiers: {line} and {filename}. If
73 this parameter is not specified, the line number option to the %edit
73 this parameter is not specified, the line number option to the %edit
74 magic will be ignored.
74 magic will be ignored.
75 """)
75 """)
76
76
77 style_sheet = Unicode(config=True,
77 style_sheet = Unicode(config=True,
78 help="""
78 help="""
79 A CSS stylesheet. The stylesheet can contain classes for:
79 A CSS stylesheet. The stylesheet can contain classes for:
80 1. Qt: QPlainTextEdit, QFrame, QWidget, etc
80 1. Qt: QPlainTextEdit, QFrame, QWidget, etc
81 2. Pygments: .c, .k, .o, etc. (see PygmentsHighlighter)
81 2. Pygments: .c, .k, .o, etc. (see PygmentsHighlighter)
82 3. IPython: .error, .in-prompt, .out-prompt, etc
82 3. IPython: .error, .in-prompt, .out-prompt, etc
83 """)
83 """)
84
84
85 syntax_style = Unicode(config=True,
85 syntax_style = Unicode(config=True,
86 help="""
86 help="""
87 If not empty, use this Pygments style for syntax highlighting.
87 If not empty, use this Pygments style for syntax highlighting.
88 Otherwise, the style sheet is queried for Pygments style
88 Otherwise, the style sheet is queried for Pygments style
89 information.
89 information.
90 """)
90 """)
91
91
92 # Prompts.
92 # Prompts.
93 in_prompt = Unicode(default_in_prompt, config=True)
93 in_prompt = Unicode(default_in_prompt, config=True)
94 out_prompt = Unicode(default_out_prompt, config=True)
94 out_prompt = Unicode(default_out_prompt, config=True)
95 input_sep = Unicode(default_input_sep, config=True)
95 input_sep = Unicode(default_input_sep, config=True)
96 output_sep = Unicode(default_output_sep, config=True)
96 output_sep = Unicode(default_output_sep, config=True)
97 output_sep2 = Unicode(default_output_sep2, config=True)
97 output_sep2 = Unicode(default_output_sep2, config=True)
98
98
99 # FrontendWidget protected class variables.
99 # FrontendWidget protected class variables.
100 _input_splitter_class = IPythonInputSplitter
100 _input_splitter_class = IPythonInputSplitter
101 _transform_prompt = staticmethod(transform_ipy_prompt)
101 _transform_prompt = staticmethod(transform_ipy_prompt)
102
102
103 # IPythonWidget protected class variables.
103 # IPythonWidget protected class variables.
104 _PromptBlock = namedtuple('_PromptBlock', ['block', 'length', 'number'])
104 _PromptBlock = namedtuple('_PromptBlock', ['block', 'length', 'number'])
105 _payload_source_edit = zmq_shell_source + '.edit_magic'
105 _payload_source_edit = zmq_shell_source + '.edit_magic'
106 _payload_source_exit = zmq_shell_source + '.ask_exit'
106 _payload_source_exit = zmq_shell_source + '.ask_exit'
107 _payload_source_next_input = zmq_shell_source + '.set_next_input'
107 _payload_source_next_input = zmq_shell_source + '.set_next_input'
108 _payload_source_page = 'IPython.zmq.page.page'
108 _payload_source_page = 'IPython.zmq.page.page'
109 _retrying_history_request = False
109 _retrying_history_request = False
110
110
111 #---------------------------------------------------------------------------
111 #---------------------------------------------------------------------------
112 # 'object' interface
112 # 'object' interface
113 #---------------------------------------------------------------------------
113 #---------------------------------------------------------------------------
114
114
115 def __init__(self, *args, **kw):
115 def __init__(self, *args, **kw):
116 super(IPythonWidget, self).__init__(*args, **kw)
116 super(IPythonWidget, self).__init__(*args, **kw)
117
117
118 # IPythonWidget protected variables.
118 # IPythonWidget protected variables.
119 self._payload_handlers = {
119 self._payload_handlers = {
120 self._payload_source_edit : self._handle_payload_edit,
120 self._payload_source_edit : self._handle_payload_edit,
121 self._payload_source_exit : self._handle_payload_exit,
121 self._payload_source_exit : self._handle_payload_exit,
122 self._payload_source_page : self._handle_payload_page,
122 self._payload_source_page : self._handle_payload_page,
123 self._payload_source_next_input : self._handle_payload_next_input }
123 self._payload_source_next_input : self._handle_payload_next_input }
124 self._previous_prompt_obj = None
124 self._previous_prompt_obj = None
125 self._keep_kernel_on_exit = None
125 self._keep_kernel_on_exit = None
126
126
127 # Initialize widget styling.
127 # Initialize widget styling.
128 if self.style_sheet:
128 if self.style_sheet:
129 self._style_sheet_changed()
129 self._style_sheet_changed()
130 self._syntax_style_changed()
130 self._syntax_style_changed()
131 else:
131 else:
132 self.set_default_style()
132 self.set_default_style()
133
133
134 #---------------------------------------------------------------------------
134 #---------------------------------------------------------------------------
135 # 'BaseFrontendMixin' abstract interface
135 # 'BaseFrontendMixin' abstract interface
136 #---------------------------------------------------------------------------
136 #---------------------------------------------------------------------------
137
137
138 def _handle_complete_reply(self, rep):
138 def _handle_complete_reply(self, rep):
139 """ Reimplemented to support IPython's improved completion machinery.
139 """ Reimplemented to support IPython's improved completion machinery.
140 """
140 """
141 self.log.debug("complete: %s", rep.get('content', ''))
141 self.log.debug("complete: %s", rep.get('content', ''))
142 cursor = self._get_cursor()
142 cursor = self._get_cursor()
143 info = self._request_info.get('complete')
143 info = self._request_info.get('complete')
144 if info and info.id == rep['parent_header']['msg_id'] and \
144 if info and info.id == rep['parent_header']['msg_id'] and \
145 info.pos == cursor.position():
145 info.pos == cursor.position():
146 matches = rep['content']['matches']
146 matches = rep['content']['matches']
147 text = rep['content']['matched_text']
147 text = rep['content']['matched_text']
148 offset = len(text)
148 offset = len(text)
149
149
150 # Clean up matches with period and path separators if the matched
150 # Clean up matches with period and path separators if the matched
151 # text has not been transformed. This is done by truncating all
151 # text has not been transformed. This is done by truncating all
152 # but the last component and then suitably decreasing the offset
152 # but the last component and then suitably decreasing the offset
153 # between the current cursor position and the start of completion.
153 # between the current cursor position and the start of completion.
154 if len(matches) > 1 and matches[0][:offset] == text:
154 if len(matches) > 1 and matches[0][:offset] == text:
155 parts = re.split(r'[./\\]', text)
155 parts = re.split(r'[./\\]', text)
156 sep_count = len(parts) - 1
156 sep_count = len(parts) - 1
157 if sep_count:
157 if sep_count:
158 chop_length = sum(map(len, parts[:sep_count])) + sep_count
158 chop_length = sum(map(len, parts[:sep_count])) + sep_count
159 matches = [ match[chop_length:] for match in matches ]
159 matches = [ match[chop_length:] for match in matches ]
160 offset -= chop_length
160 offset -= chop_length
161
161
162 # Move the cursor to the start of the match and complete.
162 # Move the cursor to the start of the match and complete.
163 cursor.movePosition(QtGui.QTextCursor.Left, n=offset)
163 cursor.movePosition(QtGui.QTextCursor.Left, n=offset)
164 self._complete_with_items(cursor, matches)
164 self._complete_with_items(cursor, matches)
165
165
166 def _handle_execute_reply(self, msg):
166 def _handle_execute_reply(self, msg):
167 """ Reimplemented to support prompt requests.
167 """ Reimplemented to support prompt requests.
168 """
168 """
169 msg_id = msg['parent_header'].get('msg_id')
169 msg_id = msg['parent_header'].get('msg_id')
170 info = self._request_info['execute'].get(msg_id)
170 info = self._request_info['execute'].get(msg_id)
171 if info and info.kind == 'prompt':
171 if info and info.kind == 'prompt':
172 number = msg['content']['execution_count'] + 1
172 number = msg['content']['execution_count'] + 1
173 self._show_interpreter_prompt(number)
173 self._show_interpreter_prompt(number)
174 self._request_info['execute'].pop(msg_id)
174 self._request_info['execute'].pop(msg_id)
175 else:
175 else:
176 super(IPythonWidget, self)._handle_execute_reply(msg)
176 super(IPythonWidget, self)._handle_execute_reply(msg)
177
177
178 def _handle_history_reply(self, msg):
178 def _handle_history_reply(self, msg):
179 """ Implemented to handle history tail replies, which are only supported
179 """ Implemented to handle history tail replies, which are only supported
180 by the IPython kernel.
180 by the IPython kernel.
181 """
181 """
182 content = msg['content']
182 content = msg['content']
183 if 'history' not in content:
183 if 'history' not in content:
184 self.log.error("History request failed: %r"%content)
184 self.log.error("History request failed: %r"%content)
185 if content.get('status', '') == 'aborted' and \
185 if content.get('status', '') == 'aborted' and \
186 not self._retrying_history_request:
186 not self._retrying_history_request:
187 # a *different* action caused this request to be aborted, so
187 # a *different* action caused this request to be aborted, so
188 # we should try again.
188 # we should try again.
189 self.log.error("Retrying aborted history request")
189 self.log.error("Retrying aborted history request")
190 # prevent multiple retries of aborted requests:
190 # prevent multiple retries of aborted requests:
191 self._retrying_history_request = True
191 self._retrying_history_request = True
192 # wait out the kernel's queue flush, which is currently timed at 0.1s
192 # wait out the kernel's queue flush, which is currently timed at 0.1s
193 time.sleep(0.25)
193 time.sleep(0.25)
194 self.kernel_manager.shell_channel.history(hist_access_type='tail',n=1000)
194 self.kernel_manager.shell_channel.history(hist_access_type='tail',n=1000)
195 else:
195 else:
196 self._retrying_history_request = False
196 self._retrying_history_request = False
197 return
197 return
198 # reset retry flag
198 # reset retry flag
199 self._retrying_history_request = False
199 self._retrying_history_request = False
200 history_items = content['history']
200 history_items = content['history']
201 self.log.debug("Received history reply with %i entries", len(history_items))
201 self.log.debug("Received history reply with %i entries", len(history_items))
202 items = []
202 items = []
203 last_cell = u""
203 last_cell = u""
204 for _, _, cell in history_items:
204 for _, _, cell in history_items:
205 cell = cell.rstrip()
205 cell = cell.rstrip()
206 if cell != last_cell:
206 if cell != last_cell:
207 items.append(cell)
207 items.append(cell)
208 last_cell = cell
208 last_cell = cell
209 self._set_history(items)
209 self._set_history(items)
210
210
211 def _handle_pyout(self, msg):
211 def _handle_pyout(self, msg):
212 """ Reimplemented for IPython-style "display hook".
212 """ Reimplemented for IPython-style "display hook".
213 """
213 """
214 self.log.debug("pyout: %s", msg.get('content', ''))
214 self.log.debug("pyout: %s", msg.get('content', ''))
215 if not self._hidden and self._is_from_this_session(msg):
215 if not self._hidden and self._is_from_this_session(msg):
216 content = msg['content']
216 content = msg['content']
217 prompt_number = content.get('execution_count', 0)
217 prompt_number = content.get('execution_count', 0)
218 data = content['data']
218 data = content['data']
219 if data.has_key('text/html'):
219 if 'text/html' in data:
220 self._append_plain_text(self.output_sep, True)
220 self._append_plain_text(self.output_sep, True)
221 self._append_html(self._make_out_prompt(prompt_number), True)
221 self._append_html(self._make_out_prompt(prompt_number), True)
222 html = data['text/html']
222 html = data['text/html']
223 self._append_plain_text('\n', True)
223 self._append_plain_text('\n', True)
224 self._append_html(html + self.output_sep2, True)
224 self._append_html(html + self.output_sep2, True)
225 elif data.has_key('text/plain'):
225 elif 'text/plain' in data:
226 self._append_plain_text(self.output_sep, True)
226 self._append_plain_text(self.output_sep, True)
227 self._append_html(self._make_out_prompt(prompt_number), True)
227 self._append_html(self._make_out_prompt(prompt_number), True)
228 text = data['text/plain']
228 text = data['text/plain']
229 # If the repr is multiline, make sure we start on a new line,
229 # If the repr is multiline, make sure we start on a new line,
230 # so that its lines are aligned.
230 # so that its lines are aligned.
231 if "\n" in text and not self.output_sep.endswith("\n"):
231 if "\n" in text and not self.output_sep.endswith("\n"):
232 self._append_plain_text('\n', True)
232 self._append_plain_text('\n', True)
233 self._append_plain_text(text + self.output_sep2, True)
233 self._append_plain_text(text + self.output_sep2, True)
234
234
235 def _handle_display_data(self, msg):
235 def _handle_display_data(self, msg):
236 """ The base handler for the ``display_data`` message.
236 """ The base handler for the ``display_data`` message.
237 """
237 """
238 self.log.debug("display: %s", msg.get('content', ''))
238 self.log.debug("display: %s", msg.get('content', ''))
239 # For now, we don't display data from other frontends, but we
239 # For now, we don't display data from other frontends, but we
240 # eventually will as this allows all frontends to monitor the display
240 # eventually will as this allows all frontends to monitor the display
241 # data. But we need to figure out how to handle this in the GUI.
241 # data. But we need to figure out how to handle this in the GUI.
242 if not self._hidden and self._is_from_this_session(msg):
242 if not self._hidden and self._is_from_this_session(msg):
243 source = msg['content']['source']
243 source = msg['content']['source']
244 data = msg['content']['data']
244 data = msg['content']['data']
245 metadata = msg['content']['metadata']
245 metadata = msg['content']['metadata']
246 # In the regular IPythonWidget, we simply print the plain text
246 # In the regular IPythonWidget, we simply print the plain text
247 # representation.
247 # representation.
248 if data.has_key('text/html'):
248 if 'text/html' in data:
249 html = data['text/html']
249 html = data['text/html']
250 self._append_html(html, True)
250 self._append_html(html, True)
251 elif data.has_key('text/plain'):
251 elif 'text/plain' in data:
252 text = data['text/plain']
252 text = data['text/plain']
253 self._append_plain_text(text, True)
253 self._append_plain_text(text, True)
254 # This newline seems to be needed for text and html output.
254 # This newline seems to be needed for text and html output.
255 self._append_plain_text(u'\n', True)
255 self._append_plain_text(u'\n', True)
256
256
257 def _started_channels(self):
257 def _started_channels(self):
258 """Reimplemented to make a history request and load %guiref."""
258 """Reimplemented to make a history request and load %guiref."""
259 super(IPythonWidget, self)._started_channels()
259 super(IPythonWidget, self)._started_channels()
260 self._load_guiref_magic()
260 self._load_guiref_magic()
261 self.kernel_manager.shell_channel.history(hist_access_type='tail',
261 self.kernel_manager.shell_channel.history(hist_access_type='tail',
262 n=1000)
262 n=1000)
263
263
264 def _started_kernel(self):
264 def _started_kernel(self):
265 """Load %guiref when the kernel starts (if channels are also started).
265 """Load %guiref when the kernel starts (if channels are also started).
266
266
267 Principally triggered by kernel restart.
267 Principally triggered by kernel restart.
268 """
268 """
269 if self.kernel_manager.shell_channel is not None:
269 if self.kernel_manager.shell_channel is not None:
270 self._load_guiref_magic()
270 self._load_guiref_magic()
271
271
272 def _load_guiref_magic(self):
272 def _load_guiref_magic(self):
273 """Load %guiref magic."""
273 """Load %guiref magic."""
274 self.kernel_manager.shell_channel.execute('\n'.join([
274 self.kernel_manager.shell_channel.execute('\n'.join([
275 "from IPython.core import usage",
275 "from IPython.core import usage",
276 "get_ipython().register_magic_function(usage.page_guiref, 'line', 'guiref')",
276 "get_ipython().register_magic_function(usage.page_guiref, 'line', 'guiref')",
277 ]), silent=True)
277 ]), silent=True)
278
278
279 #---------------------------------------------------------------------------
279 #---------------------------------------------------------------------------
280 # 'ConsoleWidget' public interface
280 # 'ConsoleWidget' public interface
281 #---------------------------------------------------------------------------
281 #---------------------------------------------------------------------------
282
282
283 #---------------------------------------------------------------------------
283 #---------------------------------------------------------------------------
284 # 'FrontendWidget' public interface
284 # 'FrontendWidget' public interface
285 #---------------------------------------------------------------------------
285 #---------------------------------------------------------------------------
286
286
287 def execute_file(self, path, hidden=False):
287 def execute_file(self, path, hidden=False):
288 """ Reimplemented to use the 'run' magic.
288 """ Reimplemented to use the 'run' magic.
289 """
289 """
290 # Use forward slashes on Windows to avoid escaping each separator.
290 # Use forward slashes on Windows to avoid escaping each separator.
291 if sys.platform == 'win32':
291 if sys.platform == 'win32':
292 path = os.path.normpath(path).replace('\\', '/')
292 path = os.path.normpath(path).replace('\\', '/')
293
293
294 # Perhaps we should not be using %run directly, but while we
294 # Perhaps we should not be using %run directly, but while we
295 # are, it is necessary to quote or escape filenames containing spaces
295 # are, it is necessary to quote or escape filenames containing spaces
296 # or quotes.
296 # or quotes.
297
297
298 # In earlier code here, to minimize escaping, we sometimes quoted the
298 # In earlier code here, to minimize escaping, we sometimes quoted the
299 # filename with single quotes. But to do this, this code must be
299 # filename with single quotes. But to do this, this code must be
300 # platform-aware, because run uses shlex rather than python string
300 # platform-aware, because run uses shlex rather than python string
301 # parsing, so that:
301 # parsing, so that:
302 # * In Win: single quotes can be used in the filename without quoting,
302 # * In Win: single quotes can be used in the filename without quoting,
303 # and we cannot use single quotes to quote the filename.
303 # and we cannot use single quotes to quote the filename.
304 # * In *nix: we can escape double quotes in a double quoted filename,
304 # * In *nix: we can escape double quotes in a double quoted filename,
305 # but can't escape single quotes in a single quoted filename.
305 # but can't escape single quotes in a single quoted filename.
306
306
307 # So to keep this code non-platform-specific and simple, we now only
307 # So to keep this code non-platform-specific and simple, we now only
308 # use double quotes to quote filenames, and escape when needed:
308 # use double quotes to quote filenames, and escape when needed:
309 if ' ' in path or "'" in path or '"' in path:
309 if ' ' in path or "'" in path or '"' in path:
310 path = '"%s"' % path.replace('"', '\\"')
310 path = '"%s"' % path.replace('"', '\\"')
311 self.execute('%%run %s' % path, hidden=hidden)
311 self.execute('%%run %s' % path, hidden=hidden)
312
312
313 #---------------------------------------------------------------------------
313 #---------------------------------------------------------------------------
314 # 'FrontendWidget' protected interface
314 # 'FrontendWidget' protected interface
315 #---------------------------------------------------------------------------
315 #---------------------------------------------------------------------------
316
316
317 def _complete(self):
317 def _complete(self):
318 """ Reimplemented to support IPython's improved completion machinery.
318 """ Reimplemented to support IPython's improved completion machinery.
319 """
319 """
320 # We let the kernel split the input line, so we *always* send an empty
320 # We let the kernel split the input line, so we *always* send an empty
321 # text field. Readline-based frontends do get a real text field which
321 # text field. Readline-based frontends do get a real text field which
322 # they can use.
322 # they can use.
323 text = ''
323 text = ''
324
324
325 # Send the completion request to the kernel
325 # Send the completion request to the kernel
326 msg_id = self.kernel_manager.shell_channel.complete(
326 msg_id = self.kernel_manager.shell_channel.complete(
327 text, # text
327 text, # text
328 self._get_input_buffer_cursor_line(), # line
328 self._get_input_buffer_cursor_line(), # line
329 self._get_input_buffer_cursor_column(), # cursor_pos
329 self._get_input_buffer_cursor_column(), # cursor_pos
330 self.input_buffer) # block
330 self.input_buffer) # block
331 pos = self._get_cursor().position()
331 pos = self._get_cursor().position()
332 info = self._CompletionRequest(msg_id, pos)
332 info = self._CompletionRequest(msg_id, pos)
333 self._request_info['complete'] = info
333 self._request_info['complete'] = info
334
334
335 def _process_execute_error(self, msg):
335 def _process_execute_error(self, msg):
336 """ Reimplemented for IPython-style traceback formatting.
336 """ Reimplemented for IPython-style traceback formatting.
337 """
337 """
338 content = msg['content']
338 content = msg['content']
339 traceback = '\n'.join(content['traceback']) + '\n'
339 traceback = '\n'.join(content['traceback']) + '\n'
340 if False:
340 if False:
341 # FIXME: For now, tracebacks come as plain text, so we can't use
341 # FIXME: For now, tracebacks come as plain text, so we can't use
342 # the html renderer yet. Once we refactor ultratb to produce
342 # the html renderer yet. Once we refactor ultratb to produce
343 # properly styled tracebacks, this branch should be the default
343 # properly styled tracebacks, this branch should be the default
344 traceback = traceback.replace(' ', '&nbsp;')
344 traceback = traceback.replace(' ', '&nbsp;')
345 traceback = traceback.replace('\n', '<br/>')
345 traceback = traceback.replace('\n', '<br/>')
346
346
347 ename = content['ename']
347 ename = content['ename']
348 ename_styled = '<span class="error">%s</span>' % ename
348 ename_styled = '<span class="error">%s</span>' % ename
349 traceback = traceback.replace(ename, ename_styled)
349 traceback = traceback.replace(ename, ename_styled)
350
350
351 self._append_html(traceback)
351 self._append_html(traceback)
352 else:
352 else:
353 # This is the fallback for now, using plain text with ansi escapes
353 # This is the fallback for now, using plain text with ansi escapes
354 self._append_plain_text(traceback)
354 self._append_plain_text(traceback)
355
355
356 def _process_execute_payload(self, item):
356 def _process_execute_payload(self, item):
357 """ Reimplemented to dispatch payloads to handler methods.
357 """ Reimplemented to dispatch payloads to handler methods.
358 """
358 """
359 handler = self._payload_handlers.get(item['source'])
359 handler = self._payload_handlers.get(item['source'])
360 if handler is None:
360 if handler is None:
361 # We have no handler for this type of payload, simply ignore it
361 # We have no handler for this type of payload, simply ignore it
362 return False
362 return False
363 else:
363 else:
364 handler(item)
364 handler(item)
365 return True
365 return True
366
366
367 def _show_interpreter_prompt(self, number=None):
367 def _show_interpreter_prompt(self, number=None):
368 """ Reimplemented for IPython-style prompts.
368 """ Reimplemented for IPython-style prompts.
369 """
369 """
370 # If a number was not specified, make a prompt number request.
370 # If a number was not specified, make a prompt number request.
371 if number is None:
371 if number is None:
372 msg_id = self.kernel_manager.shell_channel.execute('', silent=True)
372 msg_id = self.kernel_manager.shell_channel.execute('', silent=True)
373 info = self._ExecutionRequest(msg_id, 'prompt')
373 info = self._ExecutionRequest(msg_id, 'prompt')
374 self._request_info['execute'][msg_id] = info
374 self._request_info['execute'][msg_id] = info
375 return
375 return
376
376
377 # Show a new prompt and save information about it so that it can be
377 # Show a new prompt and save information about it so that it can be
378 # updated later if the prompt number turns out to be wrong.
378 # updated later if the prompt number turns out to be wrong.
379 self._prompt_sep = self.input_sep
379 self._prompt_sep = self.input_sep
380 self._show_prompt(self._make_in_prompt(number), html=True)
380 self._show_prompt(self._make_in_prompt(number), html=True)
381 block = self._control.document().lastBlock()
381 block = self._control.document().lastBlock()
382 length = len(self._prompt)
382 length = len(self._prompt)
383 self._previous_prompt_obj = self._PromptBlock(block, length, number)
383 self._previous_prompt_obj = self._PromptBlock(block, length, number)
384
384
385 # Update continuation prompt to reflect (possibly) new prompt length.
385 # Update continuation prompt to reflect (possibly) new prompt length.
386 self._set_continuation_prompt(
386 self._set_continuation_prompt(
387 self._make_continuation_prompt(self._prompt), html=True)
387 self._make_continuation_prompt(self._prompt), html=True)
388
388
389 def _show_interpreter_prompt_for_reply(self, msg):
389 def _show_interpreter_prompt_for_reply(self, msg):
390 """ Reimplemented for IPython-style prompts.
390 """ Reimplemented for IPython-style prompts.
391 """
391 """
392 # Update the old prompt number if necessary.
392 # Update the old prompt number if necessary.
393 content = msg['content']
393 content = msg['content']
394 # abort replies do not have any keys:
394 # abort replies do not have any keys:
395 if content['status'] == 'aborted':
395 if content['status'] == 'aborted':
396 if self._previous_prompt_obj:
396 if self._previous_prompt_obj:
397 previous_prompt_number = self._previous_prompt_obj.number
397 previous_prompt_number = self._previous_prompt_obj.number
398 else:
398 else:
399 previous_prompt_number = 0
399 previous_prompt_number = 0
400 else:
400 else:
401 previous_prompt_number = content['execution_count']
401 previous_prompt_number = content['execution_count']
402 if self._previous_prompt_obj and \
402 if self._previous_prompt_obj and \
403 self._previous_prompt_obj.number != previous_prompt_number:
403 self._previous_prompt_obj.number != previous_prompt_number:
404 block = self._previous_prompt_obj.block
404 block = self._previous_prompt_obj.block
405
405
406 # Make sure the prompt block has not been erased.
406 # Make sure the prompt block has not been erased.
407 if block.isValid() and block.text():
407 if block.isValid() and block.text():
408
408
409 # Remove the old prompt and insert a new prompt.
409 # Remove the old prompt and insert a new prompt.
410 cursor = QtGui.QTextCursor(block)
410 cursor = QtGui.QTextCursor(block)
411 cursor.movePosition(QtGui.QTextCursor.Right,
411 cursor.movePosition(QtGui.QTextCursor.Right,
412 QtGui.QTextCursor.KeepAnchor,
412 QtGui.QTextCursor.KeepAnchor,
413 self._previous_prompt_obj.length)
413 self._previous_prompt_obj.length)
414 prompt = self._make_in_prompt(previous_prompt_number)
414 prompt = self._make_in_prompt(previous_prompt_number)
415 self._prompt = self._insert_html_fetching_plain_text(
415 self._prompt = self._insert_html_fetching_plain_text(
416 cursor, prompt)
416 cursor, prompt)
417
417
418 # When the HTML is inserted, Qt blows away the syntax
418 # When the HTML is inserted, Qt blows away the syntax
419 # highlighting for the line, so we need to rehighlight it.
419 # highlighting for the line, so we need to rehighlight it.
420 self._highlighter.rehighlightBlock(cursor.block())
420 self._highlighter.rehighlightBlock(cursor.block())
421
421
422 self._previous_prompt_obj = None
422 self._previous_prompt_obj = None
423
423
424 # Show a new prompt with the kernel's estimated prompt number.
424 # Show a new prompt with the kernel's estimated prompt number.
425 self._show_interpreter_prompt(previous_prompt_number + 1)
425 self._show_interpreter_prompt(previous_prompt_number + 1)
426
426
427 #---------------------------------------------------------------------------
427 #---------------------------------------------------------------------------
428 # 'IPythonWidget' interface
428 # 'IPythonWidget' interface
429 #---------------------------------------------------------------------------
429 #---------------------------------------------------------------------------
430
430
431 def set_default_style(self, colors='lightbg'):
431 def set_default_style(self, colors='lightbg'):
432 """ Sets the widget style to the class defaults.
432 """ Sets the widget style to the class defaults.
433
433
434 Parameters:
434 Parameters:
435 -----------
435 -----------
436 colors : str, optional (default lightbg)
436 colors : str, optional (default lightbg)
437 Whether to use the default IPython light background or dark
437 Whether to use the default IPython light background or dark
438 background or B&W style.
438 background or B&W style.
439 """
439 """
440 colors = colors.lower()
440 colors = colors.lower()
441 if colors=='lightbg':
441 if colors=='lightbg':
442 self.style_sheet = styles.default_light_style_sheet
442 self.style_sheet = styles.default_light_style_sheet
443 self.syntax_style = styles.default_light_syntax_style
443 self.syntax_style = styles.default_light_syntax_style
444 elif colors=='linux':
444 elif colors=='linux':
445 self.style_sheet = styles.default_dark_style_sheet
445 self.style_sheet = styles.default_dark_style_sheet
446 self.syntax_style = styles.default_dark_syntax_style
446 self.syntax_style = styles.default_dark_syntax_style
447 elif colors=='nocolor':
447 elif colors=='nocolor':
448 self.style_sheet = styles.default_bw_style_sheet
448 self.style_sheet = styles.default_bw_style_sheet
449 self.syntax_style = styles.default_bw_syntax_style
449 self.syntax_style = styles.default_bw_syntax_style
450 else:
450 else:
451 raise KeyError("No such color scheme: %s"%colors)
451 raise KeyError("No such color scheme: %s"%colors)
452
452
453 #---------------------------------------------------------------------------
453 #---------------------------------------------------------------------------
454 # 'IPythonWidget' protected interface
454 # 'IPythonWidget' protected interface
455 #---------------------------------------------------------------------------
455 #---------------------------------------------------------------------------
456
456
457 def _edit(self, filename, line=None):
457 def _edit(self, filename, line=None):
458 """ Opens a Python script for editing.
458 """ Opens a Python script for editing.
459
459
460 Parameters:
460 Parameters:
461 -----------
461 -----------
462 filename : str
462 filename : str
463 A path to a local system file.
463 A path to a local system file.
464
464
465 line : int, optional
465 line : int, optional
466 A line of interest in the file.
466 A line of interest in the file.
467 """
467 """
468 if self.custom_edit:
468 if self.custom_edit:
469 self.custom_edit_requested.emit(filename, line)
469 self.custom_edit_requested.emit(filename, line)
470 elif not self.editor:
470 elif not self.editor:
471 self._append_plain_text('No default editor available.\n'
471 self._append_plain_text('No default editor available.\n'
472 'Specify a GUI text editor in the `IPythonWidget.editor` '
472 'Specify a GUI text editor in the `IPythonWidget.editor` '
473 'configurable to enable the %edit magic')
473 'configurable to enable the %edit magic')
474 else:
474 else:
475 try:
475 try:
476 filename = '"%s"' % filename
476 filename = '"%s"' % filename
477 if line and self.editor_line:
477 if line and self.editor_line:
478 command = self.editor_line.format(filename=filename,
478 command = self.editor_line.format(filename=filename,
479 line=line)
479 line=line)
480 else:
480 else:
481 try:
481 try:
482 command = self.editor.format()
482 command = self.editor.format()
483 except KeyError:
483 except KeyError:
484 command = self.editor.format(filename=filename)
484 command = self.editor.format(filename=filename)
485 else:
485 else:
486 command += ' ' + filename
486 command += ' ' + filename
487 except KeyError:
487 except KeyError:
488 self._append_plain_text('Invalid editor command.\n')
488 self._append_plain_text('Invalid editor command.\n')
489 else:
489 else:
490 try:
490 try:
491 Popen(command, shell=True)
491 Popen(command, shell=True)
492 except OSError:
492 except OSError:
493 msg = 'Opening editor with command "%s" failed.\n'
493 msg = 'Opening editor with command "%s" failed.\n'
494 self._append_plain_text(msg % command)
494 self._append_plain_text(msg % command)
495
495
496 def _make_in_prompt(self, number):
496 def _make_in_prompt(self, number):
497 """ Given a prompt number, returns an HTML In prompt.
497 """ Given a prompt number, returns an HTML In prompt.
498 """
498 """
499 try:
499 try:
500 body = self.in_prompt % number
500 body = self.in_prompt % number
501 except TypeError:
501 except TypeError:
502 # allow in_prompt to leave out number, e.g. '>>> '
502 # allow in_prompt to leave out number, e.g. '>>> '
503 body = self.in_prompt
503 body = self.in_prompt
504 return '<span class="in-prompt">%s</span>' % body
504 return '<span class="in-prompt">%s</span>' % body
505
505
506 def _make_continuation_prompt(self, prompt):
506 def _make_continuation_prompt(self, prompt):
507 """ Given a plain text version of an In prompt, returns an HTML
507 """ Given a plain text version of an In prompt, returns an HTML
508 continuation prompt.
508 continuation prompt.
509 """
509 """
510 end_chars = '...: '
510 end_chars = '...: '
511 space_count = len(prompt.lstrip('\n')) - len(end_chars)
511 space_count = len(prompt.lstrip('\n')) - len(end_chars)
512 body = '&nbsp;' * space_count + end_chars
512 body = '&nbsp;' * space_count + end_chars
513 return '<span class="in-prompt">%s</span>' % body
513 return '<span class="in-prompt">%s</span>' % body
514
514
515 def _make_out_prompt(self, number):
515 def _make_out_prompt(self, number):
516 """ Given a prompt number, returns an HTML Out prompt.
516 """ Given a prompt number, returns an HTML Out prompt.
517 """
517 """
518 body = self.out_prompt % number
518 body = self.out_prompt % number
519 return '<span class="out-prompt">%s</span>' % body
519 return '<span class="out-prompt">%s</span>' % body
520
520
521 #------ Payload handlers --------------------------------------------------
521 #------ Payload handlers --------------------------------------------------
522
522
523 # Payload handlers with a generic interface: each takes the opaque payload
523 # Payload handlers with a generic interface: each takes the opaque payload
524 # dict, unpacks it and calls the underlying functions with the necessary
524 # dict, unpacks it and calls the underlying functions with the necessary
525 # arguments.
525 # arguments.
526
526
527 def _handle_payload_edit(self, item):
527 def _handle_payload_edit(self, item):
528 self._edit(item['filename'], item['line_number'])
528 self._edit(item['filename'], item['line_number'])
529
529
530 def _handle_payload_exit(self, item):
530 def _handle_payload_exit(self, item):
531 self._keep_kernel_on_exit = item['keepkernel']
531 self._keep_kernel_on_exit = item['keepkernel']
532 self.exit_requested.emit(self)
532 self.exit_requested.emit(self)
533
533
534 def _handle_payload_next_input(self, item):
534 def _handle_payload_next_input(self, item):
535 self.input_buffer = dedent(item['text'].rstrip())
535 self.input_buffer = dedent(item['text'].rstrip())
536
536
537 def _handle_payload_page(self, item):
537 def _handle_payload_page(self, item):
538 # Since the plain text widget supports only a very small subset of HTML
538 # Since the plain text widget supports only a very small subset of HTML
539 # and we have no control over the HTML source, we only page HTML
539 # and we have no control over the HTML source, we only page HTML
540 # payloads in the rich text widget.
540 # payloads in the rich text widget.
541 if item['html'] and self.kind == 'rich':
541 if item['html'] and self.kind == 'rich':
542 self._page(item['html'], html=True)
542 self._page(item['html'], html=True)
543 else:
543 else:
544 self._page(item['text'], html=False)
544 self._page(item['text'], html=False)
545
545
546 #------ Trait change handlers --------------------------------------------
546 #------ Trait change handlers --------------------------------------------
547
547
548 def _style_sheet_changed(self):
548 def _style_sheet_changed(self):
549 """ Set the style sheets of the underlying widgets.
549 """ Set the style sheets of the underlying widgets.
550 """
550 """
551 self.setStyleSheet(self.style_sheet)
551 self.setStyleSheet(self.style_sheet)
552 if self._control is not None:
552 if self._control is not None:
553 self._control.document().setDefaultStyleSheet(self.style_sheet)
553 self._control.document().setDefaultStyleSheet(self.style_sheet)
554 bg_color = self._control.palette().window().color()
554 bg_color = self._control.palette().window().color()
555 self._ansi_processor.set_background_color(bg_color)
555 self._ansi_processor.set_background_color(bg_color)
556
556
557 if self._page_control is not None:
557 if self._page_control is not None:
558 self._page_control.document().setDefaultStyleSheet(self.style_sheet)
558 self._page_control.document().setDefaultStyleSheet(self.style_sheet)
559
559
560
560
561
561
562 def _syntax_style_changed(self):
562 def _syntax_style_changed(self):
563 """ Set the style for the syntax highlighter.
563 """ Set the style for the syntax highlighter.
564 """
564 """
565 if self._highlighter is None:
565 if self._highlighter is None:
566 # ignore premature calls
566 # ignore premature calls
567 return
567 return
568 if self.syntax_style:
568 if self.syntax_style:
569 self._highlighter.set_style(self.syntax_style)
569 self._highlighter.set_style(self.syntax_style)
570 else:
570 else:
571 self._highlighter.set_style_sheet(self.style_sheet)
571 self._highlighter.set_style_sheet(self.style_sheet)
572
572
573 #------ Trait default initializers -----------------------------------------
573 #------ Trait default initializers -----------------------------------------
574
574
575 def _banner_default(self):
575 def _banner_default(self):
576 from IPython.core.usage import default_gui_banner
576 from IPython.core.usage import default_gui_banner
577 return default_gui_banner
577 return default_gui_banner
@@ -1,325 +1,325 b''
1 #-----------------------------------------------------------------------------
1 #-----------------------------------------------------------------------------
2 # Copyright (c) 2010, IPython Development Team.
2 # Copyright (c) 2010, IPython Development Team.
3 #
3 #
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5 #
5 #
6 # The full license is in the file COPYING.txt, distributed with this software.
6 # The full license is in the file COPYING.txt, distributed with this software.
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8
8
9 # Standard libary imports.
9 # Standard libary imports.
10 from base64 import decodestring
10 from base64 import decodestring
11 import os
11 import os
12 import re
12 import re
13
13
14 # System libary imports.
14 # System libary imports.
15 from IPython.external.qt import QtCore, QtGui
15 from IPython.external.qt import QtCore, QtGui
16
16
17 # Local imports
17 # Local imports
18 from IPython.utils.traitlets import Bool
18 from IPython.utils.traitlets import Bool
19 from IPython.frontend.qt.svg import save_svg, svg_to_clipboard, svg_to_image
19 from IPython.frontend.qt.svg import save_svg, svg_to_clipboard, svg_to_image
20 from ipython_widget import IPythonWidget
20 from ipython_widget import IPythonWidget
21
21
22
22
23 class RichIPythonWidget(IPythonWidget):
23 class RichIPythonWidget(IPythonWidget):
24 """ An IPythonWidget that supports rich text, including lists, images, and
24 """ An IPythonWidget that supports rich text, including lists, images, and
25 tables. Note that raw performance will be reduced compared to the plain
25 tables. Note that raw performance will be reduced compared to the plain
26 text version.
26 text version.
27 """
27 """
28
28
29 # RichIPythonWidget protected class variables.
29 # RichIPythonWidget protected class variables.
30 _payload_source_plot = 'IPython.zmq.pylab.backend_payload.add_plot_payload'
30 _payload_source_plot = 'IPython.zmq.pylab.backend_payload.add_plot_payload'
31 _jpg_supported = Bool(False)
31 _jpg_supported = Bool(False)
32
32
33 # Used to determine whether a given html export attempt has already
33 # Used to determine whether a given html export attempt has already
34 # displayed a warning about being unable to convert a png to svg.
34 # displayed a warning about being unable to convert a png to svg.
35 _svg_warning_displayed = False
35 _svg_warning_displayed = False
36
36
37 #---------------------------------------------------------------------------
37 #---------------------------------------------------------------------------
38 # 'object' interface
38 # 'object' interface
39 #---------------------------------------------------------------------------
39 #---------------------------------------------------------------------------
40
40
41 def __init__(self, *args, **kw):
41 def __init__(self, *args, **kw):
42 """ Create a RichIPythonWidget.
42 """ Create a RichIPythonWidget.
43 """
43 """
44 kw['kind'] = 'rich'
44 kw['kind'] = 'rich'
45 super(RichIPythonWidget, self).__init__(*args, **kw)
45 super(RichIPythonWidget, self).__init__(*args, **kw)
46
46
47 # Configure the ConsoleWidget HTML exporter for our formats.
47 # Configure the ConsoleWidget HTML exporter for our formats.
48 self._html_exporter.image_tag = self._get_image_tag
48 self._html_exporter.image_tag = self._get_image_tag
49
49
50 # Dictionary for resolving document resource names to SVG data.
50 # Dictionary for resolving document resource names to SVG data.
51 self._name_to_svg_map = {}
51 self._name_to_svg_map = {}
52
52
53 # Do we support jpg ?
53 # Do we support jpg ?
54 # it seems that sometime jpg support is a plugin of QT, so try to assume
54 # it seems that sometime jpg support is a plugin of QT, so try to assume
55 # it is not always supported.
55 # it is not always supported.
56 _supported_format = map(str, QtGui.QImageReader.supportedImageFormats())
56 _supported_format = map(str, QtGui.QImageReader.supportedImageFormats())
57 self._jpg_supported = 'jpeg' in _supported_format
57 self._jpg_supported = 'jpeg' in _supported_format
58
58
59
59
60 #---------------------------------------------------------------------------
60 #---------------------------------------------------------------------------
61 # 'ConsoleWidget' public interface overides
61 # 'ConsoleWidget' public interface overides
62 #---------------------------------------------------------------------------
62 #---------------------------------------------------------------------------
63
63
64 def export_html(self):
64 def export_html(self):
65 """ Shows a dialog to export HTML/XML in various formats.
65 """ Shows a dialog to export HTML/XML in various formats.
66
66
67 Overridden in order to reset the _svg_warning_displayed flag prior
67 Overridden in order to reset the _svg_warning_displayed flag prior
68 to the export running.
68 to the export running.
69 """
69 """
70 self._svg_warning_displayed = False
70 self._svg_warning_displayed = False
71 super(RichIPythonWidget, self).export_html()
71 super(RichIPythonWidget, self).export_html()
72
72
73
73
74 #---------------------------------------------------------------------------
74 #---------------------------------------------------------------------------
75 # 'ConsoleWidget' protected interface
75 # 'ConsoleWidget' protected interface
76 #---------------------------------------------------------------------------
76 #---------------------------------------------------------------------------
77
77
78 def _context_menu_make(self, pos):
78 def _context_menu_make(self, pos):
79 """ Reimplemented to return a custom context menu for images.
79 """ Reimplemented to return a custom context menu for images.
80 """
80 """
81 format = self._control.cursorForPosition(pos).charFormat()
81 format = self._control.cursorForPosition(pos).charFormat()
82 name = format.stringProperty(QtGui.QTextFormat.ImageName)
82 name = format.stringProperty(QtGui.QTextFormat.ImageName)
83 if name:
83 if name:
84 menu = QtGui.QMenu()
84 menu = QtGui.QMenu()
85
85
86 menu.addAction('Copy Image', lambda: self._copy_image(name))
86 menu.addAction('Copy Image', lambda: self._copy_image(name))
87 menu.addAction('Save Image As...', lambda: self._save_image(name))
87 menu.addAction('Save Image As...', lambda: self._save_image(name))
88 menu.addSeparator()
88 menu.addSeparator()
89
89
90 svg = self._name_to_svg_map.get(name, None)
90 svg = self._name_to_svg_map.get(name, None)
91 if svg is not None:
91 if svg is not None:
92 menu.addSeparator()
92 menu.addSeparator()
93 menu.addAction('Copy SVG', lambda: svg_to_clipboard(svg))
93 menu.addAction('Copy SVG', lambda: svg_to_clipboard(svg))
94 menu.addAction('Save SVG As...',
94 menu.addAction('Save SVG As...',
95 lambda: save_svg(svg, self._control))
95 lambda: save_svg(svg, self._control))
96 else:
96 else:
97 menu = super(RichIPythonWidget, self)._context_menu_make(pos)
97 menu = super(RichIPythonWidget, self)._context_menu_make(pos)
98 return menu
98 return menu
99
99
100 #---------------------------------------------------------------------------
100 #---------------------------------------------------------------------------
101 # 'BaseFrontendMixin' abstract interface
101 # 'BaseFrontendMixin' abstract interface
102 #---------------------------------------------------------------------------
102 #---------------------------------------------------------------------------
103 def _pre_image_append(self, msg, prompt_number):
103 def _pre_image_append(self, msg, prompt_number):
104 """ Append the Out[] prompt and make the output nicer
104 """ Append the Out[] prompt and make the output nicer
105
105
106 Shared code for some the following if statement
106 Shared code for some the following if statement
107 """
107 """
108 self.log.debug("pyout: %s", msg.get('content', ''))
108 self.log.debug("pyout: %s", msg.get('content', ''))
109 self._append_plain_text(self.output_sep, True)
109 self._append_plain_text(self.output_sep, True)
110 self._append_html(self._make_out_prompt(prompt_number), True)
110 self._append_html(self._make_out_prompt(prompt_number), True)
111 self._append_plain_text('\n', True)
111 self._append_plain_text('\n', True)
112
112
113 def _handle_pyout(self, msg):
113 def _handle_pyout(self, msg):
114 """ Overridden to handle rich data types, like SVG.
114 """ Overridden to handle rich data types, like SVG.
115 """
115 """
116 if not self._hidden and self._is_from_this_session(msg):
116 if not self._hidden and self._is_from_this_session(msg):
117 content = msg['content']
117 content = msg['content']
118 prompt_number = content.get('execution_count', 0)
118 prompt_number = content.get('execution_count', 0)
119 data = content['data']
119 data = content['data']
120 if data.has_key('image/svg+xml'):
120 if 'image/svg+xml' in data:
121 self._pre_image_append(msg, prompt_number)
121 self._pre_image_append(msg, prompt_number)
122 self._append_svg(data['image/svg+xml'], True)
122 self._append_svg(data['image/svg+xml'], True)
123 self._append_html(self.output_sep2, True)
123 self._append_html(self.output_sep2, True)
124 elif data.has_key('image/png'):
124 elif 'image/png' in data:
125 self._pre_image_append(msg, prompt_number)
125 self._pre_image_append(msg, prompt_number)
126 self._append_png(decodestring(data['image/png'].encode('ascii')), True)
126 self._append_png(decodestring(data['image/png'].encode('ascii')), True)
127 self._append_html(self.output_sep2, True)
127 self._append_html(self.output_sep2, True)
128 elif data.has_key('image/jpeg') and self._jpg_supported:
128 elif 'image/jpeg' in data and self._jpg_supported:
129 self._pre_image_append(msg, prompt_number)
129 self._pre_image_append(msg, prompt_number)
130 self._append_jpg(decodestring(data['image/jpeg'].encode('ascii')), True)
130 self._append_jpg(decodestring(data['image/jpeg'].encode('ascii')), True)
131 self._append_html(self.output_sep2, True)
131 self._append_html(self.output_sep2, True)
132 else:
132 else:
133 # Default back to the plain text representation.
133 # Default back to the plain text representation.
134 return super(RichIPythonWidget, self)._handle_pyout(msg)
134 return super(RichIPythonWidget, self)._handle_pyout(msg)
135
135
136 def _handle_display_data(self, msg):
136 def _handle_display_data(self, msg):
137 """ Overridden to handle rich data types, like SVG.
137 """ Overridden to handle rich data types, like SVG.
138 """
138 """
139 if not self._hidden and self._is_from_this_session(msg):
139 if not self._hidden and self._is_from_this_session(msg):
140 source = msg['content']['source']
140 source = msg['content']['source']
141 data = msg['content']['data']
141 data = msg['content']['data']
142 metadata = msg['content']['metadata']
142 metadata = msg['content']['metadata']
143 # Try to use the svg or html representations.
143 # Try to use the svg or html representations.
144 # FIXME: Is this the right ordering of things to try?
144 # FIXME: Is this the right ordering of things to try?
145 if data.has_key('image/svg+xml'):
145 if 'image/svg+xml' in data:
146 self.log.debug("display: %s", msg.get('content', ''))
146 self.log.debug("display: %s", msg.get('content', ''))
147 svg = data['image/svg+xml']
147 svg = data['image/svg+xml']
148 self._append_svg(svg, True)
148 self._append_svg(svg, True)
149 elif data.has_key('image/png'):
149 elif 'image/png' in data:
150 self.log.debug("display: %s", msg.get('content', ''))
150 self.log.debug("display: %s", msg.get('content', ''))
151 # PNG data is base64 encoded as it passes over the network
151 # PNG data is base64 encoded as it passes over the network
152 # in a JSON structure so we decode it.
152 # in a JSON structure so we decode it.
153 png = decodestring(data['image/png'].encode('ascii'))
153 png = decodestring(data['image/png'].encode('ascii'))
154 self._append_png(png, True)
154 self._append_png(png, True)
155 elif data.has_key('image/jpeg') and self._jpg_supported:
155 elif 'image/jpeg' in data and self._jpg_supported:
156 self.log.debug("display: %s", msg.get('content', ''))
156 self.log.debug("display: %s", msg.get('content', ''))
157 jpg = decodestring(data['image/jpeg'].encode('ascii'))
157 jpg = decodestring(data['image/jpeg'].encode('ascii'))
158 self._append_jpg(jpg, True)
158 self._append_jpg(jpg, True)
159 else:
159 else:
160 # Default back to the plain text representation.
160 # Default back to the plain text representation.
161 return super(RichIPythonWidget, self)._handle_display_data(msg)
161 return super(RichIPythonWidget, self)._handle_display_data(msg)
162
162
163 #---------------------------------------------------------------------------
163 #---------------------------------------------------------------------------
164 # 'RichIPythonWidget' protected interface
164 # 'RichIPythonWidget' protected interface
165 #---------------------------------------------------------------------------
165 #---------------------------------------------------------------------------
166
166
167 def _append_jpg(self, jpg, before_prompt=False):
167 def _append_jpg(self, jpg, before_prompt=False):
168 """ Append raw JPG data to the widget."""
168 """ Append raw JPG data to the widget."""
169 self._append_custom(self._insert_jpg, jpg, before_prompt)
169 self._append_custom(self._insert_jpg, jpg, before_prompt)
170
170
171 def _append_png(self, png, before_prompt=False):
171 def _append_png(self, png, before_prompt=False):
172 """ Append raw PNG data to the widget.
172 """ Append raw PNG data to the widget.
173 """
173 """
174 self._append_custom(self._insert_png, png, before_prompt)
174 self._append_custom(self._insert_png, png, before_prompt)
175
175
176 def _append_svg(self, svg, before_prompt=False):
176 def _append_svg(self, svg, before_prompt=False):
177 """ Append raw SVG data to the widget.
177 """ Append raw SVG data to the widget.
178 """
178 """
179 self._append_custom(self._insert_svg, svg, before_prompt)
179 self._append_custom(self._insert_svg, svg, before_prompt)
180
180
181 def _add_image(self, image):
181 def _add_image(self, image):
182 """ Adds the specified QImage to the document and returns a
182 """ Adds the specified QImage to the document and returns a
183 QTextImageFormat that references it.
183 QTextImageFormat that references it.
184 """
184 """
185 document = self._control.document()
185 document = self._control.document()
186 name = str(image.cacheKey())
186 name = str(image.cacheKey())
187 document.addResource(QtGui.QTextDocument.ImageResource,
187 document.addResource(QtGui.QTextDocument.ImageResource,
188 QtCore.QUrl(name), image)
188 QtCore.QUrl(name), image)
189 format = QtGui.QTextImageFormat()
189 format = QtGui.QTextImageFormat()
190 format.setName(name)
190 format.setName(name)
191 return format
191 return format
192
192
193 def _copy_image(self, name):
193 def _copy_image(self, name):
194 """ Copies the ImageResource with 'name' to the clipboard.
194 """ Copies the ImageResource with 'name' to the clipboard.
195 """
195 """
196 image = self._get_image(name)
196 image = self._get_image(name)
197 QtGui.QApplication.clipboard().setImage(image)
197 QtGui.QApplication.clipboard().setImage(image)
198
198
199 def _get_image(self, name):
199 def _get_image(self, name):
200 """ Returns the QImage stored as the ImageResource with 'name'.
200 """ Returns the QImage stored as the ImageResource with 'name'.
201 """
201 """
202 document = self._control.document()
202 document = self._control.document()
203 image = document.resource(QtGui.QTextDocument.ImageResource,
203 image = document.resource(QtGui.QTextDocument.ImageResource,
204 QtCore.QUrl(name))
204 QtCore.QUrl(name))
205 return image
205 return image
206
206
207 def _get_image_tag(self, match, path = None, format = "png"):
207 def _get_image_tag(self, match, path = None, format = "png"):
208 """ Return (X)HTML mark-up for the image-tag given by match.
208 """ Return (X)HTML mark-up for the image-tag given by match.
209
209
210 Parameters
210 Parameters
211 ----------
211 ----------
212 match : re.SRE_Match
212 match : re.SRE_Match
213 A match to an HTML image tag as exported by Qt, with
213 A match to an HTML image tag as exported by Qt, with
214 match.group("Name") containing the matched image ID.
214 match.group("Name") containing the matched image ID.
215
215
216 path : string|None, optional [default None]
216 path : string|None, optional [default None]
217 If not None, specifies a path to which supporting files may be
217 If not None, specifies a path to which supporting files may be
218 written (e.g., for linked images). If None, all images are to be
218 written (e.g., for linked images). If None, all images are to be
219 included inline.
219 included inline.
220
220
221 format : "png"|"svg"|"jpg", optional [default "png"]
221 format : "png"|"svg"|"jpg", optional [default "png"]
222 Format for returned or referenced images.
222 Format for returned or referenced images.
223 """
223 """
224 if format in ("png","jpg"):
224 if format in ("png","jpg"):
225 try:
225 try:
226 image = self._get_image(match.group("name"))
226 image = self._get_image(match.group("name"))
227 except KeyError:
227 except KeyError:
228 return "<b>Couldn't find image %s</b>" % match.group("name")
228 return "<b>Couldn't find image %s</b>" % match.group("name")
229
229
230 if path is not None:
230 if path is not None:
231 if not os.path.exists(path):
231 if not os.path.exists(path):
232 os.mkdir(path)
232 os.mkdir(path)
233 relpath = os.path.basename(path)
233 relpath = os.path.basename(path)
234 if image.save("%s/qt_img%s.%s" % (path, match.group("name"), format),
234 if image.save("%s/qt_img%s.%s" % (path, match.group("name"), format),
235 "PNG"):
235 "PNG"):
236 return '<img src="%s/qt_img%s.%s">' % (relpath,
236 return '<img src="%s/qt_img%s.%s">' % (relpath,
237 match.group("name"),format)
237 match.group("name"),format)
238 else:
238 else:
239 return "<b>Couldn't save image!</b>"
239 return "<b>Couldn't save image!</b>"
240 else:
240 else:
241 ba = QtCore.QByteArray()
241 ba = QtCore.QByteArray()
242 buffer_ = QtCore.QBuffer(ba)
242 buffer_ = QtCore.QBuffer(ba)
243 buffer_.open(QtCore.QIODevice.WriteOnly)
243 buffer_.open(QtCore.QIODevice.WriteOnly)
244 image.save(buffer_, format.upper())
244 image.save(buffer_, format.upper())
245 buffer_.close()
245 buffer_.close()
246 return '<img src="data:image/%s;base64,\n%s\n" />' % (
246 return '<img src="data:image/%s;base64,\n%s\n" />' % (
247 format,re.sub(r'(.{60})',r'\1\n',str(ba.toBase64())))
247 format,re.sub(r'(.{60})',r'\1\n',str(ba.toBase64())))
248
248
249 elif format == "svg":
249 elif format == "svg":
250 try:
250 try:
251 svg = str(self._name_to_svg_map[match.group("name")])
251 svg = str(self._name_to_svg_map[match.group("name")])
252 except KeyError:
252 except KeyError:
253 if not self._svg_warning_displayed:
253 if not self._svg_warning_displayed:
254 QtGui.QMessageBox.warning(self, 'Error converting PNG to SVG.',
254 QtGui.QMessageBox.warning(self, 'Error converting PNG to SVG.',
255 'Cannot convert a PNG to SVG. To fix this, add this '
255 'Cannot convert a PNG to SVG. To fix this, add this '
256 'to your ipython config:\n\n'
256 'to your ipython config:\n\n'
257 '\tc.InlineBackendConfig.figure_format = \'svg\'\n\n'
257 '\tc.InlineBackendConfig.figure_format = \'svg\'\n\n'
258 'And regenerate the figures.',
258 'And regenerate the figures.',
259 QtGui.QMessageBox.Ok)
259 QtGui.QMessageBox.Ok)
260 self._svg_warning_displayed = True
260 self._svg_warning_displayed = True
261 return ("<b>Cannot convert a PNG to SVG.</b> "
261 return ("<b>Cannot convert a PNG to SVG.</b> "
262 "To fix this, add this to your config: "
262 "To fix this, add this to your config: "
263 "<span>c.InlineBackendConfig.figure_format = 'svg'</span> "
263 "<span>c.InlineBackendConfig.figure_format = 'svg'</span> "
264 "and regenerate the figures.")
264 "and regenerate the figures.")
265
265
266 # Not currently checking path, because it's tricky to find a
266 # Not currently checking path, because it's tricky to find a
267 # cross-browser way to embed external SVG images (e.g., via
267 # cross-browser way to embed external SVG images (e.g., via
268 # object or embed tags).
268 # object or embed tags).
269
269
270 # Chop stand-alone header from matplotlib SVG
270 # Chop stand-alone header from matplotlib SVG
271 offset = svg.find("<svg")
271 offset = svg.find("<svg")
272 assert(offset > -1)
272 assert(offset > -1)
273
273
274 return svg[offset:]
274 return svg[offset:]
275
275
276 else:
276 else:
277 return '<b>Unrecognized image format</b>'
277 return '<b>Unrecognized image format</b>'
278
278
279 def _insert_jpg(self, cursor, jpg):
279 def _insert_jpg(self, cursor, jpg):
280 """ Insert raw PNG data into the widget."""
280 """ Insert raw PNG data into the widget."""
281 self._insert_img(cursor, jpg, 'jpg')
281 self._insert_img(cursor, jpg, 'jpg')
282
282
283 def _insert_png(self, cursor, png):
283 def _insert_png(self, cursor, png):
284 """ Insert raw PNG data into the widget.
284 """ Insert raw PNG data into the widget.
285 """
285 """
286 self._insert_img(cursor, png, 'png')
286 self._insert_img(cursor, png, 'png')
287
287
288 def _insert_img(self, cursor, img, fmt):
288 def _insert_img(self, cursor, img, fmt):
289 """ insert a raw image, jpg or png """
289 """ insert a raw image, jpg or png """
290 try:
290 try:
291 image = QtGui.QImage()
291 image = QtGui.QImage()
292 image.loadFromData(img, fmt.upper())
292 image.loadFromData(img, fmt.upper())
293 except ValueError:
293 except ValueError:
294 self._insert_plain_text(cursor, 'Received invalid %s data.'%fmt)
294 self._insert_plain_text(cursor, 'Received invalid %s data.'%fmt)
295 else:
295 else:
296 format = self._add_image(image)
296 format = self._add_image(image)
297 cursor.insertBlock()
297 cursor.insertBlock()
298 cursor.insertImage(format)
298 cursor.insertImage(format)
299 cursor.insertBlock()
299 cursor.insertBlock()
300
300
301 def _insert_svg(self, cursor, svg):
301 def _insert_svg(self, cursor, svg):
302 """ Insert raw SVG data into the widet.
302 """ Insert raw SVG data into the widet.
303 """
303 """
304 try:
304 try:
305 image = svg_to_image(svg)
305 image = svg_to_image(svg)
306 except ValueError:
306 except ValueError:
307 self._insert_plain_text(cursor, 'Received invalid SVG data.')
307 self._insert_plain_text(cursor, 'Received invalid SVG data.')
308 else:
308 else:
309 format = self._add_image(image)
309 format = self._add_image(image)
310 self._name_to_svg_map[format.name()] = svg
310 self._name_to_svg_map[format.name()] = svg
311 cursor.insertBlock()
311 cursor.insertBlock()
312 cursor.insertImage(format)
312 cursor.insertImage(format)
313 cursor.insertBlock()
313 cursor.insertBlock()
314
314
315 def _save_image(self, name, format='PNG'):
315 def _save_image(self, name, format='PNG'):
316 """ Shows a save dialog for the ImageResource with 'name'.
316 """ Shows a save dialog for the ImageResource with 'name'.
317 """
317 """
318 dialog = QtGui.QFileDialog(self._control, 'Save Image')
318 dialog = QtGui.QFileDialog(self._control, 'Save Image')
319 dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
319 dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
320 dialog.setDefaultSuffix(format.lower())
320 dialog.setDefaultSuffix(format.lower())
321 dialog.setNameFilter('%s file (*.%s)' % (format, format.lower()))
321 dialog.setNameFilter('%s file (*.%s)' % (format, format.lower()))
322 if dialog.exec_():
322 if dialog.exec_():
323 filename = dialog.selectedFiles()[0]
323 filename = dialog.selectedFiles()[0]
324 image = self._get_image(name)
324 image = self._get_image(name)
325 image.save(filename, format)
325 image.save(filename, format)
@@ -1,146 +1,146 b''
1 # coding: utf-8
1 # coding: utf-8
2 """
2 """
3 Support for creating GUI apps and starting event loops.
3 Support for creating GUI apps and starting event loops.
4
4
5 IPython's GUI integration allows interative plotting and GUI usage in IPython
5 IPython's GUI integration allows interative plotting and GUI usage in IPython
6 session. IPython has two different types of GUI integration:
6 session. IPython has two different types of GUI integration:
7
7
8 1. The terminal based IPython supports GUI event loops through Python's
8 1. The terminal based IPython supports GUI event loops through Python's
9 PyOS_InputHook. PyOS_InputHook is a hook that Python calls periodically
9 PyOS_InputHook. PyOS_InputHook is a hook that Python calls periodically
10 whenever raw_input is waiting for a user to type code. We implement GUI
10 whenever raw_input is waiting for a user to type code. We implement GUI
11 support in the terminal by setting PyOS_InputHook to a function that
11 support in the terminal by setting PyOS_InputHook to a function that
12 iterates the event loop for a short while. It is important to note that
12 iterates the event loop for a short while. It is important to note that
13 in this situation, the real GUI event loop is NOT run in the normal
13 in this situation, the real GUI event loop is NOT run in the normal
14 manner, so you can't use the normal means to detect that it is running.
14 manner, so you can't use the normal means to detect that it is running.
15 2. In the two process IPython kernel/frontend, the GUI event loop is run in
15 2. In the two process IPython kernel/frontend, the GUI event loop is run in
16 the kernel. In this case, the event loop is run in the normal manner by
16 the kernel. In this case, the event loop is run in the normal manner by
17 calling the function or method of the GUI toolkit that starts the event
17 calling the function or method of the GUI toolkit that starts the event
18 loop.
18 loop.
19
19
20 In addition to starting the GUI event loops in one of these two ways, IPython
20 In addition to starting the GUI event loops in one of these two ways, IPython
21 will *always* create an appropriate GUI application object when GUi
21 will *always* create an appropriate GUI application object when GUi
22 integration is enabled.
22 integration is enabled.
23
23
24 If you want your GUI apps to run in IPython you need to do two things:
24 If you want your GUI apps to run in IPython you need to do two things:
25
25
26 1. Test to see if there is already an existing main application object. If
26 1. Test to see if there is already an existing main application object. If
27 there is, you should use it. If there is not an existing application object
27 there is, you should use it. If there is not an existing application object
28 you should create one.
28 you should create one.
29 2. Test to see if the GUI event loop is running. If it is, you should not
29 2. Test to see if the GUI event loop is running. If it is, you should not
30 start it. If the event loop is not running you may start it.
30 start it. If the event loop is not running you may start it.
31
31
32 This module contains functions for each toolkit that perform these things
32 This module contains functions for each toolkit that perform these things
33 in a consistent manner. Because of how PyOS_InputHook runs the event loop
33 in a consistent manner. Because of how PyOS_InputHook runs the event loop
34 you cannot detect if the event loop is running using the traditional calls
34 you cannot detect if the event loop is running using the traditional calls
35 (such as ``wx.GetApp.IsMainLoopRunning()`` in wxPython). If PyOS_InputHook is
35 (such as ``wx.GetApp.IsMainLoopRunning()`` in wxPython). If PyOS_InputHook is
36 set These methods will return a false negative. That is, they will say the
36 set These methods will return a false negative. That is, they will say the
37 event loop is not running, when is actually is. To work around this limitation
37 event loop is not running, when is actually is. To work around this limitation
38 we proposed the following informal protocol:
38 we proposed the following informal protocol:
39
39
40 * Whenever someone starts the event loop, they *must* set the ``_in_event_loop``
40 * Whenever someone starts the event loop, they *must* set the ``_in_event_loop``
41 attribute of the main application object to ``True``. This should be done
41 attribute of the main application object to ``True``. This should be done
42 regardless of how the event loop is actually run.
42 regardless of how the event loop is actually run.
43 * Whenever someone stops the event loop, they *must* set the ``_in_event_loop``
43 * Whenever someone stops the event loop, they *must* set the ``_in_event_loop``
44 attribute of the main application object to ``False``.
44 attribute of the main application object to ``False``.
45 * If you want to see if the event loop is running, you *must* use ``hasattr``
45 * If you want to see if the event loop is running, you *must* use ``hasattr``
46 to see if ``_in_event_loop`` attribute has been set. If it is set, you
46 to see if ``_in_event_loop`` attribute has been set. If it is set, you
47 *must* use its value. If it has not been set, you can query the toolkit
47 *must* use its value. If it has not been set, you can query the toolkit
48 in the normal manner.
48 in the normal manner.
49 * If you want GUI support and no one else has created an application or
49 * If you want GUI support and no one else has created an application or
50 started the event loop you *must* do this. We don't want projects to
50 started the event loop you *must* do this. We don't want projects to
51 attempt to defer these things to someone else if they themselves need it.
51 attempt to defer these things to someone else if they themselves need it.
52
52
53 The functions below implement this logic for each GUI toolkit. If you need
53 The functions below implement this logic for each GUI toolkit. If you need
54 to create custom application subclasses, you will likely have to modify this
54 to create custom application subclasses, you will likely have to modify this
55 code for your own purposes. This code can be copied into your own project
55 code for your own purposes. This code can be copied into your own project
56 so you don't have to depend on IPython.
56 so you don't have to depend on IPython.
57
57
58 """
58 """
59
59
60 #-----------------------------------------------------------------------------
60 #-----------------------------------------------------------------------------
61 # Copyright (C) 2008-2011 The IPython Development Team
61 # Copyright (C) 2008-2011 The IPython Development Team
62 #
62 #
63 # Distributed under the terms of the BSD License. The full license is in
63 # Distributed under the terms of the BSD License. The full license is in
64 # the file COPYING, distributed as part of this software.
64 # the file COPYING, distributed as part of this software.
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66
66
67 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
68 # Imports
68 # Imports
69 #-----------------------------------------------------------------------------
69 #-----------------------------------------------------------------------------
70
70
71 #-----------------------------------------------------------------------------
71 #-----------------------------------------------------------------------------
72 # wx
72 # wx
73 #-----------------------------------------------------------------------------
73 #-----------------------------------------------------------------------------
74
74
75 def get_app_wx(*args, **kwargs):
75 def get_app_wx(*args, **kwargs):
76 """Create a new wx app or return an exiting one."""
76 """Create a new wx app or return an exiting one."""
77 import wx
77 import wx
78 app = wx.GetApp()
78 app = wx.GetApp()
79 if app is None:
79 if app is None:
80 if not kwargs.has_key('redirect'):
80 if 'redirect' not in kwargs:
81 kwargs['redirect'] = False
81 kwargs['redirect'] = False
82 app = wx.PySimpleApp(*args, **kwargs)
82 app = wx.PySimpleApp(*args, **kwargs)
83 return app
83 return app
84
84
85 def is_event_loop_running_wx(app=None):
85 def is_event_loop_running_wx(app=None):
86 """Is the wx event loop running."""
86 """Is the wx event loop running."""
87 if app is None:
87 if app is None:
88 app = get_app_wx()
88 app = get_app_wx()
89 if hasattr(app, '_in_event_loop'):
89 if hasattr(app, '_in_event_loop'):
90 return app._in_event_loop
90 return app._in_event_loop
91 else:
91 else:
92 return app.IsMainLoopRunning()
92 return app.IsMainLoopRunning()
93
93
94 def start_event_loop_wx(app=None):
94 def start_event_loop_wx(app=None):
95 """Start the wx event loop in a consistent manner."""
95 """Start the wx event loop in a consistent manner."""
96 if app is None:
96 if app is None:
97 app = get_app_wx()
97 app = get_app_wx()
98 if not is_event_loop_running_wx(app):
98 if not is_event_loop_running_wx(app):
99 app._in_event_loop = True
99 app._in_event_loop = True
100 app.MainLoop()
100 app.MainLoop()
101 app._in_event_loop = False
101 app._in_event_loop = False
102 else:
102 else:
103 app._in_event_loop = True
103 app._in_event_loop = True
104
104
105 #-----------------------------------------------------------------------------
105 #-----------------------------------------------------------------------------
106 # qt4
106 # qt4
107 #-----------------------------------------------------------------------------
107 #-----------------------------------------------------------------------------
108
108
109 def get_app_qt4(*args, **kwargs):
109 def get_app_qt4(*args, **kwargs):
110 """Create a new qt4 app or return an existing one."""
110 """Create a new qt4 app or return an existing one."""
111 from IPython.external.qt_for_kernel import QtGui
111 from IPython.external.qt_for_kernel import QtGui
112 app = QtGui.QApplication.instance()
112 app = QtGui.QApplication.instance()
113 if app is None:
113 if app is None:
114 if not args:
114 if not args:
115 args = ([''],)
115 args = ([''],)
116 app = QtGui.QApplication(*args, **kwargs)
116 app = QtGui.QApplication(*args, **kwargs)
117 return app
117 return app
118
118
119 def is_event_loop_running_qt4(app=None):
119 def is_event_loop_running_qt4(app=None):
120 """Is the qt4 event loop running."""
120 """Is the qt4 event loop running."""
121 if app is None:
121 if app is None:
122 app = get_app_qt4([''])
122 app = get_app_qt4([''])
123 if hasattr(app, '_in_event_loop'):
123 if hasattr(app, '_in_event_loop'):
124 return app._in_event_loop
124 return app._in_event_loop
125 else:
125 else:
126 # Does qt4 provide a other way to detect this?
126 # Does qt4 provide a other way to detect this?
127 return False
127 return False
128
128
129 def start_event_loop_qt4(app=None):
129 def start_event_loop_qt4(app=None):
130 """Start the qt4 event loop in a consistent manner."""
130 """Start the qt4 event loop in a consistent manner."""
131 if app is None:
131 if app is None:
132 app = get_app_qt4([''])
132 app = get_app_qt4([''])
133 if not is_event_loop_running_qt4(app):
133 if not is_event_loop_running_qt4(app):
134 app._in_event_loop = True
134 app._in_event_loop = True
135 app.exec_()
135 app.exec_()
136 app._in_event_loop = False
136 app._in_event_loop = False
137 else:
137 else:
138 app._in_event_loop = True
138 app._in_event_loop = True
139
139
140 #-----------------------------------------------------------------------------
140 #-----------------------------------------------------------------------------
141 # Tk
141 # Tk
142 #-----------------------------------------------------------------------------
142 #-----------------------------------------------------------------------------
143
143
144 #-----------------------------------------------------------------------------
144 #-----------------------------------------------------------------------------
145 # gtk
145 # gtk
146 #-----------------------------------------------------------------------------
146 #-----------------------------------------------------------------------------
@@ -1,529 +1,529 b''
1 # coding: utf-8
1 # coding: utf-8
2 """
2 """
3 Inputhook management for GUI event loop integration.
3 Inputhook management for GUI event loop integration.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 try:
17 try:
18 import ctypes
18 import ctypes
19 except ImportError:
19 except ImportError:
20 ctypes = None
20 ctypes = None
21 import os
21 import os
22 import sys
22 import sys
23 from distutils.version import LooseVersion as V
23 from distutils.version import LooseVersion as V
24
24
25 from IPython.utils.warn import warn
25 from IPython.utils.warn import warn
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Constants
28 # Constants
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 # Constants for identifying the GUI toolkits.
31 # Constants for identifying the GUI toolkits.
32 GUI_WX = 'wx'
32 GUI_WX = 'wx'
33 GUI_QT = 'qt'
33 GUI_QT = 'qt'
34 GUI_QT4 = 'qt4'
34 GUI_QT4 = 'qt4'
35 GUI_GTK = 'gtk'
35 GUI_GTK = 'gtk'
36 GUI_TK = 'tk'
36 GUI_TK = 'tk'
37 GUI_OSX = 'osx'
37 GUI_OSX = 'osx'
38 GUI_GLUT = 'glut'
38 GUI_GLUT = 'glut'
39 GUI_PYGLET = 'pyglet'
39 GUI_PYGLET = 'pyglet'
40 GUI_GTK3 = 'gtk3'
40 GUI_GTK3 = 'gtk3'
41 GUI_NONE = 'none' # i.e. disable
41 GUI_NONE = 'none' # i.e. disable
42
42
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44 # Utilities
44 # Utilities
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 def _stdin_ready_posix():
47 def _stdin_ready_posix():
48 """Return True if there's something to read on stdin (posix version)."""
48 """Return True if there's something to read on stdin (posix version)."""
49 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
49 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
50 return bool(infds)
50 return bool(infds)
51
51
52 def _stdin_ready_nt():
52 def _stdin_ready_nt():
53 """Return True if there's something to read on stdin (nt version)."""
53 """Return True if there's something to read on stdin (nt version)."""
54 return msvcrt.kbhit()
54 return msvcrt.kbhit()
55
55
56 def _stdin_ready_other():
56 def _stdin_ready_other():
57 """Return True, assuming there's something to read on stdin."""
57 """Return True, assuming there's something to read on stdin."""
58 return True #
58 return True #
59
59
60
60
61 def _ignore_CTRL_C_posix():
61 def _ignore_CTRL_C_posix():
62 """Ignore CTRL+C (SIGINT)."""
62 """Ignore CTRL+C (SIGINT)."""
63 signal.signal(signal.SIGINT, signal.SIG_IGN)
63 signal.signal(signal.SIGINT, signal.SIG_IGN)
64
64
65 def _allow_CTRL_C_posix():
65 def _allow_CTRL_C_posix():
66 """Take CTRL+C into account (SIGINT)."""
66 """Take CTRL+C into account (SIGINT)."""
67 signal.signal(signal.SIGINT, signal.default_int_handler)
67 signal.signal(signal.SIGINT, signal.default_int_handler)
68
68
69 def _ignore_CTRL_C_other():
69 def _ignore_CTRL_C_other():
70 """Ignore CTRL+C (not implemented)."""
70 """Ignore CTRL+C (not implemented)."""
71 pass
71 pass
72
72
73 def _allow_CTRL_C_other():
73 def _allow_CTRL_C_other():
74 """Take CTRL+C into account (not implemented)."""
74 """Take CTRL+C into account (not implemented)."""
75 pass
75 pass
76
76
77 if os.name == 'posix':
77 if os.name == 'posix':
78 import select
78 import select
79 import signal
79 import signal
80 stdin_ready = _stdin_ready_posix
80 stdin_ready = _stdin_ready_posix
81 ignore_CTRL_C = _ignore_CTRL_C_posix
81 ignore_CTRL_C = _ignore_CTRL_C_posix
82 allow_CTRL_C = _allow_CTRL_C_posix
82 allow_CTRL_C = _allow_CTRL_C_posix
83 elif os.name == 'nt':
83 elif os.name == 'nt':
84 import msvcrt
84 import msvcrt
85 stdin_ready = _stdin_ready_nt
85 stdin_ready = _stdin_ready_nt
86 ignore_CTRL_C = _ignore_CTRL_C_other
86 ignore_CTRL_C = _ignore_CTRL_C_other
87 allow_CTRL_C = _allow_CTRL_C_other
87 allow_CTRL_C = _allow_CTRL_C_other
88 else:
88 else:
89 stdin_ready = _stdin_ready_other
89 stdin_ready = _stdin_ready_other
90 ignore_CTRL_C = _ignore_CTRL_C_other
90 ignore_CTRL_C = _ignore_CTRL_C_other
91 allow_CTRL_C = _allow_CTRL_C_other
91 allow_CTRL_C = _allow_CTRL_C_other
92
92
93
93
94 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
95 # Main InputHookManager class
95 # Main InputHookManager class
96 #-----------------------------------------------------------------------------
96 #-----------------------------------------------------------------------------
97
97
98
98
99 class InputHookManager(object):
99 class InputHookManager(object):
100 """Manage PyOS_InputHook for different GUI toolkits.
100 """Manage PyOS_InputHook for different GUI toolkits.
101
101
102 This class installs various hooks under ``PyOSInputHook`` to handle
102 This class installs various hooks under ``PyOSInputHook`` to handle
103 GUI event loop integration.
103 GUI event loop integration.
104 """
104 """
105
105
106 def __init__(self):
106 def __init__(self):
107 if ctypes is None:
107 if ctypes is None:
108 warn("IPython GUI event loop requires ctypes, %gui will not be available\n")
108 warn("IPython GUI event loop requires ctypes, %gui will not be available\n")
109 return
109 return
110 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
110 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
111 self._apps = {}
111 self._apps = {}
112 self._reset()
112 self._reset()
113
113
114 def _reset(self):
114 def _reset(self):
115 self._callback_pyfunctype = None
115 self._callback_pyfunctype = None
116 self._callback = None
116 self._callback = None
117 self._installed = False
117 self._installed = False
118 self._current_gui = None
118 self._current_gui = None
119
119
120 def get_pyos_inputhook(self):
120 def get_pyos_inputhook(self):
121 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
121 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
122 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
122 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
123
123
124 def get_pyos_inputhook_as_func(self):
124 def get_pyos_inputhook_as_func(self):
125 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
125 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
126 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
126 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
127
127
128 def set_inputhook(self, callback):
128 def set_inputhook(self, callback):
129 """Set PyOS_InputHook to callback and return the previous one."""
129 """Set PyOS_InputHook to callback and return the previous one."""
130 # On platforms with 'readline' support, it's all too likely to
130 # On platforms with 'readline' support, it's all too likely to
131 # have a KeyboardInterrupt signal delivered *even before* an
131 # have a KeyboardInterrupt signal delivered *even before* an
132 # initial ``try:`` clause in the callback can be executed, so
132 # initial ``try:`` clause in the callback can be executed, so
133 # we need to disable CTRL+C in this situation.
133 # we need to disable CTRL+C in this situation.
134 ignore_CTRL_C()
134 ignore_CTRL_C()
135 self._callback = callback
135 self._callback = callback
136 self._callback_pyfunctype = self.PYFUNC(callback)
136 self._callback_pyfunctype = self.PYFUNC(callback)
137 pyos_inputhook_ptr = self.get_pyos_inputhook()
137 pyos_inputhook_ptr = self.get_pyos_inputhook()
138 original = self.get_pyos_inputhook_as_func()
138 original = self.get_pyos_inputhook_as_func()
139 pyos_inputhook_ptr.value = \
139 pyos_inputhook_ptr.value = \
140 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
140 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
141 self._installed = True
141 self._installed = True
142 return original
142 return original
143
143
144 def clear_inputhook(self, app=None):
144 def clear_inputhook(self, app=None):
145 """Set PyOS_InputHook to NULL and return the previous one.
145 """Set PyOS_InputHook to NULL and return the previous one.
146
146
147 Parameters
147 Parameters
148 ----------
148 ----------
149 app : optional, ignored
149 app : optional, ignored
150 This parameter is allowed only so that clear_inputhook() can be
150 This parameter is allowed only so that clear_inputhook() can be
151 called with a similar interface as all the ``enable_*`` methods. But
151 called with a similar interface as all the ``enable_*`` methods. But
152 the actual value of the parameter is ignored. This uniform interface
152 the actual value of the parameter is ignored. This uniform interface
153 makes it easier to have user-level entry points in the main IPython
153 makes it easier to have user-level entry points in the main IPython
154 app like :meth:`enable_gui`."""
154 app like :meth:`enable_gui`."""
155 pyos_inputhook_ptr = self.get_pyos_inputhook()
155 pyos_inputhook_ptr = self.get_pyos_inputhook()
156 original = self.get_pyos_inputhook_as_func()
156 original = self.get_pyos_inputhook_as_func()
157 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
157 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
158 allow_CTRL_C()
158 allow_CTRL_C()
159 self._reset()
159 self._reset()
160 return original
160 return original
161
161
162 def clear_app_refs(self, gui=None):
162 def clear_app_refs(self, gui=None):
163 """Clear IPython's internal reference to an application instance.
163 """Clear IPython's internal reference to an application instance.
164
164
165 Whenever we create an app for a user on qt4 or wx, we hold a
165 Whenever we create an app for a user on qt4 or wx, we hold a
166 reference to the app. This is needed because in some cases bad things
166 reference to the app. This is needed because in some cases bad things
167 can happen if a user doesn't hold a reference themselves. This
167 can happen if a user doesn't hold a reference themselves. This
168 method is provided to clear the references we are holding.
168 method is provided to clear the references we are holding.
169
169
170 Parameters
170 Parameters
171 ----------
171 ----------
172 gui : None or str
172 gui : None or str
173 If None, clear all app references. If ('wx', 'qt4') clear
173 If None, clear all app references. If ('wx', 'qt4') clear
174 the app for that toolkit. References are not held for gtk or tk
174 the app for that toolkit. References are not held for gtk or tk
175 as those toolkits don't have the notion of an app.
175 as those toolkits don't have the notion of an app.
176 """
176 """
177 if gui is None:
177 if gui is None:
178 self._apps = {}
178 self._apps = {}
179 elif self._apps.has_key(gui):
179 elif gui in self._apps:
180 del self._apps[gui]
180 del self._apps[gui]
181
181
182 def enable_wx(self, app=None):
182 def enable_wx(self, app=None):
183 """Enable event loop integration with wxPython.
183 """Enable event loop integration with wxPython.
184
184
185 Parameters
185 Parameters
186 ----------
186 ----------
187 app : WX Application, optional.
187 app : WX Application, optional.
188 Running application to use. If not given, we probe WX for an
188 Running application to use. If not given, we probe WX for an
189 existing application object, and create a new one if none is found.
189 existing application object, and create a new one if none is found.
190
190
191 Notes
191 Notes
192 -----
192 -----
193 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
193 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
194 the wxPython to integrate with terminal based applications like
194 the wxPython to integrate with terminal based applications like
195 IPython.
195 IPython.
196
196
197 If ``app`` is not given we probe for an existing one, and return it if
197 If ``app`` is not given we probe for an existing one, and return it if
198 found. If no existing app is found, we create an :class:`wx.App` as
198 found. If no existing app is found, we create an :class:`wx.App` as
199 follows::
199 follows::
200
200
201 import wx
201 import wx
202 app = wx.App(redirect=False, clearSigInt=False)
202 app = wx.App(redirect=False, clearSigInt=False)
203 """
203 """
204 import wx
204 import wx
205
205
206 wx_version = V(wx.__version__).version
206 wx_version = V(wx.__version__).version
207
207
208 if wx_version < [2, 8]:
208 if wx_version < [2, 8]:
209 raise ValueError("requires wxPython >= 2.8, but you have %s" % wx.__version__)
209 raise ValueError("requires wxPython >= 2.8, but you have %s" % wx.__version__)
210
210
211 from IPython.lib.inputhookwx import inputhook_wx
211 from IPython.lib.inputhookwx import inputhook_wx
212 self.set_inputhook(inputhook_wx)
212 self.set_inputhook(inputhook_wx)
213 self._current_gui = GUI_WX
213 self._current_gui = GUI_WX
214 import wx
214 import wx
215 if app is None:
215 if app is None:
216 app = wx.GetApp()
216 app = wx.GetApp()
217 if app is None:
217 if app is None:
218 app = wx.App(redirect=False, clearSigInt=False)
218 app = wx.App(redirect=False, clearSigInt=False)
219 app._in_event_loop = True
219 app._in_event_loop = True
220 self._apps[GUI_WX] = app
220 self._apps[GUI_WX] = app
221 return app
221 return app
222
222
223 def disable_wx(self):
223 def disable_wx(self):
224 """Disable event loop integration with wxPython.
224 """Disable event loop integration with wxPython.
225
225
226 This merely sets PyOS_InputHook to NULL.
226 This merely sets PyOS_InputHook to NULL.
227 """
227 """
228 if self._apps.has_key(GUI_WX):
228 if GUI_WX in self._apps:
229 self._apps[GUI_WX]._in_event_loop = False
229 self._apps[GUI_WX]._in_event_loop = False
230 self.clear_inputhook()
230 self.clear_inputhook()
231
231
232 def enable_qt4(self, app=None):
232 def enable_qt4(self, app=None):
233 """Enable event loop integration with PyQt4.
233 """Enable event loop integration with PyQt4.
234
234
235 Parameters
235 Parameters
236 ----------
236 ----------
237 app : Qt Application, optional.
237 app : Qt Application, optional.
238 Running application to use. If not given, we probe Qt for an
238 Running application to use. If not given, we probe Qt for an
239 existing application object, and create a new one if none is found.
239 existing application object, and create a new one if none is found.
240
240
241 Notes
241 Notes
242 -----
242 -----
243 This methods sets the PyOS_InputHook for PyQt4, which allows
243 This methods sets the PyOS_InputHook for PyQt4, which allows
244 the PyQt4 to integrate with terminal based applications like
244 the PyQt4 to integrate with terminal based applications like
245 IPython.
245 IPython.
246
246
247 If ``app`` is not given we probe for an existing one, and return it if
247 If ``app`` is not given we probe for an existing one, and return it if
248 found. If no existing app is found, we create an :class:`QApplication`
248 found. If no existing app is found, we create an :class:`QApplication`
249 as follows::
249 as follows::
250
250
251 from PyQt4 import QtCore
251 from PyQt4 import QtCore
252 app = QtGui.QApplication(sys.argv)
252 app = QtGui.QApplication(sys.argv)
253 """
253 """
254 from IPython.lib.inputhookqt4 import create_inputhook_qt4
254 from IPython.lib.inputhookqt4 import create_inputhook_qt4
255 app, inputhook_qt4 = create_inputhook_qt4(self, app)
255 app, inputhook_qt4 = create_inputhook_qt4(self, app)
256 self.set_inputhook(inputhook_qt4)
256 self.set_inputhook(inputhook_qt4)
257
257
258 self._current_gui = GUI_QT4
258 self._current_gui = GUI_QT4
259 app._in_event_loop = True
259 app._in_event_loop = True
260 self._apps[GUI_QT4] = app
260 self._apps[GUI_QT4] = app
261 return app
261 return app
262
262
263 def disable_qt4(self):
263 def disable_qt4(self):
264 """Disable event loop integration with PyQt4.
264 """Disable event loop integration with PyQt4.
265
265
266 This merely sets PyOS_InputHook to NULL.
266 This merely sets PyOS_InputHook to NULL.
267 """
267 """
268 if self._apps.has_key(GUI_QT4):
268 if GUI_QT4 in self._apps:
269 self._apps[GUI_QT4]._in_event_loop = False
269 self._apps[GUI_QT4]._in_event_loop = False
270 self.clear_inputhook()
270 self.clear_inputhook()
271
271
272 def enable_gtk(self, app=None):
272 def enable_gtk(self, app=None):
273 """Enable event loop integration with PyGTK.
273 """Enable event loop integration with PyGTK.
274
274
275 Parameters
275 Parameters
276 ----------
276 ----------
277 app : ignored
277 app : ignored
278 Ignored, it's only a placeholder to keep the call signature of all
278 Ignored, it's only a placeholder to keep the call signature of all
279 gui activation methods consistent, which simplifies the logic of
279 gui activation methods consistent, which simplifies the logic of
280 supporting magics.
280 supporting magics.
281
281
282 Notes
282 Notes
283 -----
283 -----
284 This methods sets the PyOS_InputHook for PyGTK, which allows
284 This methods sets the PyOS_InputHook for PyGTK, which allows
285 the PyGTK to integrate with terminal based applications like
285 the PyGTK to integrate with terminal based applications like
286 IPython.
286 IPython.
287 """
287 """
288 import gtk
288 import gtk
289 try:
289 try:
290 gtk.set_interactive(True)
290 gtk.set_interactive(True)
291 self._current_gui = GUI_GTK
291 self._current_gui = GUI_GTK
292 except AttributeError:
292 except AttributeError:
293 # For older versions of gtk, use our own ctypes version
293 # For older versions of gtk, use our own ctypes version
294 from IPython.lib.inputhookgtk import inputhook_gtk
294 from IPython.lib.inputhookgtk import inputhook_gtk
295 self.set_inputhook(inputhook_gtk)
295 self.set_inputhook(inputhook_gtk)
296 self._current_gui = GUI_GTK
296 self._current_gui = GUI_GTK
297
297
298 def disable_gtk(self):
298 def disable_gtk(self):
299 """Disable event loop integration with PyGTK.
299 """Disable event loop integration with PyGTK.
300
300
301 This merely sets PyOS_InputHook to NULL.
301 This merely sets PyOS_InputHook to NULL.
302 """
302 """
303 self.clear_inputhook()
303 self.clear_inputhook()
304
304
305 def enable_tk(self, app=None):
305 def enable_tk(self, app=None):
306 """Enable event loop integration with Tk.
306 """Enable event loop integration with Tk.
307
307
308 Parameters
308 Parameters
309 ----------
309 ----------
310 app : toplevel :class:`Tkinter.Tk` widget, optional.
310 app : toplevel :class:`Tkinter.Tk` widget, optional.
311 Running toplevel widget to use. If not given, we probe Tk for an
311 Running toplevel widget to use. If not given, we probe Tk for an
312 existing one, and create a new one if none is found.
312 existing one, and create a new one if none is found.
313
313
314 Notes
314 Notes
315 -----
315 -----
316 If you have already created a :class:`Tkinter.Tk` object, the only
316 If you have already created a :class:`Tkinter.Tk` object, the only
317 thing done by this method is to register with the
317 thing done by this method is to register with the
318 :class:`InputHookManager`, since creating that object automatically
318 :class:`InputHookManager`, since creating that object automatically
319 sets ``PyOS_InputHook``.
319 sets ``PyOS_InputHook``.
320 """
320 """
321 self._current_gui = GUI_TK
321 self._current_gui = GUI_TK
322 if app is None:
322 if app is None:
323 import Tkinter
323 import Tkinter
324 app = Tkinter.Tk()
324 app = Tkinter.Tk()
325 app.withdraw()
325 app.withdraw()
326 self._apps[GUI_TK] = app
326 self._apps[GUI_TK] = app
327 return app
327 return app
328
328
329 def disable_tk(self):
329 def disable_tk(self):
330 """Disable event loop integration with Tkinter.
330 """Disable event loop integration with Tkinter.
331
331
332 This merely sets PyOS_InputHook to NULL.
332 This merely sets PyOS_InputHook to NULL.
333 """
333 """
334 self.clear_inputhook()
334 self.clear_inputhook()
335
335
336
336
337 def enable_glut(self, app=None):
337 def enable_glut(self, app=None):
338 """ Enable event loop integration with GLUT.
338 """ Enable event loop integration with GLUT.
339
339
340 Parameters
340 Parameters
341 ----------
341 ----------
342
342
343 app : ignored
343 app : ignored
344 Ignored, it's only a placeholder to keep the call signature of all
344 Ignored, it's only a placeholder to keep the call signature of all
345 gui activation methods consistent, which simplifies the logic of
345 gui activation methods consistent, which simplifies the logic of
346 supporting magics.
346 supporting magics.
347
347
348 Notes
348 Notes
349 -----
349 -----
350
350
351 This methods sets the PyOS_InputHook for GLUT, which allows the GLUT to
351 This methods sets the PyOS_InputHook for GLUT, which allows the GLUT to
352 integrate with terminal based applications like IPython. Due to GLUT
352 integrate with terminal based applications like IPython. Due to GLUT
353 limitations, it is currently not possible to start the event loop
353 limitations, it is currently not possible to start the event loop
354 without first creating a window. You should thus not create another
354 without first creating a window. You should thus not create another
355 window but use instead the created one. See 'gui-glut.py' in the
355 window but use instead the created one. See 'gui-glut.py' in the
356 docs/examples/lib directory.
356 docs/examples/lib directory.
357
357
358 The default screen mode is set to:
358 The default screen mode is set to:
359 glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH
359 glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH
360 """
360 """
361
361
362 import OpenGL.GLUT as glut
362 import OpenGL.GLUT as glut
363 from IPython.lib.inputhookglut import glut_display_mode, \
363 from IPython.lib.inputhookglut import glut_display_mode, \
364 glut_close, glut_display, \
364 glut_close, glut_display, \
365 glut_idle, inputhook_glut
365 glut_idle, inputhook_glut
366
366
367 if not self._apps.has_key( GUI_GLUT ):
367 if GUI_GLUT not in self._apps:
368 glut.glutInit( sys.argv )
368 glut.glutInit( sys.argv )
369 glut.glutInitDisplayMode( glut_display_mode )
369 glut.glutInitDisplayMode( glut_display_mode )
370 # This is specific to freeglut
370 # This is specific to freeglut
371 if bool(glut.glutSetOption):
371 if bool(glut.glutSetOption):
372 glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
372 glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
373 glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
373 glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
374 glut.glutCreateWindow( sys.argv[0] )
374 glut.glutCreateWindow( sys.argv[0] )
375 glut.glutReshapeWindow( 1, 1 )
375 glut.glutReshapeWindow( 1, 1 )
376 glut.glutHideWindow( )
376 glut.glutHideWindow( )
377 glut.glutWMCloseFunc( glut_close )
377 glut.glutWMCloseFunc( glut_close )
378 glut.glutDisplayFunc( glut_display )
378 glut.glutDisplayFunc( glut_display )
379 glut.glutIdleFunc( glut_idle )
379 glut.glutIdleFunc( glut_idle )
380 else:
380 else:
381 glut.glutWMCloseFunc( glut_close )
381 glut.glutWMCloseFunc( glut_close )
382 glut.glutDisplayFunc( glut_display )
382 glut.glutDisplayFunc( glut_display )
383 glut.glutIdleFunc( glut_idle)
383 glut.glutIdleFunc( glut_idle)
384 self.set_inputhook( inputhook_glut )
384 self.set_inputhook( inputhook_glut )
385 self._current_gui = GUI_GLUT
385 self._current_gui = GUI_GLUT
386 self._apps[GUI_GLUT] = True
386 self._apps[GUI_GLUT] = True
387
387
388
388
389 def disable_glut(self):
389 def disable_glut(self):
390 """Disable event loop integration with glut.
390 """Disable event loop integration with glut.
391
391
392 This sets PyOS_InputHook to NULL and set the display function to a
392 This sets PyOS_InputHook to NULL and set the display function to a
393 dummy one and set the timer to a dummy timer that will be triggered
393 dummy one and set the timer to a dummy timer that will be triggered
394 very far in the future.
394 very far in the future.
395 """
395 """
396 import OpenGL.GLUT as glut
396 import OpenGL.GLUT as glut
397 from glut_support import glutMainLoopEvent
397 from glut_support import glutMainLoopEvent
398
398
399 glut.glutHideWindow() # This is an event to be processed below
399 glut.glutHideWindow() # This is an event to be processed below
400 glutMainLoopEvent()
400 glutMainLoopEvent()
401 self.clear_inputhook()
401 self.clear_inputhook()
402
402
403 def enable_pyglet(self, app=None):
403 def enable_pyglet(self, app=None):
404 """Enable event loop integration with pyglet.
404 """Enable event loop integration with pyglet.
405
405
406 Parameters
406 Parameters
407 ----------
407 ----------
408 app : ignored
408 app : ignored
409 Ignored, it's only a placeholder to keep the call signature of all
409 Ignored, it's only a placeholder to keep the call signature of all
410 gui activation methods consistent, which simplifies the logic of
410 gui activation methods consistent, which simplifies the logic of
411 supporting magics.
411 supporting magics.
412
412
413 Notes
413 Notes
414 -----
414 -----
415 This methods sets the ``PyOS_InputHook`` for pyglet, which allows
415 This methods sets the ``PyOS_InputHook`` for pyglet, which allows
416 pyglet to integrate with terminal based applications like
416 pyglet to integrate with terminal based applications like
417 IPython.
417 IPython.
418
418
419 """
419 """
420 import pyglet
420 import pyglet
421 from IPython.lib.inputhookpyglet import inputhook_pyglet
421 from IPython.lib.inputhookpyglet import inputhook_pyglet
422 self.set_inputhook(inputhook_pyglet)
422 self.set_inputhook(inputhook_pyglet)
423 self._current_gui = GUI_PYGLET
423 self._current_gui = GUI_PYGLET
424 return app
424 return app
425
425
426 def disable_pyglet(self):
426 def disable_pyglet(self):
427 """Disable event loop integration with pyglet.
427 """Disable event loop integration with pyglet.
428
428
429 This merely sets PyOS_InputHook to NULL.
429 This merely sets PyOS_InputHook to NULL.
430 """
430 """
431 self.clear_inputhook()
431 self.clear_inputhook()
432
432
433 def enable_gtk3(self, app=None):
433 def enable_gtk3(self, app=None):
434 """Enable event loop integration with Gtk3 (gir bindings).
434 """Enable event loop integration with Gtk3 (gir bindings).
435
435
436 Parameters
436 Parameters
437 ----------
437 ----------
438 app : ignored
438 app : ignored
439 Ignored, it's only a placeholder to keep the call signature of all
439 Ignored, it's only a placeholder to keep the call signature of all
440 gui activation methods consistent, which simplifies the logic of
440 gui activation methods consistent, which simplifies the logic of
441 supporting magics.
441 supporting magics.
442
442
443 Notes
443 Notes
444 -----
444 -----
445 This methods sets the PyOS_InputHook for Gtk3, which allows
445 This methods sets the PyOS_InputHook for Gtk3, which allows
446 the Gtk3 to integrate with terminal based applications like
446 the Gtk3 to integrate with terminal based applications like
447 IPython.
447 IPython.
448 """
448 """
449 from IPython.lib.inputhookgtk3 import inputhook_gtk3
449 from IPython.lib.inputhookgtk3 import inputhook_gtk3
450 self.set_inputhook(inputhook_gtk3)
450 self.set_inputhook(inputhook_gtk3)
451 self._current_gui = GUI_GTK
451 self._current_gui = GUI_GTK
452
452
453 def disable_gtk3(self):
453 def disable_gtk3(self):
454 """Disable event loop integration with PyGTK.
454 """Disable event loop integration with PyGTK.
455
455
456 This merely sets PyOS_InputHook to NULL.
456 This merely sets PyOS_InputHook to NULL.
457 """
457 """
458 self.clear_inputhook()
458 self.clear_inputhook()
459
459
460 def current_gui(self):
460 def current_gui(self):
461 """Return a string indicating the currently active GUI or None."""
461 """Return a string indicating the currently active GUI or None."""
462 return self._current_gui
462 return self._current_gui
463
463
464 inputhook_manager = InputHookManager()
464 inputhook_manager = InputHookManager()
465
465
466 enable_wx = inputhook_manager.enable_wx
466 enable_wx = inputhook_manager.enable_wx
467 disable_wx = inputhook_manager.disable_wx
467 disable_wx = inputhook_manager.disable_wx
468 enable_qt4 = inputhook_manager.enable_qt4
468 enable_qt4 = inputhook_manager.enable_qt4
469 disable_qt4 = inputhook_manager.disable_qt4
469 disable_qt4 = inputhook_manager.disable_qt4
470 enable_gtk = inputhook_manager.enable_gtk
470 enable_gtk = inputhook_manager.enable_gtk
471 disable_gtk = inputhook_manager.disable_gtk
471 disable_gtk = inputhook_manager.disable_gtk
472 enable_tk = inputhook_manager.enable_tk
472 enable_tk = inputhook_manager.enable_tk
473 disable_tk = inputhook_manager.disable_tk
473 disable_tk = inputhook_manager.disable_tk
474 enable_glut = inputhook_manager.enable_glut
474 enable_glut = inputhook_manager.enable_glut
475 disable_glut = inputhook_manager.disable_glut
475 disable_glut = inputhook_manager.disable_glut
476 enable_pyglet = inputhook_manager.enable_pyglet
476 enable_pyglet = inputhook_manager.enable_pyglet
477 disable_pyglet = inputhook_manager.disable_pyglet
477 disable_pyglet = inputhook_manager.disable_pyglet
478 enable_gtk3 = inputhook_manager.enable_gtk3
478 enable_gtk3 = inputhook_manager.enable_gtk3
479 disable_gtk3 = inputhook_manager.disable_gtk3
479 disable_gtk3 = inputhook_manager.disable_gtk3
480 clear_inputhook = inputhook_manager.clear_inputhook
480 clear_inputhook = inputhook_manager.clear_inputhook
481 set_inputhook = inputhook_manager.set_inputhook
481 set_inputhook = inputhook_manager.set_inputhook
482 current_gui = inputhook_manager.current_gui
482 current_gui = inputhook_manager.current_gui
483 clear_app_refs = inputhook_manager.clear_app_refs
483 clear_app_refs = inputhook_manager.clear_app_refs
484
484
485
485
486 # Convenience function to switch amongst them
486 # Convenience function to switch amongst them
487 def enable_gui(gui=None, app=None):
487 def enable_gui(gui=None, app=None):
488 """Switch amongst GUI input hooks by name.
488 """Switch amongst GUI input hooks by name.
489
489
490 This is just a utility wrapper around the methods of the InputHookManager
490 This is just a utility wrapper around the methods of the InputHookManager
491 object.
491 object.
492
492
493 Parameters
493 Parameters
494 ----------
494 ----------
495 gui : optional, string or None
495 gui : optional, string or None
496 If None (or 'none'), clears input hook, otherwise it must be one
496 If None (or 'none'), clears input hook, otherwise it must be one
497 of the recognized GUI names (see ``GUI_*`` constants in module).
497 of the recognized GUI names (see ``GUI_*`` constants in module).
498
498
499 app : optional, existing application object.
499 app : optional, existing application object.
500 For toolkits that have the concept of a global app, you can supply an
500 For toolkits that have the concept of a global app, you can supply an
501 existing one. If not given, the toolkit will be probed for one, and if
501 existing one. If not given, the toolkit will be probed for one, and if
502 none is found, a new one will be created. Note that GTK does not have
502 none is found, a new one will be created. Note that GTK does not have
503 this concept, and passing an app if `gui`=="GTK" will raise an error.
503 this concept, and passing an app if `gui`=="GTK" will raise an error.
504
504
505 Returns
505 Returns
506 -------
506 -------
507 The output of the underlying gui switch routine, typically the actual
507 The output of the underlying gui switch routine, typically the actual
508 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
508 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
509 one.
509 one.
510 """
510 """
511 guis = {None: clear_inputhook,
511 guis = {None: clear_inputhook,
512 GUI_NONE: clear_inputhook,
512 GUI_NONE: clear_inputhook,
513 GUI_OSX: lambda app=False: None,
513 GUI_OSX: lambda app=False: None,
514 GUI_TK: enable_tk,
514 GUI_TK: enable_tk,
515 GUI_GTK: enable_gtk,
515 GUI_GTK: enable_gtk,
516 GUI_WX: enable_wx,
516 GUI_WX: enable_wx,
517 GUI_QT: enable_qt4, # qt3 not supported
517 GUI_QT: enable_qt4, # qt3 not supported
518 GUI_QT4: enable_qt4,
518 GUI_QT4: enable_qt4,
519 GUI_GLUT: enable_glut,
519 GUI_GLUT: enable_glut,
520 GUI_PYGLET: enable_pyglet,
520 GUI_PYGLET: enable_pyglet,
521 GUI_GTK3: enable_gtk3,
521 GUI_GTK3: enable_gtk3,
522 }
522 }
523 try:
523 try:
524 gui_hook = guis[gui]
524 gui_hook = guis[gui]
525 except KeyError:
525 except KeyError:
526 e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
526 e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
527 raise ValueError(e)
527 raise ValueError(e)
528 return gui_hook(app)
528 return gui_hook(app)
529
529
@@ -1,220 +1,220 b''
1 """A Task logger that presents our DB interface,
1 """A Task logger that presents our DB interface,
2 but exists entirely in memory and implemented with dicts.
2 but exists entirely in memory and implemented with dicts.
3
3
4 Authors:
4 Authors:
5
5
6 * Min RK
6 * Min RK
7
7
8
8
9 TaskRecords are dicts of the form:
9 TaskRecords are dicts of the form:
10 {
10 {
11 'msg_id' : str(uuid),
11 'msg_id' : str(uuid),
12 'client_uuid' : str(uuid),
12 'client_uuid' : str(uuid),
13 'engine_uuid' : str(uuid) or None,
13 'engine_uuid' : str(uuid) or None,
14 'header' : dict(header),
14 'header' : dict(header),
15 'content': dict(content),
15 'content': dict(content),
16 'buffers': list(buffers),
16 'buffers': list(buffers),
17 'submitted': datetime,
17 'submitted': datetime,
18 'started': datetime or None,
18 'started': datetime or None,
19 'completed': datetime or None,
19 'completed': datetime or None,
20 'resubmitted': datetime or None,
20 'resubmitted': datetime or None,
21 'result_header' : dict(header) or None,
21 'result_header' : dict(header) or None,
22 'result_content' : dict(content) or None,
22 'result_content' : dict(content) or None,
23 'result_buffers' : list(buffers) or None,
23 'result_buffers' : list(buffers) or None,
24 }
24 }
25 With this info, many of the special categories of tasks can be defined by query:
25 With this info, many of the special categories of tasks can be defined by query:
26
26
27 pending: completed is None
27 pending: completed is None
28 client's outstanding: client_uuid = uuid && completed is None
28 client's outstanding: client_uuid = uuid && completed is None
29 MIA: arrived is None (and completed is None)
29 MIA: arrived is None (and completed is None)
30 etc.
30 etc.
31
31
32 EngineRecords are dicts of the form:
32 EngineRecords are dicts of the form:
33 {
33 {
34 'eid' : int(id),
34 'eid' : int(id),
35 'uuid': str(uuid)
35 'uuid': str(uuid)
36 }
36 }
37 This may be extended, but is currently.
37 This may be extended, but is currently.
38
38
39 We support a subset of mongodb operators:
39 We support a subset of mongodb operators:
40 $lt,$gt,$lte,$gte,$ne,$in,$nin,$all,$mod,$exists
40 $lt,$gt,$lte,$gte,$ne,$in,$nin,$all,$mod,$exists
41 """
41 """
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Copyright (C) 2010-2011 The IPython Development Team
43 # Copyright (C) 2010-2011 The IPython Development Team
44 #
44 #
45 # Distributed under the terms of the BSD License. The full license is in
45 # Distributed under the terms of the BSD License. The full license is in
46 # the file COPYING, distributed as part of this software.
46 # the file COPYING, distributed as part of this software.
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 from copy import deepcopy as copy
49 from copy import deepcopy as copy
50 from datetime import datetime
50 from datetime import datetime
51
51
52 from IPython.config.configurable import LoggingConfigurable
52 from IPython.config.configurable import LoggingConfigurable
53
53
54 from IPython.utils.traitlets import Dict, Unicode, Instance
54 from IPython.utils.traitlets import Dict, Unicode, Instance
55
55
56 filters = {
56 filters = {
57 '$lt' : lambda a,b: a < b,
57 '$lt' : lambda a,b: a < b,
58 '$gt' : lambda a,b: b > a,
58 '$gt' : lambda a,b: b > a,
59 '$eq' : lambda a,b: a == b,
59 '$eq' : lambda a,b: a == b,
60 '$ne' : lambda a,b: a != b,
60 '$ne' : lambda a,b: a != b,
61 '$lte': lambda a,b: a <= b,
61 '$lte': lambda a,b: a <= b,
62 '$gte': lambda a,b: a >= b,
62 '$gte': lambda a,b: a >= b,
63 '$in' : lambda a,b: a in b,
63 '$in' : lambda a,b: a in b,
64 '$nin': lambda a,b: a not in b,
64 '$nin': lambda a,b: a not in b,
65 '$all': lambda a,b: all([ a in bb for bb in b ]),
65 '$all': lambda a,b: all([ a in bb for bb in b ]),
66 '$mod': lambda a,b: a%b[0] == b[1],
66 '$mod': lambda a,b: a%b[0] == b[1],
67 '$exists' : lambda a,b: (b and a is not None) or (a is None and not b)
67 '$exists' : lambda a,b: (b and a is not None) or (a is None and not b)
68 }
68 }
69
69
70
70
71 class CompositeFilter(object):
71 class CompositeFilter(object):
72 """Composite filter for matching multiple properties."""
72 """Composite filter for matching multiple properties."""
73
73
74 def __init__(self, dikt):
74 def __init__(self, dikt):
75 self.tests = []
75 self.tests = []
76 self.values = []
76 self.values = []
77 for key, value in dikt.iteritems():
77 for key, value in dikt.iteritems():
78 self.tests.append(filters[key])
78 self.tests.append(filters[key])
79 self.values.append(value)
79 self.values.append(value)
80
80
81 def __call__(self, value):
81 def __call__(self, value):
82 for test,check in zip(self.tests, self.values):
82 for test,check in zip(self.tests, self.values):
83 if not test(value, check):
83 if not test(value, check):
84 return False
84 return False
85 return True
85 return True
86
86
87 class BaseDB(LoggingConfigurable):
87 class BaseDB(LoggingConfigurable):
88 """Empty Parent class so traitlets work on DB."""
88 """Empty Parent class so traitlets work on DB."""
89 # base configurable traits:
89 # base configurable traits:
90 session = Unicode("")
90 session = Unicode("")
91
91
92 class DictDB(BaseDB):
92 class DictDB(BaseDB):
93 """Basic in-memory dict-based object for saving Task Records.
93 """Basic in-memory dict-based object for saving Task Records.
94
94
95 This is the first object to present the DB interface
95 This is the first object to present the DB interface
96 for logging tasks out of memory.
96 for logging tasks out of memory.
97
97
98 The interface is based on MongoDB, so adding a MongoDB
98 The interface is based on MongoDB, so adding a MongoDB
99 backend should be straightforward.
99 backend should be straightforward.
100 """
100 """
101
101
102 _records = Dict()
102 _records = Dict()
103
103
104 def _match_one(self, rec, tests):
104 def _match_one(self, rec, tests):
105 """Check if a specific record matches tests."""
105 """Check if a specific record matches tests."""
106 for key,test in tests.iteritems():
106 for key,test in tests.iteritems():
107 if not test(rec.get(key, None)):
107 if not test(rec.get(key, None)):
108 return False
108 return False
109 return True
109 return True
110
110
111 def _match(self, check):
111 def _match(self, check):
112 """Find all the matches for a check dict."""
112 """Find all the matches for a check dict."""
113 matches = []
113 matches = []
114 tests = {}
114 tests = {}
115 for k,v in check.iteritems():
115 for k,v in check.iteritems():
116 if isinstance(v, dict):
116 if isinstance(v, dict):
117 tests[k] = CompositeFilter(v)
117 tests[k] = CompositeFilter(v)
118 else:
118 else:
119 tests[k] = lambda o: o==v
119 tests[k] = lambda o: o==v
120
120
121 for rec in self._records.itervalues():
121 for rec in self._records.itervalues():
122 if self._match_one(rec, tests):
122 if self._match_one(rec, tests):
123 matches.append(copy(rec))
123 matches.append(copy(rec))
124 return matches
124 return matches
125
125
126 def _extract_subdict(self, rec, keys):
126 def _extract_subdict(self, rec, keys):
127 """extract subdict of keys"""
127 """extract subdict of keys"""
128 d = {}
128 d = {}
129 d['msg_id'] = rec['msg_id']
129 d['msg_id'] = rec['msg_id']
130 for key in keys:
130 for key in keys:
131 d[key] = rec[key]
131 d[key] = rec[key]
132 return copy(d)
132 return copy(d)
133
133
134 def add_record(self, msg_id, rec):
134 def add_record(self, msg_id, rec):
135 """Add a new Task Record, by msg_id."""
135 """Add a new Task Record, by msg_id."""
136 if self._records.has_key(msg_id):
136 if msg_id in self._records:
137 raise KeyError("Already have msg_id %r"%(msg_id))
137 raise KeyError("Already have msg_id %r"%(msg_id))
138 self._records[msg_id] = rec
138 self._records[msg_id] = rec
139
139
140 def get_record(self, msg_id):
140 def get_record(self, msg_id):
141 """Get a specific Task Record, by msg_id."""
141 """Get a specific Task Record, by msg_id."""
142 if not msg_id in self._records:
142 if not msg_id in self._records:
143 raise KeyError("No such msg_id %r"%(msg_id))
143 raise KeyError("No such msg_id %r"%(msg_id))
144 return copy(self._records[msg_id])
144 return copy(self._records[msg_id])
145
145
146 def update_record(self, msg_id, rec):
146 def update_record(self, msg_id, rec):
147 """Update the data in an existing record."""
147 """Update the data in an existing record."""
148 self._records[msg_id].update(rec)
148 self._records[msg_id].update(rec)
149
149
150 def drop_matching_records(self, check):
150 def drop_matching_records(self, check):
151 """Remove a record from the DB."""
151 """Remove a record from the DB."""
152 matches = self._match(check)
152 matches = self._match(check)
153 for m in matches:
153 for m in matches:
154 del self._records[m['msg_id']]
154 del self._records[m['msg_id']]
155
155
156 def drop_record(self, msg_id):
156 def drop_record(self, msg_id):
157 """Remove a record from the DB."""
157 """Remove a record from the DB."""
158 del self._records[msg_id]
158 del self._records[msg_id]
159
159
160
160
161 def find_records(self, check, keys=None):
161 def find_records(self, check, keys=None):
162 """Find records matching a query dict, optionally extracting subset of keys.
162 """Find records matching a query dict, optionally extracting subset of keys.
163
163
164 Returns dict keyed by msg_id of matching records.
164 Returns dict keyed by msg_id of matching records.
165
165
166 Parameters
166 Parameters
167 ----------
167 ----------
168
168
169 check: dict
169 check: dict
170 mongodb-style query argument
170 mongodb-style query argument
171 keys: list of strs [optional]
171 keys: list of strs [optional]
172 if specified, the subset of keys to extract. msg_id will *always* be
172 if specified, the subset of keys to extract. msg_id will *always* be
173 included.
173 included.
174 """
174 """
175 matches = self._match(check)
175 matches = self._match(check)
176 if keys:
176 if keys:
177 return [ self._extract_subdict(rec, keys) for rec in matches ]
177 return [ self._extract_subdict(rec, keys) for rec in matches ]
178 else:
178 else:
179 return matches
179 return matches
180
180
181
181
182 def get_history(self):
182 def get_history(self):
183 """get all msg_ids, ordered by time submitted."""
183 """get all msg_ids, ordered by time submitted."""
184 msg_ids = self._records.keys()
184 msg_ids = self._records.keys()
185 return sorted(msg_ids, key=lambda m: self._records[m]['submitted'])
185 return sorted(msg_ids, key=lambda m: self._records[m]['submitted'])
186
186
187 NODATA = KeyError("NoDB backend doesn't store any data. "
187 NODATA = KeyError("NoDB backend doesn't store any data. "
188 "Start the Controller with a DB backend to enable resubmission / result persistence."
188 "Start the Controller with a DB backend to enable resubmission / result persistence."
189 )
189 )
190
190
191 class NoDB(DictDB):
191 class NoDB(DictDB):
192 """A blackhole db backend that actually stores no information.
192 """A blackhole db backend that actually stores no information.
193
193
194 Provides the full DB interface, but raises KeyErrors on any
194 Provides the full DB interface, but raises KeyErrors on any
195 method that tries to access the records. This can be used to
195 method that tries to access the records. This can be used to
196 minimize the memory footprint of the Hub when its record-keeping
196 minimize the memory footprint of the Hub when its record-keeping
197 functionality is not required.
197 functionality is not required.
198 """
198 """
199
199
200 def add_record(self, msg_id, record):
200 def add_record(self, msg_id, record):
201 pass
201 pass
202
202
203 def get_record(self, msg_id):
203 def get_record(self, msg_id):
204 raise NODATA
204 raise NODATA
205
205
206 def update_record(self, msg_id, record):
206 def update_record(self, msg_id, record):
207 pass
207 pass
208
208
209 def drop_matching_records(self, check):
209 def drop_matching_records(self, check):
210 pass
210 pass
211
211
212 def drop_record(self, msg_id):
212 def drop_record(self, msg_id):
213 pass
213 pass
214
214
215 def find_records(self, check, keys=None):
215 def find_records(self, check, keys=None):
216 raise NODATA
216 raise NODATA
217
217
218 def get_history(self):
218 def get_history(self):
219 raise NODATA
219 raise NODATA
220
220
@@ -1,358 +1,358 b''
1 """some generic utilities for dealing with classes, urls, and serialization
1 """some generic utilities for dealing with classes, urls, and serialization
2
2
3 Authors:
3 Authors:
4
4
5 * Min RK
5 * Min RK
6 """
6 """
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2010-2011 The IPython Development Team
8 # Copyright (C) 2010-2011 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 # Standard library imports.
18 # Standard library imports.
19 import logging
19 import logging
20 import os
20 import os
21 import re
21 import re
22 import stat
22 import stat
23 import socket
23 import socket
24 import sys
24 import sys
25 from signal import signal, SIGINT, SIGABRT, SIGTERM
25 from signal import signal, SIGINT, SIGABRT, SIGTERM
26 try:
26 try:
27 from signal import SIGKILL
27 from signal import SIGKILL
28 except ImportError:
28 except ImportError:
29 SIGKILL=None
29 SIGKILL=None
30
30
31 try:
31 try:
32 import cPickle
32 import cPickle
33 pickle = cPickle
33 pickle = cPickle
34 except:
34 except:
35 cPickle = None
35 cPickle = None
36 import pickle
36 import pickle
37
37
38 # System library imports
38 # System library imports
39 import zmq
39 import zmq
40 from zmq.log import handlers
40 from zmq.log import handlers
41
41
42 from IPython.external.decorator import decorator
42 from IPython.external.decorator import decorator
43
43
44 # IPython imports
44 # IPython imports
45 from IPython.config.application import Application
45 from IPython.config.application import Application
46 from IPython.utils import py3compat
46 from IPython.utils import py3compat
47 from IPython.utils.pickleutil import can, uncan, canSequence, uncanSequence
47 from IPython.utils.pickleutil import can, uncan, canSequence, uncanSequence
48 from IPython.utils.newserialized import serialize, unserialize
48 from IPython.utils.newserialized import serialize, unserialize
49 from IPython.zmq.log import EnginePUBHandler
49 from IPython.zmq.log import EnginePUBHandler
50 from IPython.zmq.serialize import (
50 from IPython.zmq.serialize import (
51 unserialize_object, serialize_object, pack_apply_message, unpack_apply_message
51 unserialize_object, serialize_object, pack_apply_message, unpack_apply_message
52 )
52 )
53
53
54 if py3compat.PY3:
54 if py3compat.PY3:
55 buffer = memoryview
55 buffer = memoryview
56
56
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58 # Classes
58 # Classes
59 #-----------------------------------------------------------------------------
59 #-----------------------------------------------------------------------------
60
60
61 class Namespace(dict):
61 class Namespace(dict):
62 """Subclass of dict for attribute access to keys."""
62 """Subclass of dict for attribute access to keys."""
63
63
64 def __getattr__(self, key):
64 def __getattr__(self, key):
65 """getattr aliased to getitem"""
65 """getattr aliased to getitem"""
66 if key in self.iterkeys():
66 if key in self.iterkeys():
67 return self[key]
67 return self[key]
68 else:
68 else:
69 raise NameError(key)
69 raise NameError(key)
70
70
71 def __setattr__(self, key, value):
71 def __setattr__(self, key, value):
72 """setattr aliased to setitem, with strict"""
72 """setattr aliased to setitem, with strict"""
73 if hasattr(dict, key):
73 if hasattr(dict, key):
74 raise KeyError("Cannot override dict keys %r"%key)
74 raise KeyError("Cannot override dict keys %r"%key)
75 self[key] = value
75 self[key] = value
76
76
77
77
78 class ReverseDict(dict):
78 class ReverseDict(dict):
79 """simple double-keyed subset of dict methods."""
79 """simple double-keyed subset of dict methods."""
80
80
81 def __init__(self, *args, **kwargs):
81 def __init__(self, *args, **kwargs):
82 dict.__init__(self, *args, **kwargs)
82 dict.__init__(self, *args, **kwargs)
83 self._reverse = dict()
83 self._reverse = dict()
84 for key, value in self.iteritems():
84 for key, value in self.iteritems():
85 self._reverse[value] = key
85 self._reverse[value] = key
86
86
87 def __getitem__(self, key):
87 def __getitem__(self, key):
88 try:
88 try:
89 return dict.__getitem__(self, key)
89 return dict.__getitem__(self, key)
90 except KeyError:
90 except KeyError:
91 return self._reverse[key]
91 return self._reverse[key]
92
92
93 def __setitem__(self, key, value):
93 def __setitem__(self, key, value):
94 if key in self._reverse:
94 if key in self._reverse:
95 raise KeyError("Can't have key %r on both sides!"%key)
95 raise KeyError("Can't have key %r on both sides!"%key)
96 dict.__setitem__(self, key, value)
96 dict.__setitem__(self, key, value)
97 self._reverse[value] = key
97 self._reverse[value] = key
98
98
99 def pop(self, key):
99 def pop(self, key):
100 value = dict.pop(self, key)
100 value = dict.pop(self, key)
101 self._reverse.pop(value)
101 self._reverse.pop(value)
102 return value
102 return value
103
103
104 def get(self, key, default=None):
104 def get(self, key, default=None):
105 try:
105 try:
106 return self[key]
106 return self[key]
107 except KeyError:
107 except KeyError:
108 return default
108 return default
109
109
110 #-----------------------------------------------------------------------------
110 #-----------------------------------------------------------------------------
111 # Functions
111 # Functions
112 #-----------------------------------------------------------------------------
112 #-----------------------------------------------------------------------------
113
113
114 @decorator
114 @decorator
115 def log_errors(f, self, *args, **kwargs):
115 def log_errors(f, self, *args, **kwargs):
116 """decorator to log unhandled exceptions raised in a method.
116 """decorator to log unhandled exceptions raised in a method.
117
117
118 For use wrapping on_recv callbacks, so that exceptions
118 For use wrapping on_recv callbacks, so that exceptions
119 do not cause the stream to be closed.
119 do not cause the stream to be closed.
120 """
120 """
121 try:
121 try:
122 return f(self, *args, **kwargs)
122 return f(self, *args, **kwargs)
123 except Exception:
123 except Exception:
124 self.log.error("Uncaught exception in %r" % f, exc_info=True)
124 self.log.error("Uncaught exception in %r" % f, exc_info=True)
125
125
126
126
127 def is_url(url):
127 def is_url(url):
128 """boolean check for whether a string is a zmq url"""
128 """boolean check for whether a string is a zmq url"""
129 if '://' not in url:
129 if '://' not in url:
130 return False
130 return False
131 proto, addr = url.split('://', 1)
131 proto, addr = url.split('://', 1)
132 if proto.lower() not in ['tcp','pgm','epgm','ipc','inproc']:
132 if proto.lower() not in ['tcp','pgm','epgm','ipc','inproc']:
133 return False
133 return False
134 return True
134 return True
135
135
136 def validate_url(url):
136 def validate_url(url):
137 """validate a url for zeromq"""
137 """validate a url for zeromq"""
138 if not isinstance(url, basestring):
138 if not isinstance(url, basestring):
139 raise TypeError("url must be a string, not %r"%type(url))
139 raise TypeError("url must be a string, not %r"%type(url))
140 url = url.lower()
140 url = url.lower()
141
141
142 proto_addr = url.split('://')
142 proto_addr = url.split('://')
143 assert len(proto_addr) == 2, 'Invalid url: %r'%url
143 assert len(proto_addr) == 2, 'Invalid url: %r'%url
144 proto, addr = proto_addr
144 proto, addr = proto_addr
145 assert proto in ['tcp','pgm','epgm','ipc','inproc'], "Invalid protocol: %r"%proto
145 assert proto in ['tcp','pgm','epgm','ipc','inproc'], "Invalid protocol: %r"%proto
146
146
147 # domain pattern adapted from http://www.regexlib.com/REDetails.aspx?regexp_id=391
147 # domain pattern adapted from http://www.regexlib.com/REDetails.aspx?regexp_id=391
148 # author: Remi Sabourin
148 # author: Remi Sabourin
149 pat = re.compile(r'^([\w\d]([\w\d\-]{0,61}[\w\d])?\.)*[\w\d]([\w\d\-]{0,61}[\w\d])?$')
149 pat = re.compile(r'^([\w\d]([\w\d\-]{0,61}[\w\d])?\.)*[\w\d]([\w\d\-]{0,61}[\w\d])?$')
150
150
151 if proto == 'tcp':
151 if proto == 'tcp':
152 lis = addr.split(':')
152 lis = addr.split(':')
153 assert len(lis) == 2, 'Invalid url: %r'%url
153 assert len(lis) == 2, 'Invalid url: %r'%url
154 addr,s_port = lis
154 addr,s_port = lis
155 try:
155 try:
156 port = int(s_port)
156 port = int(s_port)
157 except ValueError:
157 except ValueError:
158 raise AssertionError("Invalid port %r in url: %r"%(port, url))
158 raise AssertionError("Invalid port %r in url: %r"%(port, url))
159
159
160 assert addr == '*' or pat.match(addr) is not None, 'Invalid url: %r'%url
160 assert addr == '*' or pat.match(addr) is not None, 'Invalid url: %r'%url
161
161
162 else:
162 else:
163 # only validate tcp urls currently
163 # only validate tcp urls currently
164 pass
164 pass
165
165
166 return True
166 return True
167
167
168
168
169 def validate_url_container(container):
169 def validate_url_container(container):
170 """validate a potentially nested collection of urls."""
170 """validate a potentially nested collection of urls."""
171 if isinstance(container, basestring):
171 if isinstance(container, basestring):
172 url = container
172 url = container
173 return validate_url(url)
173 return validate_url(url)
174 elif isinstance(container, dict):
174 elif isinstance(container, dict):
175 container = container.itervalues()
175 container = container.itervalues()
176
176
177 for element in container:
177 for element in container:
178 validate_url_container(element)
178 validate_url_container(element)
179
179
180
180
181 def split_url(url):
181 def split_url(url):
182 """split a zmq url (tcp://ip:port) into ('tcp','ip','port')."""
182 """split a zmq url (tcp://ip:port) into ('tcp','ip','port')."""
183 proto_addr = url.split('://')
183 proto_addr = url.split('://')
184 assert len(proto_addr) == 2, 'Invalid url: %r'%url
184 assert len(proto_addr) == 2, 'Invalid url: %r'%url
185 proto, addr = proto_addr
185 proto, addr = proto_addr
186 lis = addr.split(':')
186 lis = addr.split(':')
187 assert len(lis) == 2, 'Invalid url: %r'%url
187 assert len(lis) == 2, 'Invalid url: %r'%url
188 addr,s_port = lis
188 addr,s_port = lis
189 return proto,addr,s_port
189 return proto,addr,s_port
190
190
191 def disambiguate_ip_address(ip, location=None):
191 def disambiguate_ip_address(ip, location=None):
192 """turn multi-ip interfaces '0.0.0.0' and '*' into connectable
192 """turn multi-ip interfaces '0.0.0.0' and '*' into connectable
193 ones, based on the location (default interpretation of location is localhost)."""
193 ones, based on the location (default interpretation of location is localhost)."""
194 if ip in ('0.0.0.0', '*'):
194 if ip in ('0.0.0.0', '*'):
195 try:
195 try:
196 external_ips = socket.gethostbyname_ex(socket.gethostname())[2]
196 external_ips = socket.gethostbyname_ex(socket.gethostname())[2]
197 except (socket.gaierror, IndexError):
197 except (socket.gaierror, IndexError):
198 # couldn't identify this machine, assume localhost
198 # couldn't identify this machine, assume localhost
199 external_ips = []
199 external_ips = []
200 if location is None or location in external_ips or not external_ips:
200 if location is None or location in external_ips or not external_ips:
201 # If location is unspecified or cannot be determined, assume local
201 # If location is unspecified or cannot be determined, assume local
202 ip='127.0.0.1'
202 ip='127.0.0.1'
203 elif location:
203 elif location:
204 return location
204 return location
205 return ip
205 return ip
206
206
207 def disambiguate_url(url, location=None):
207 def disambiguate_url(url, location=None):
208 """turn multi-ip interfaces '0.0.0.0' and '*' into connectable
208 """turn multi-ip interfaces '0.0.0.0' and '*' into connectable
209 ones, based on the location (default interpretation is localhost).
209 ones, based on the location (default interpretation is localhost).
210
210
211 This is for zeromq urls, such as tcp://*:10101."""
211 This is for zeromq urls, such as tcp://*:10101."""
212 try:
212 try:
213 proto,ip,port = split_url(url)
213 proto,ip,port = split_url(url)
214 except AssertionError:
214 except AssertionError:
215 # probably not tcp url; could be ipc, etc.
215 # probably not tcp url; could be ipc, etc.
216 return url
216 return url
217
217
218 ip = disambiguate_ip_address(ip,location)
218 ip = disambiguate_ip_address(ip,location)
219
219
220 return "%s://%s:%s"%(proto,ip,port)
220 return "%s://%s:%s"%(proto,ip,port)
221
221
222
222
223 #--------------------------------------------------------------------------
223 #--------------------------------------------------------------------------
224 # helpers for implementing old MEC API via view.apply
224 # helpers for implementing old MEC API via view.apply
225 #--------------------------------------------------------------------------
225 #--------------------------------------------------------------------------
226
226
227 def interactive(f):
227 def interactive(f):
228 """decorator for making functions appear as interactively defined.
228 """decorator for making functions appear as interactively defined.
229 This results in the function being linked to the user_ns as globals()
229 This results in the function being linked to the user_ns as globals()
230 instead of the module globals().
230 instead of the module globals().
231 """
231 """
232 f.__module__ = '__main__'
232 f.__module__ = '__main__'
233 return f
233 return f
234
234
235 @interactive
235 @interactive
236 def _push(**ns):
236 def _push(**ns):
237 """helper method for implementing `client.push` via `client.apply`"""
237 """helper method for implementing `client.push` via `client.apply`"""
238 globals().update(ns)
238 globals().update(ns)
239
239
240 @interactive
240 @interactive
241 def _pull(keys):
241 def _pull(keys):
242 """helper method for implementing `client.pull` via `client.apply`"""
242 """helper method for implementing `client.pull` via `client.apply`"""
243 user_ns = globals()
243 user_ns = globals()
244 if isinstance(keys, (list,tuple, set)):
244 if isinstance(keys, (list,tuple, set)):
245 for key in keys:
245 for key in keys:
246 if not user_ns.has_key(key):
246 if key not in user_ns:
247 raise NameError("name '%s' is not defined"%key)
247 raise NameError("name '%s' is not defined"%key)
248 return map(user_ns.get, keys)
248 return map(user_ns.get, keys)
249 else:
249 else:
250 if not user_ns.has_key(keys):
250 if keys not in user_ns:
251 raise NameError("name '%s' is not defined"%keys)
251 raise NameError("name '%s' is not defined"%keys)
252 return user_ns.get(keys)
252 return user_ns.get(keys)
253
253
254 @interactive
254 @interactive
255 def _execute(code):
255 def _execute(code):
256 """helper method for implementing `client.execute` via `client.apply`"""
256 """helper method for implementing `client.execute` via `client.apply`"""
257 exec code in globals()
257 exec code in globals()
258
258
259 #--------------------------------------------------------------------------
259 #--------------------------------------------------------------------------
260 # extra process management utilities
260 # extra process management utilities
261 #--------------------------------------------------------------------------
261 #--------------------------------------------------------------------------
262
262
263 _random_ports = set()
263 _random_ports = set()
264
264
265 def select_random_ports(n):
265 def select_random_ports(n):
266 """Selects and return n random ports that are available."""
266 """Selects and return n random ports that are available."""
267 ports = []
267 ports = []
268 for i in xrange(n):
268 for i in xrange(n):
269 sock = socket.socket()
269 sock = socket.socket()
270 sock.bind(('', 0))
270 sock.bind(('', 0))
271 while sock.getsockname()[1] in _random_ports:
271 while sock.getsockname()[1] in _random_ports:
272 sock.close()
272 sock.close()
273 sock = socket.socket()
273 sock = socket.socket()
274 sock.bind(('', 0))
274 sock.bind(('', 0))
275 ports.append(sock)
275 ports.append(sock)
276 for i, sock in enumerate(ports):
276 for i, sock in enumerate(ports):
277 port = sock.getsockname()[1]
277 port = sock.getsockname()[1]
278 sock.close()
278 sock.close()
279 ports[i] = port
279 ports[i] = port
280 _random_ports.add(port)
280 _random_ports.add(port)
281 return ports
281 return ports
282
282
283 def signal_children(children):
283 def signal_children(children):
284 """Relay interupt/term signals to children, for more solid process cleanup."""
284 """Relay interupt/term signals to children, for more solid process cleanup."""
285 def terminate_children(sig, frame):
285 def terminate_children(sig, frame):
286 log = Application.instance().log
286 log = Application.instance().log
287 log.critical("Got signal %i, terminating children..."%sig)
287 log.critical("Got signal %i, terminating children..."%sig)
288 for child in children:
288 for child in children:
289 child.terminate()
289 child.terminate()
290
290
291 sys.exit(sig != SIGINT)
291 sys.exit(sig != SIGINT)
292 # sys.exit(sig)
292 # sys.exit(sig)
293 for sig in (SIGINT, SIGABRT, SIGTERM):
293 for sig in (SIGINT, SIGABRT, SIGTERM):
294 signal(sig, terminate_children)
294 signal(sig, terminate_children)
295
295
296 def generate_exec_key(keyfile):
296 def generate_exec_key(keyfile):
297 import uuid
297 import uuid
298 newkey = str(uuid.uuid4())
298 newkey = str(uuid.uuid4())
299 with open(keyfile, 'w') as f:
299 with open(keyfile, 'w') as f:
300 # f.write('ipython-key ')
300 # f.write('ipython-key ')
301 f.write(newkey+'\n')
301 f.write(newkey+'\n')
302 # set user-only RW permissions (0600)
302 # set user-only RW permissions (0600)
303 # this will have no effect on Windows
303 # this will have no effect on Windows
304 os.chmod(keyfile, stat.S_IRUSR|stat.S_IWUSR)
304 os.chmod(keyfile, stat.S_IRUSR|stat.S_IWUSR)
305
305
306
306
307 def integer_loglevel(loglevel):
307 def integer_loglevel(loglevel):
308 try:
308 try:
309 loglevel = int(loglevel)
309 loglevel = int(loglevel)
310 except ValueError:
310 except ValueError:
311 if isinstance(loglevel, str):
311 if isinstance(loglevel, str):
312 loglevel = getattr(logging, loglevel)
312 loglevel = getattr(logging, loglevel)
313 return loglevel
313 return loglevel
314
314
315 def connect_logger(logname, context, iface, root="ip", loglevel=logging.DEBUG):
315 def connect_logger(logname, context, iface, root="ip", loglevel=logging.DEBUG):
316 logger = logging.getLogger(logname)
316 logger = logging.getLogger(logname)
317 if any([isinstance(h, handlers.PUBHandler) for h in logger.handlers]):
317 if any([isinstance(h, handlers.PUBHandler) for h in logger.handlers]):
318 # don't add a second PUBHandler
318 # don't add a second PUBHandler
319 return
319 return
320 loglevel = integer_loglevel(loglevel)
320 loglevel = integer_loglevel(loglevel)
321 lsock = context.socket(zmq.PUB)
321 lsock = context.socket(zmq.PUB)
322 lsock.connect(iface)
322 lsock.connect(iface)
323 handler = handlers.PUBHandler(lsock)
323 handler = handlers.PUBHandler(lsock)
324 handler.setLevel(loglevel)
324 handler.setLevel(loglevel)
325 handler.root_topic = root
325 handler.root_topic = root
326 logger.addHandler(handler)
326 logger.addHandler(handler)
327 logger.setLevel(loglevel)
327 logger.setLevel(loglevel)
328
328
329 def connect_engine_logger(context, iface, engine, loglevel=logging.DEBUG):
329 def connect_engine_logger(context, iface, engine, loglevel=logging.DEBUG):
330 logger = logging.getLogger()
330 logger = logging.getLogger()
331 if any([isinstance(h, handlers.PUBHandler) for h in logger.handlers]):
331 if any([isinstance(h, handlers.PUBHandler) for h in logger.handlers]):
332 # don't add a second PUBHandler
332 # don't add a second PUBHandler
333 return
333 return
334 loglevel = integer_loglevel(loglevel)
334 loglevel = integer_loglevel(loglevel)
335 lsock = context.socket(zmq.PUB)
335 lsock = context.socket(zmq.PUB)
336 lsock.connect(iface)
336 lsock.connect(iface)
337 handler = EnginePUBHandler(engine, lsock)
337 handler = EnginePUBHandler(engine, lsock)
338 handler.setLevel(loglevel)
338 handler.setLevel(loglevel)
339 logger.addHandler(handler)
339 logger.addHandler(handler)
340 logger.setLevel(loglevel)
340 logger.setLevel(loglevel)
341 return logger
341 return logger
342
342
343 def local_logger(logname, loglevel=logging.DEBUG):
343 def local_logger(logname, loglevel=logging.DEBUG):
344 loglevel = integer_loglevel(loglevel)
344 loglevel = integer_loglevel(loglevel)
345 logger = logging.getLogger(logname)
345 logger = logging.getLogger(logname)
346 if any([isinstance(h, logging.StreamHandler) for h in logger.handlers]):
346 if any([isinstance(h, logging.StreamHandler) for h in logger.handlers]):
347 # don't add a second StreamHandler
347 # don't add a second StreamHandler
348 return
348 return
349 handler = logging.StreamHandler()
349 handler = logging.StreamHandler()
350 handler.setLevel(loglevel)
350 handler.setLevel(loglevel)
351 formatter = logging.Formatter("%(asctime)s.%(msecs).03d [%(name)s] %(message)s",
351 formatter = logging.Formatter("%(asctime)s.%(msecs).03d [%(name)s] %(message)s",
352 datefmt="%Y-%m-%d %H:%M:%S")
352 datefmt="%Y-%m-%d %H:%M:%S")
353 handler.setFormatter(formatter)
353 handler.setFormatter(formatter)
354
354
355 logger.addHandler(handler)
355 logger.addHandler(handler)
356 logger.setLevel(loglevel)
356 logger.setLevel(loglevel)
357 return logger
357 return logger
358
358
@@ -1,393 +1,393 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """A dict subclass that supports attribute style access.
2 """A dict subclass that supports attribute style access.
3
3
4 Authors:
4 Authors:
5
5
6 * Fernando Perez (original)
6 * Fernando Perez (original)
7 * Brian Granger (refactoring to a dict subclass)
7 * Brian Granger (refactoring to a dict subclass)
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2011 The IPython Development Team
11 # Copyright (C) 2008-2011 The IPython Development Team
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Imports
18 # Imports
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 from IPython.utils.data import list2dict2
21 from IPython.utils.data import list2dict2
22
22
23 __all__ = ['Struct']
23 __all__ = ['Struct']
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Code
26 # Code
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28
28
29
29
30 class Struct(dict):
30 class Struct(dict):
31 """A dict subclass with attribute style access.
31 """A dict subclass with attribute style access.
32
32
33 This dict subclass has a a few extra features:
33 This dict subclass has a a few extra features:
34
34
35 * Attribute style access.
35 * Attribute style access.
36 * Protection of class members (like keys, items) when using attribute
36 * Protection of class members (like keys, items) when using attribute
37 style access.
37 style access.
38 * The ability to restrict assignment to only existing keys.
38 * The ability to restrict assignment to only existing keys.
39 * Intelligent merging.
39 * Intelligent merging.
40 * Overloaded operators.
40 * Overloaded operators.
41 """
41 """
42 _allownew = True
42 _allownew = True
43 def __init__(self, *args, **kw):
43 def __init__(self, *args, **kw):
44 """Initialize with a dictionary, another Struct, or data.
44 """Initialize with a dictionary, another Struct, or data.
45
45
46 Parameters
46 Parameters
47 ----------
47 ----------
48 args : dict, Struct
48 args : dict, Struct
49 Initialize with one dict or Struct
49 Initialize with one dict or Struct
50 kw : dict
50 kw : dict
51 Initialize with key, value pairs.
51 Initialize with key, value pairs.
52
52
53 Examples
53 Examples
54 --------
54 --------
55
55
56 >>> s = Struct(a=10,b=30)
56 >>> s = Struct(a=10,b=30)
57 >>> s.a
57 >>> s.a
58 10
58 10
59 >>> s.b
59 >>> s.b
60 30
60 30
61 >>> s2 = Struct(s,c=30)
61 >>> s2 = Struct(s,c=30)
62 >>> sorted(s2.keys())
62 >>> sorted(s2.keys())
63 ['a', 'b', 'c']
63 ['a', 'b', 'c']
64 """
64 """
65 object.__setattr__(self, '_allownew', True)
65 object.__setattr__(self, '_allownew', True)
66 dict.__init__(self, *args, **kw)
66 dict.__init__(self, *args, **kw)
67
67
68 def __setitem__(self, key, value):
68 def __setitem__(self, key, value):
69 """Set an item with check for allownew.
69 """Set an item with check for allownew.
70
70
71 Examples
71 Examples
72 --------
72 --------
73
73
74 >>> s = Struct()
74 >>> s = Struct()
75 >>> s['a'] = 10
75 >>> s['a'] = 10
76 >>> s.allow_new_attr(False)
76 >>> s.allow_new_attr(False)
77 >>> s['a'] = 10
77 >>> s['a'] = 10
78 >>> s['a']
78 >>> s['a']
79 10
79 10
80 >>> try:
80 >>> try:
81 ... s['b'] = 20
81 ... s['b'] = 20
82 ... except KeyError:
82 ... except KeyError:
83 ... print 'this is not allowed'
83 ... print 'this is not allowed'
84 ...
84 ...
85 this is not allowed
85 this is not allowed
86 """
86 """
87 if not self._allownew and not self.has_key(key):
87 if not self._allownew and key not in self:
88 raise KeyError(
88 raise KeyError(
89 "can't create new attribute %s when allow_new_attr(False)" % key)
89 "can't create new attribute %s when allow_new_attr(False)" % key)
90 dict.__setitem__(self, key, value)
90 dict.__setitem__(self, key, value)
91
91
92 def __setattr__(self, key, value):
92 def __setattr__(self, key, value):
93 """Set an attr with protection of class members.
93 """Set an attr with protection of class members.
94
94
95 This calls :meth:`self.__setitem__` but convert :exc:`KeyError` to
95 This calls :meth:`self.__setitem__` but convert :exc:`KeyError` to
96 :exc:`AttributeError`.
96 :exc:`AttributeError`.
97
97
98 Examples
98 Examples
99 --------
99 --------
100
100
101 >>> s = Struct()
101 >>> s = Struct()
102 >>> s.a = 10
102 >>> s.a = 10
103 >>> s.a
103 >>> s.a
104 10
104 10
105 >>> try:
105 >>> try:
106 ... s.get = 10
106 ... s.get = 10
107 ... except AttributeError:
107 ... except AttributeError:
108 ... print "you can't set a class member"
108 ... print "you can't set a class member"
109 ...
109 ...
110 you can't set a class member
110 you can't set a class member
111 """
111 """
112 # If key is an str it might be a class member or instance var
112 # If key is an str it might be a class member or instance var
113 if isinstance(key, str):
113 if isinstance(key, str):
114 # I can't simply call hasattr here because it calls getattr, which
114 # I can't simply call hasattr here because it calls getattr, which
115 # calls self.__getattr__, which returns True for keys in
115 # calls self.__getattr__, which returns True for keys in
116 # self._data. But I only want keys in the class and in
116 # self._data. But I only want keys in the class and in
117 # self.__dict__
117 # self.__dict__
118 if key in self.__dict__ or hasattr(Struct, key):
118 if key in self.__dict__ or hasattr(Struct, key):
119 raise AttributeError(
119 raise AttributeError(
120 'attr %s is a protected member of class Struct.' % key
120 'attr %s is a protected member of class Struct.' % key
121 )
121 )
122 try:
122 try:
123 self.__setitem__(key, value)
123 self.__setitem__(key, value)
124 except KeyError as e:
124 except KeyError as e:
125 raise AttributeError(e)
125 raise AttributeError(e)
126
126
127 def __getattr__(self, key):
127 def __getattr__(self, key):
128 """Get an attr by calling :meth:`dict.__getitem__`.
128 """Get an attr by calling :meth:`dict.__getitem__`.
129
129
130 Like :meth:`__setattr__`, this method converts :exc:`KeyError` to
130 Like :meth:`__setattr__`, this method converts :exc:`KeyError` to
131 :exc:`AttributeError`.
131 :exc:`AttributeError`.
132
132
133 Examples
133 Examples
134 --------
134 --------
135
135
136 >>> s = Struct(a=10)
136 >>> s = Struct(a=10)
137 >>> s.a
137 >>> s.a
138 10
138 10
139 >>> type(s.get)
139 >>> type(s.get)
140 <... 'builtin_function_or_method'>
140 <... 'builtin_function_or_method'>
141 >>> try:
141 >>> try:
142 ... s.b
142 ... s.b
143 ... except AttributeError:
143 ... except AttributeError:
144 ... print "I don't have that key"
144 ... print "I don't have that key"
145 ...
145 ...
146 I don't have that key
146 I don't have that key
147 """
147 """
148 try:
148 try:
149 result = self[key]
149 result = self[key]
150 except KeyError:
150 except KeyError:
151 raise AttributeError(key)
151 raise AttributeError(key)
152 else:
152 else:
153 return result
153 return result
154
154
155 def __iadd__(self, other):
155 def __iadd__(self, other):
156 """s += s2 is a shorthand for s.merge(s2).
156 """s += s2 is a shorthand for s.merge(s2).
157
157
158 Examples
158 Examples
159 --------
159 --------
160
160
161 >>> s = Struct(a=10,b=30)
161 >>> s = Struct(a=10,b=30)
162 >>> s2 = Struct(a=20,c=40)
162 >>> s2 = Struct(a=20,c=40)
163 >>> s += s2
163 >>> s += s2
164 >>> sorted(s.keys())
164 >>> sorted(s.keys())
165 ['a', 'b', 'c']
165 ['a', 'b', 'c']
166 """
166 """
167 self.merge(other)
167 self.merge(other)
168 return self
168 return self
169
169
170 def __add__(self,other):
170 def __add__(self,other):
171 """s + s2 -> New Struct made from s.merge(s2).
171 """s + s2 -> New Struct made from s.merge(s2).
172
172
173 Examples
173 Examples
174 --------
174 --------
175
175
176 >>> s1 = Struct(a=10,b=30)
176 >>> s1 = Struct(a=10,b=30)
177 >>> s2 = Struct(a=20,c=40)
177 >>> s2 = Struct(a=20,c=40)
178 >>> s = s1 + s2
178 >>> s = s1 + s2
179 >>> sorted(s.keys())
179 >>> sorted(s.keys())
180 ['a', 'b', 'c']
180 ['a', 'b', 'c']
181 """
181 """
182 sout = self.copy()
182 sout = self.copy()
183 sout.merge(other)
183 sout.merge(other)
184 return sout
184 return sout
185
185
186 def __sub__(self,other):
186 def __sub__(self,other):
187 """s1 - s2 -> remove keys in s2 from s1.
187 """s1 - s2 -> remove keys in s2 from s1.
188
188
189 Examples
189 Examples
190 --------
190 --------
191
191
192 >>> s1 = Struct(a=10,b=30)
192 >>> s1 = Struct(a=10,b=30)
193 >>> s2 = Struct(a=40)
193 >>> s2 = Struct(a=40)
194 >>> s = s1 - s2
194 >>> s = s1 - s2
195 >>> s
195 >>> s
196 {'b': 30}
196 {'b': 30}
197 """
197 """
198 sout = self.copy()
198 sout = self.copy()
199 sout -= other
199 sout -= other
200 return sout
200 return sout
201
201
202 def __isub__(self,other):
202 def __isub__(self,other):
203 """Inplace remove keys from self that are in other.
203 """Inplace remove keys from self that are in other.
204
204
205 Examples
205 Examples
206 --------
206 --------
207
207
208 >>> s1 = Struct(a=10,b=30)
208 >>> s1 = Struct(a=10,b=30)
209 >>> s2 = Struct(a=40)
209 >>> s2 = Struct(a=40)
210 >>> s1 -= s2
210 >>> s1 -= s2
211 >>> s1
211 >>> s1
212 {'b': 30}
212 {'b': 30}
213 """
213 """
214 for k in other.keys():
214 for k in other.keys():
215 if self.has_key(k):
215 if k in self:
216 del self[k]
216 del self[k]
217 return self
217 return self
218
218
219 def __dict_invert(self, data):
219 def __dict_invert(self, data):
220 """Helper function for merge.
220 """Helper function for merge.
221
221
222 Takes a dictionary whose values are lists and returns a dict with
222 Takes a dictionary whose values are lists and returns a dict with
223 the elements of each list as keys and the original keys as values.
223 the elements of each list as keys and the original keys as values.
224 """
224 """
225 outdict = {}
225 outdict = {}
226 for k,lst in data.items():
226 for k,lst in data.items():
227 if isinstance(lst, str):
227 if isinstance(lst, str):
228 lst = lst.split()
228 lst = lst.split()
229 for entry in lst:
229 for entry in lst:
230 outdict[entry] = k
230 outdict[entry] = k
231 return outdict
231 return outdict
232
232
233 def dict(self):
233 def dict(self):
234 return self
234 return self
235
235
236 def copy(self):
236 def copy(self):
237 """Return a copy as a Struct.
237 """Return a copy as a Struct.
238
238
239 Examples
239 Examples
240 --------
240 --------
241
241
242 >>> s = Struct(a=10,b=30)
242 >>> s = Struct(a=10,b=30)
243 >>> s2 = s.copy()
243 >>> s2 = s.copy()
244 >>> type(s2) is Struct
244 >>> type(s2) is Struct
245 True
245 True
246 """
246 """
247 return Struct(dict.copy(self))
247 return Struct(dict.copy(self))
248
248
249 def hasattr(self, key):
249 def hasattr(self, key):
250 """hasattr function available as a method.
250 """hasattr function available as a method.
251
251
252 Implemented like has_key.
252 Implemented like has_key.
253
253
254 Examples
254 Examples
255 --------
255 --------
256
256
257 >>> s = Struct(a=10)
257 >>> s = Struct(a=10)
258 >>> s.hasattr('a')
258 >>> s.hasattr('a')
259 True
259 True
260 >>> s.hasattr('b')
260 >>> s.hasattr('b')
261 False
261 False
262 >>> s.hasattr('get')
262 >>> s.hasattr('get')
263 False
263 False
264 """
264 """
265 return self.has_key(key)
265 return key in self
266
266
267 def allow_new_attr(self, allow = True):
267 def allow_new_attr(self, allow = True):
268 """Set whether new attributes can be created in this Struct.
268 """Set whether new attributes can be created in this Struct.
269
269
270 This can be used to catch typos by verifying that the attribute user
270 This can be used to catch typos by verifying that the attribute user
271 tries to change already exists in this Struct.
271 tries to change already exists in this Struct.
272 """
272 """
273 object.__setattr__(self, '_allownew', allow)
273 object.__setattr__(self, '_allownew', allow)
274
274
275 def merge(self, __loc_data__=None, __conflict_solve=None, **kw):
275 def merge(self, __loc_data__=None, __conflict_solve=None, **kw):
276 """Merge two Structs with customizable conflict resolution.
276 """Merge two Structs with customizable conflict resolution.
277
277
278 This is similar to :meth:`update`, but much more flexible. First, a
278 This is similar to :meth:`update`, but much more flexible. First, a
279 dict is made from data+key=value pairs. When merging this dict with
279 dict is made from data+key=value pairs. When merging this dict with
280 the Struct S, the optional dictionary 'conflict' is used to decide
280 the Struct S, the optional dictionary 'conflict' is used to decide
281 what to do.
281 what to do.
282
282
283 If conflict is not given, the default behavior is to preserve any keys
283 If conflict is not given, the default behavior is to preserve any keys
284 with their current value (the opposite of the :meth:`update` method's
284 with their current value (the opposite of the :meth:`update` method's
285 behavior).
285 behavior).
286
286
287 Parameters
287 Parameters
288 ----------
288 ----------
289 __loc_data : dict, Struct
289 __loc_data : dict, Struct
290 The data to merge into self
290 The data to merge into self
291 __conflict_solve : dict
291 __conflict_solve : dict
292 The conflict policy dict. The keys are binary functions used to
292 The conflict policy dict. The keys are binary functions used to
293 resolve the conflict and the values are lists of strings naming
293 resolve the conflict and the values are lists of strings naming
294 the keys the conflict resolution function applies to. Instead of
294 the keys the conflict resolution function applies to. Instead of
295 a list of strings a space separated string can be used, like
295 a list of strings a space separated string can be used, like
296 'a b c'.
296 'a b c'.
297 kw : dict
297 kw : dict
298 Additional key, value pairs to merge in
298 Additional key, value pairs to merge in
299
299
300 Notes
300 Notes
301 -----
301 -----
302
302
303 The `__conflict_solve` dict is a dictionary of binary functions which will be used to
303 The `__conflict_solve` dict is a dictionary of binary functions which will be used to
304 solve key conflicts. Here is an example::
304 solve key conflicts. Here is an example::
305
305
306 __conflict_solve = dict(
306 __conflict_solve = dict(
307 func1=['a','b','c'],
307 func1=['a','b','c'],
308 func2=['d','e']
308 func2=['d','e']
309 )
309 )
310
310
311 In this case, the function :func:`func1` will be used to resolve
311 In this case, the function :func:`func1` will be used to resolve
312 keys 'a', 'b' and 'c' and the function :func:`func2` will be used for
312 keys 'a', 'b' and 'c' and the function :func:`func2` will be used for
313 keys 'd' and 'e'. This could also be written as::
313 keys 'd' and 'e'. This could also be written as::
314
314
315 __conflict_solve = dict(func1='a b c',func2='d e')
315 __conflict_solve = dict(func1='a b c',func2='d e')
316
316
317 These functions will be called for each key they apply to with the
317 These functions will be called for each key they apply to with the
318 form::
318 form::
319
319
320 func1(self['a'], other['a'])
320 func1(self['a'], other['a'])
321
321
322 The return value is used as the final merged value.
322 The return value is used as the final merged value.
323
323
324 As a convenience, merge() provides five (the most commonly needed)
324 As a convenience, merge() provides five (the most commonly needed)
325 pre-defined policies: preserve, update, add, add_flip and add_s. The
325 pre-defined policies: preserve, update, add, add_flip and add_s. The
326 easiest explanation is their implementation::
326 easiest explanation is their implementation::
327
327
328 preserve = lambda old,new: old
328 preserve = lambda old,new: old
329 update = lambda old,new: new
329 update = lambda old,new: new
330 add = lambda old,new: old + new
330 add = lambda old,new: old + new
331 add_flip = lambda old,new: new + old # note change of order!
331 add_flip = lambda old,new: new + old # note change of order!
332 add_s = lambda old,new: old + ' ' + new # only for str!
332 add_s = lambda old,new: old + ' ' + new # only for str!
333
333
334 You can use those four words (as strings) as keys instead
334 You can use those four words (as strings) as keys instead
335 of defining them as functions, and the merge method will substitute
335 of defining them as functions, and the merge method will substitute
336 the appropriate functions for you.
336 the appropriate functions for you.
337
337
338 For more complicated conflict resolution policies, you still need to
338 For more complicated conflict resolution policies, you still need to
339 construct your own functions.
339 construct your own functions.
340
340
341 Examples
341 Examples
342 --------
342 --------
343
343
344 This show the default policy:
344 This show the default policy:
345
345
346 >>> s = Struct(a=10,b=30)
346 >>> s = Struct(a=10,b=30)
347 >>> s2 = Struct(a=20,c=40)
347 >>> s2 = Struct(a=20,c=40)
348 >>> s.merge(s2)
348 >>> s.merge(s2)
349 >>> sorted(s.items())
349 >>> sorted(s.items())
350 [('a', 10), ('b', 30), ('c', 40)]
350 [('a', 10), ('b', 30), ('c', 40)]
351
351
352 Now, show how to specify a conflict dict:
352 Now, show how to specify a conflict dict:
353
353
354 >>> s = Struct(a=10,b=30)
354 >>> s = Struct(a=10,b=30)
355 >>> s2 = Struct(a=20,b=40)
355 >>> s2 = Struct(a=20,b=40)
356 >>> conflict = {'update':'a','add':'b'}
356 >>> conflict = {'update':'a','add':'b'}
357 >>> s.merge(s2,conflict)
357 >>> s.merge(s2,conflict)
358 >>> sorted(s.items())
358 >>> sorted(s.items())
359 [('a', 20), ('b', 70)]
359 [('a', 20), ('b', 70)]
360 """
360 """
361
361
362 data_dict = dict(__loc_data__,**kw)
362 data_dict = dict(__loc_data__,**kw)
363
363
364 # policies for conflict resolution: two argument functions which return
364 # policies for conflict resolution: two argument functions which return
365 # the value that will go in the new struct
365 # the value that will go in the new struct
366 preserve = lambda old,new: old
366 preserve = lambda old,new: old
367 update = lambda old,new: new
367 update = lambda old,new: new
368 add = lambda old,new: old + new
368 add = lambda old,new: old + new
369 add_flip = lambda old,new: new + old # note change of order!
369 add_flip = lambda old,new: new + old # note change of order!
370 add_s = lambda old,new: old + ' ' + new
370 add_s = lambda old,new: old + ' ' + new
371
371
372 # default policy is to keep current keys when there's a conflict
372 # default policy is to keep current keys when there's a conflict
373 conflict_solve = list2dict2(self.keys(), default = preserve)
373 conflict_solve = list2dict2(self.keys(), default = preserve)
374
374
375 # the conflict_solve dictionary is given by the user 'inverted': we
375 # the conflict_solve dictionary is given by the user 'inverted': we
376 # need a name-function mapping, it comes as a function -> names
376 # need a name-function mapping, it comes as a function -> names
377 # dict. Make a local copy (b/c we'll make changes), replace user
377 # dict. Make a local copy (b/c we'll make changes), replace user
378 # strings for the three builtin policies and invert it.
378 # strings for the three builtin policies and invert it.
379 if __conflict_solve:
379 if __conflict_solve:
380 inv_conflict_solve_user = __conflict_solve.copy()
380 inv_conflict_solve_user = __conflict_solve.copy()
381 for name, func in [('preserve',preserve), ('update',update),
381 for name, func in [('preserve',preserve), ('update',update),
382 ('add',add), ('add_flip',add_flip),
382 ('add',add), ('add_flip',add_flip),
383 ('add_s',add_s)]:
383 ('add_s',add_s)]:
384 if name in inv_conflict_solve_user.keys():
384 if name in inv_conflict_solve_user.keys():
385 inv_conflict_solve_user[func] = inv_conflict_solve_user[name]
385 inv_conflict_solve_user[func] = inv_conflict_solve_user[name]
386 del inv_conflict_solve_user[name]
386 del inv_conflict_solve_user[name]
387 conflict_solve.update(self.__dict_invert(inv_conflict_solve_user))
387 conflict_solve.update(self.__dict_invert(inv_conflict_solve_user))
388 for key in data_dict:
388 for key in data_dict:
389 if key not in self:
389 if key not in self:
390 self[key] = data_dict[key]
390 self[key] = data_dict[key]
391 else:
391 else:
392 self[key] = conflict_solve[key](self[key],data_dict[key])
392 self[key] = conflict_solve[key](self[key],data_dict[key])
393
393
@@ -1,1427 +1,1427 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A lightweight Traits like module.
3 A lightweight Traits like module.
4
4
5 This is designed to provide a lightweight, simple, pure Python version of
5 This is designed to provide a lightweight, simple, pure Python version of
6 many of the capabilities of enthought.traits. This includes:
6 many of the capabilities of enthought.traits. This includes:
7
7
8 * Validation
8 * Validation
9 * Type specification with defaults
9 * Type specification with defaults
10 * Static and dynamic notification
10 * Static and dynamic notification
11 * Basic predefined types
11 * Basic predefined types
12 * An API that is similar to enthought.traits
12 * An API that is similar to enthought.traits
13
13
14 We don't support:
14 We don't support:
15
15
16 * Delegation
16 * Delegation
17 * Automatic GUI generation
17 * Automatic GUI generation
18 * A full set of trait types. Most importantly, we don't provide container
18 * A full set of trait types. Most importantly, we don't provide container
19 traits (list, dict, tuple) that can trigger notifications if their
19 traits (list, dict, tuple) that can trigger notifications if their
20 contents change.
20 contents change.
21 * API compatibility with enthought.traits
21 * API compatibility with enthought.traits
22
22
23 There are also some important difference in our design:
23 There are also some important difference in our design:
24
24
25 * enthought.traits does not validate default values. We do.
25 * enthought.traits does not validate default values. We do.
26
26
27 We choose to create this module because we need these capabilities, but
27 We choose to create this module because we need these capabilities, but
28 we need them to be pure Python so they work in all Python implementations,
28 we need them to be pure Python so they work in all Python implementations,
29 including Jython and IronPython.
29 including Jython and IronPython.
30
30
31 Authors:
31 Authors:
32
32
33 * Brian Granger
33 * Brian Granger
34 * Enthought, Inc. Some of the code in this file comes from enthought.traits
34 * Enthought, Inc. Some of the code in this file comes from enthought.traits
35 and is licensed under the BSD license. Also, many of the ideas also come
35 and is licensed under the BSD license. Also, many of the ideas also come
36 from enthought.traits even though our implementation is very different.
36 from enthought.traits even though our implementation is very different.
37 """
37 """
38
38
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40 # Copyright (C) 2008-2011 The IPython Development Team
40 # Copyright (C) 2008-2011 The IPython Development Team
41 #
41 #
42 # Distributed under the terms of the BSD License. The full license is in
42 # Distributed under the terms of the BSD License. The full license is in
43 # the file COPYING, distributed as part of this software.
43 # the file COPYING, distributed as part of this software.
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45
45
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47 # Imports
47 # Imports
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49
49
50
50
51 import inspect
51 import inspect
52 import re
52 import re
53 import sys
53 import sys
54 import types
54 import types
55 from types import FunctionType
55 from types import FunctionType
56 try:
56 try:
57 from types import ClassType, InstanceType
57 from types import ClassType, InstanceType
58 ClassTypes = (ClassType, type)
58 ClassTypes = (ClassType, type)
59 except:
59 except:
60 ClassTypes = (type,)
60 ClassTypes = (type,)
61
61
62 from .importstring import import_item
62 from .importstring import import_item
63 from IPython.utils import py3compat
63 from IPython.utils import py3compat
64
64
65 SequenceTypes = (list, tuple, set, frozenset)
65 SequenceTypes = (list, tuple, set, frozenset)
66
66
67 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
68 # Basic classes
68 # Basic classes
69 #-----------------------------------------------------------------------------
69 #-----------------------------------------------------------------------------
70
70
71
71
72 class NoDefaultSpecified ( object ): pass
72 class NoDefaultSpecified ( object ): pass
73 NoDefaultSpecified = NoDefaultSpecified()
73 NoDefaultSpecified = NoDefaultSpecified()
74
74
75
75
76 class Undefined ( object ): pass
76 class Undefined ( object ): pass
77 Undefined = Undefined()
77 Undefined = Undefined()
78
78
79 class TraitError(Exception):
79 class TraitError(Exception):
80 pass
80 pass
81
81
82 #-----------------------------------------------------------------------------
82 #-----------------------------------------------------------------------------
83 # Utilities
83 # Utilities
84 #-----------------------------------------------------------------------------
84 #-----------------------------------------------------------------------------
85
85
86
86
87 def class_of ( object ):
87 def class_of ( object ):
88 """ Returns a string containing the class name of an object with the
88 """ Returns a string containing the class name of an object with the
89 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
89 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
90 'a PlotValue').
90 'a PlotValue').
91 """
91 """
92 if isinstance( object, basestring ):
92 if isinstance( object, basestring ):
93 return add_article( object )
93 return add_article( object )
94
94
95 return add_article( object.__class__.__name__ )
95 return add_article( object.__class__.__name__ )
96
96
97
97
98 def add_article ( name ):
98 def add_article ( name ):
99 """ Returns a string containing the correct indefinite article ('a' or 'an')
99 """ Returns a string containing the correct indefinite article ('a' or 'an')
100 prefixed to the specified string.
100 prefixed to the specified string.
101 """
101 """
102 if name[:1].lower() in 'aeiou':
102 if name[:1].lower() in 'aeiou':
103 return 'an ' + name
103 return 'an ' + name
104
104
105 return 'a ' + name
105 return 'a ' + name
106
106
107
107
108 def repr_type(obj):
108 def repr_type(obj):
109 """ Return a string representation of a value and its type for readable
109 """ Return a string representation of a value and its type for readable
110 error messages.
110 error messages.
111 """
111 """
112 the_type = type(obj)
112 the_type = type(obj)
113 if (not py3compat.PY3) and the_type is InstanceType:
113 if (not py3compat.PY3) and the_type is InstanceType:
114 # Old-style class.
114 # Old-style class.
115 the_type = obj.__class__
115 the_type = obj.__class__
116 msg = '%r %r' % (obj, the_type)
116 msg = '%r %r' % (obj, the_type)
117 return msg
117 return msg
118
118
119
119
120 def parse_notifier_name(name):
120 def parse_notifier_name(name):
121 """Convert the name argument to a list of names.
121 """Convert the name argument to a list of names.
122
122
123 Examples
123 Examples
124 --------
124 --------
125
125
126 >>> parse_notifier_name('a')
126 >>> parse_notifier_name('a')
127 ['a']
127 ['a']
128 >>> parse_notifier_name(['a','b'])
128 >>> parse_notifier_name(['a','b'])
129 ['a', 'b']
129 ['a', 'b']
130 >>> parse_notifier_name(None)
130 >>> parse_notifier_name(None)
131 ['anytrait']
131 ['anytrait']
132 """
132 """
133 if isinstance(name, str):
133 if isinstance(name, str):
134 return [name]
134 return [name]
135 elif name is None:
135 elif name is None:
136 return ['anytrait']
136 return ['anytrait']
137 elif isinstance(name, (list, tuple)):
137 elif isinstance(name, (list, tuple)):
138 for n in name:
138 for n in name:
139 assert isinstance(n, str), "names must be strings"
139 assert isinstance(n, str), "names must be strings"
140 return name
140 return name
141
141
142
142
143 class _SimpleTest:
143 class _SimpleTest:
144 def __init__ ( self, value ): self.value = value
144 def __init__ ( self, value ): self.value = value
145 def __call__ ( self, test ):
145 def __call__ ( self, test ):
146 return test == self.value
146 return test == self.value
147 def __repr__(self):
147 def __repr__(self):
148 return "<SimpleTest(%r)" % self.value
148 return "<SimpleTest(%r)" % self.value
149 def __str__(self):
149 def __str__(self):
150 return self.__repr__()
150 return self.__repr__()
151
151
152
152
153 def getmembers(object, predicate=None):
153 def getmembers(object, predicate=None):
154 """A safe version of inspect.getmembers that handles missing attributes.
154 """A safe version of inspect.getmembers that handles missing attributes.
155
155
156 This is useful when there are descriptor based attributes that for
156 This is useful when there are descriptor based attributes that for
157 some reason raise AttributeError even though they exist. This happens
157 some reason raise AttributeError even though they exist. This happens
158 in zope.inteface with the __provides__ attribute.
158 in zope.inteface with the __provides__ attribute.
159 """
159 """
160 results = []
160 results = []
161 for key in dir(object):
161 for key in dir(object):
162 try:
162 try:
163 value = getattr(object, key)
163 value = getattr(object, key)
164 except AttributeError:
164 except AttributeError:
165 pass
165 pass
166 else:
166 else:
167 if not predicate or predicate(value):
167 if not predicate or predicate(value):
168 results.append((key, value))
168 results.append((key, value))
169 results.sort()
169 results.sort()
170 return results
170 return results
171
171
172
172
173 #-----------------------------------------------------------------------------
173 #-----------------------------------------------------------------------------
174 # Base TraitType for all traits
174 # Base TraitType for all traits
175 #-----------------------------------------------------------------------------
175 #-----------------------------------------------------------------------------
176
176
177
177
178 class TraitType(object):
178 class TraitType(object):
179 """A base class for all trait descriptors.
179 """A base class for all trait descriptors.
180
180
181 Notes
181 Notes
182 -----
182 -----
183 Our implementation of traits is based on Python's descriptor
183 Our implementation of traits is based on Python's descriptor
184 prototol. This class is the base class for all such descriptors. The
184 prototol. This class is the base class for all such descriptors. The
185 only magic we use is a custom metaclass for the main :class:`HasTraits`
185 only magic we use is a custom metaclass for the main :class:`HasTraits`
186 class that does the following:
186 class that does the following:
187
187
188 1. Sets the :attr:`name` attribute of every :class:`TraitType`
188 1. Sets the :attr:`name` attribute of every :class:`TraitType`
189 instance in the class dict to the name of the attribute.
189 instance in the class dict to the name of the attribute.
190 2. Sets the :attr:`this_class` attribute of every :class:`TraitType`
190 2. Sets the :attr:`this_class` attribute of every :class:`TraitType`
191 instance in the class dict to the *class* that declared the trait.
191 instance in the class dict to the *class* that declared the trait.
192 This is used by the :class:`This` trait to allow subclasses to
192 This is used by the :class:`This` trait to allow subclasses to
193 accept superclasses for :class:`This` values.
193 accept superclasses for :class:`This` values.
194 """
194 """
195
195
196
196
197 metadata = {}
197 metadata = {}
198 default_value = Undefined
198 default_value = Undefined
199 info_text = 'any value'
199 info_text = 'any value'
200
200
201 def __init__(self, default_value=NoDefaultSpecified, **metadata):
201 def __init__(self, default_value=NoDefaultSpecified, **metadata):
202 """Create a TraitType.
202 """Create a TraitType.
203 """
203 """
204 if default_value is not NoDefaultSpecified:
204 if default_value is not NoDefaultSpecified:
205 self.default_value = default_value
205 self.default_value = default_value
206
206
207 if len(metadata) > 0:
207 if len(metadata) > 0:
208 if len(self.metadata) > 0:
208 if len(self.metadata) > 0:
209 self._metadata = self.metadata.copy()
209 self._metadata = self.metadata.copy()
210 self._metadata.update(metadata)
210 self._metadata.update(metadata)
211 else:
211 else:
212 self._metadata = metadata
212 self._metadata = metadata
213 else:
213 else:
214 self._metadata = self.metadata
214 self._metadata = self.metadata
215
215
216 self.init()
216 self.init()
217
217
218 def init(self):
218 def init(self):
219 pass
219 pass
220
220
221 def get_default_value(self):
221 def get_default_value(self):
222 """Create a new instance of the default value."""
222 """Create a new instance of the default value."""
223 return self.default_value
223 return self.default_value
224
224
225 def instance_init(self, obj):
225 def instance_init(self, obj):
226 """This is called by :meth:`HasTraits.__new__` to finish init'ing.
226 """This is called by :meth:`HasTraits.__new__` to finish init'ing.
227
227
228 Some stages of initialization must be delayed until the parent
228 Some stages of initialization must be delayed until the parent
229 :class:`HasTraits` instance has been created. This method is
229 :class:`HasTraits` instance has been created. This method is
230 called in :meth:`HasTraits.__new__` after the instance has been
230 called in :meth:`HasTraits.__new__` after the instance has been
231 created.
231 created.
232
232
233 This method trigger the creation and validation of default values
233 This method trigger the creation and validation of default values
234 and also things like the resolution of str given class names in
234 and also things like the resolution of str given class names in
235 :class:`Type` and :class`Instance`.
235 :class:`Type` and :class`Instance`.
236
236
237 Parameters
237 Parameters
238 ----------
238 ----------
239 obj : :class:`HasTraits` instance
239 obj : :class:`HasTraits` instance
240 The parent :class:`HasTraits` instance that has just been
240 The parent :class:`HasTraits` instance that has just been
241 created.
241 created.
242 """
242 """
243 self.set_default_value(obj)
243 self.set_default_value(obj)
244
244
245 def set_default_value(self, obj):
245 def set_default_value(self, obj):
246 """Set the default value on a per instance basis.
246 """Set the default value on a per instance basis.
247
247
248 This method is called by :meth:`instance_init` to create and
248 This method is called by :meth:`instance_init` to create and
249 validate the default value. The creation and validation of
249 validate the default value. The creation and validation of
250 default values must be delayed until the parent :class:`HasTraits`
250 default values must be delayed until the parent :class:`HasTraits`
251 class has been instantiated.
251 class has been instantiated.
252 """
252 """
253 # Check for a deferred initializer defined in the same class as the
253 # Check for a deferred initializer defined in the same class as the
254 # trait declaration or above.
254 # trait declaration or above.
255 mro = type(obj).mro()
255 mro = type(obj).mro()
256 meth_name = '_%s_default' % self.name
256 meth_name = '_%s_default' % self.name
257 for cls in mro[:mro.index(self.this_class)+1]:
257 for cls in mro[:mro.index(self.this_class)+1]:
258 if meth_name in cls.__dict__:
258 if meth_name in cls.__dict__:
259 break
259 break
260 else:
260 else:
261 # We didn't find one. Do static initialization.
261 # We didn't find one. Do static initialization.
262 dv = self.get_default_value()
262 dv = self.get_default_value()
263 newdv = self._validate(obj, dv)
263 newdv = self._validate(obj, dv)
264 obj._trait_values[self.name] = newdv
264 obj._trait_values[self.name] = newdv
265 return
265 return
266 # Complete the dynamic initialization.
266 # Complete the dynamic initialization.
267 obj._trait_dyn_inits[self.name] = cls.__dict__[meth_name]
267 obj._trait_dyn_inits[self.name] = cls.__dict__[meth_name]
268
268
269 def __get__(self, obj, cls=None):
269 def __get__(self, obj, cls=None):
270 """Get the value of the trait by self.name for the instance.
270 """Get the value of the trait by self.name for the instance.
271
271
272 Default values are instantiated when :meth:`HasTraits.__new__`
272 Default values are instantiated when :meth:`HasTraits.__new__`
273 is called. Thus by the time this method gets called either the
273 is called. Thus by the time this method gets called either the
274 default value or a user defined value (they called :meth:`__set__`)
274 default value or a user defined value (they called :meth:`__set__`)
275 is in the :class:`HasTraits` instance.
275 is in the :class:`HasTraits` instance.
276 """
276 """
277 if obj is None:
277 if obj is None:
278 return self
278 return self
279 else:
279 else:
280 try:
280 try:
281 value = obj._trait_values[self.name]
281 value = obj._trait_values[self.name]
282 except KeyError:
282 except KeyError:
283 # Check for a dynamic initializer.
283 # Check for a dynamic initializer.
284 if self.name in obj._trait_dyn_inits:
284 if self.name in obj._trait_dyn_inits:
285 value = obj._trait_dyn_inits[self.name](obj)
285 value = obj._trait_dyn_inits[self.name](obj)
286 # FIXME: Do we really validate here?
286 # FIXME: Do we really validate here?
287 value = self._validate(obj, value)
287 value = self._validate(obj, value)
288 obj._trait_values[self.name] = value
288 obj._trait_values[self.name] = value
289 return value
289 return value
290 else:
290 else:
291 raise TraitError('Unexpected error in TraitType: '
291 raise TraitError('Unexpected error in TraitType: '
292 'both default value and dynamic initializer are '
292 'both default value and dynamic initializer are '
293 'absent.')
293 'absent.')
294 except Exception:
294 except Exception:
295 # HasTraits should call set_default_value to populate
295 # HasTraits should call set_default_value to populate
296 # this. So this should never be reached.
296 # this. So this should never be reached.
297 raise TraitError('Unexpected error in TraitType: '
297 raise TraitError('Unexpected error in TraitType: '
298 'default value not set properly')
298 'default value not set properly')
299 else:
299 else:
300 return value
300 return value
301
301
302 def __set__(self, obj, value):
302 def __set__(self, obj, value):
303 new_value = self._validate(obj, value)
303 new_value = self._validate(obj, value)
304 old_value = self.__get__(obj)
304 old_value = self.__get__(obj)
305 if old_value != new_value:
305 if old_value != new_value:
306 obj._trait_values[self.name] = new_value
306 obj._trait_values[self.name] = new_value
307 obj._notify_trait(self.name, old_value, new_value)
307 obj._notify_trait(self.name, old_value, new_value)
308
308
309 def _validate(self, obj, value):
309 def _validate(self, obj, value):
310 if hasattr(self, 'validate'):
310 if hasattr(self, 'validate'):
311 return self.validate(obj, value)
311 return self.validate(obj, value)
312 elif hasattr(self, 'is_valid_for'):
312 elif hasattr(self, 'is_valid_for'):
313 valid = self.is_valid_for(value)
313 valid = self.is_valid_for(value)
314 if valid:
314 if valid:
315 return value
315 return value
316 else:
316 else:
317 raise TraitError('invalid value for type: %r' % value)
317 raise TraitError('invalid value for type: %r' % value)
318 elif hasattr(self, 'value_for'):
318 elif hasattr(self, 'value_for'):
319 return self.value_for(value)
319 return self.value_for(value)
320 else:
320 else:
321 return value
321 return value
322
322
323 def info(self):
323 def info(self):
324 return self.info_text
324 return self.info_text
325
325
326 def error(self, obj, value):
326 def error(self, obj, value):
327 if obj is not None:
327 if obj is not None:
328 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
328 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
329 % (self.name, class_of(obj),
329 % (self.name, class_of(obj),
330 self.info(), repr_type(value))
330 self.info(), repr_type(value))
331 else:
331 else:
332 e = "The '%s' trait must be %s, but a value of %r was specified." \
332 e = "The '%s' trait must be %s, but a value of %r was specified." \
333 % (self.name, self.info(), repr_type(value))
333 % (self.name, self.info(), repr_type(value))
334 raise TraitError(e)
334 raise TraitError(e)
335
335
336 def get_metadata(self, key):
336 def get_metadata(self, key):
337 return getattr(self, '_metadata', {}).get(key, None)
337 return getattr(self, '_metadata', {}).get(key, None)
338
338
339 def set_metadata(self, key, value):
339 def set_metadata(self, key, value):
340 getattr(self, '_metadata', {})[key] = value
340 getattr(self, '_metadata', {})[key] = value
341
341
342
342
343 #-----------------------------------------------------------------------------
343 #-----------------------------------------------------------------------------
344 # The HasTraits implementation
344 # The HasTraits implementation
345 #-----------------------------------------------------------------------------
345 #-----------------------------------------------------------------------------
346
346
347
347
348 class MetaHasTraits(type):
348 class MetaHasTraits(type):
349 """A metaclass for HasTraits.
349 """A metaclass for HasTraits.
350
350
351 This metaclass makes sure that any TraitType class attributes are
351 This metaclass makes sure that any TraitType class attributes are
352 instantiated and sets their name attribute.
352 instantiated and sets their name attribute.
353 """
353 """
354
354
355 def __new__(mcls, name, bases, classdict):
355 def __new__(mcls, name, bases, classdict):
356 """Create the HasTraits class.
356 """Create the HasTraits class.
357
357
358 This instantiates all TraitTypes in the class dict and sets their
358 This instantiates all TraitTypes in the class dict and sets their
359 :attr:`name` attribute.
359 :attr:`name` attribute.
360 """
360 """
361 # print "MetaHasTraitlets (mcls, name): ", mcls, name
361 # print "MetaHasTraitlets (mcls, name): ", mcls, name
362 # print "MetaHasTraitlets (bases): ", bases
362 # print "MetaHasTraitlets (bases): ", bases
363 # print "MetaHasTraitlets (classdict): ", classdict
363 # print "MetaHasTraitlets (classdict): ", classdict
364 for k,v in classdict.iteritems():
364 for k,v in classdict.iteritems():
365 if isinstance(v, TraitType):
365 if isinstance(v, TraitType):
366 v.name = k
366 v.name = k
367 elif inspect.isclass(v):
367 elif inspect.isclass(v):
368 if issubclass(v, TraitType):
368 if issubclass(v, TraitType):
369 vinst = v()
369 vinst = v()
370 vinst.name = k
370 vinst.name = k
371 classdict[k] = vinst
371 classdict[k] = vinst
372 return super(MetaHasTraits, mcls).__new__(mcls, name, bases, classdict)
372 return super(MetaHasTraits, mcls).__new__(mcls, name, bases, classdict)
373
373
374 def __init__(cls, name, bases, classdict):
374 def __init__(cls, name, bases, classdict):
375 """Finish initializing the HasTraits class.
375 """Finish initializing the HasTraits class.
376
376
377 This sets the :attr:`this_class` attribute of each TraitType in the
377 This sets the :attr:`this_class` attribute of each TraitType in the
378 class dict to the newly created class ``cls``.
378 class dict to the newly created class ``cls``.
379 """
379 """
380 for k, v in classdict.iteritems():
380 for k, v in classdict.iteritems():
381 if isinstance(v, TraitType):
381 if isinstance(v, TraitType):
382 v.this_class = cls
382 v.this_class = cls
383 super(MetaHasTraits, cls).__init__(name, bases, classdict)
383 super(MetaHasTraits, cls).__init__(name, bases, classdict)
384
384
385 class HasTraits(object):
385 class HasTraits(object):
386
386
387 __metaclass__ = MetaHasTraits
387 __metaclass__ = MetaHasTraits
388
388
389 def __new__(cls, **kw):
389 def __new__(cls, **kw):
390 # This is needed because in Python 2.6 object.__new__ only accepts
390 # This is needed because in Python 2.6 object.__new__ only accepts
391 # the cls argument.
391 # the cls argument.
392 new_meth = super(HasTraits, cls).__new__
392 new_meth = super(HasTraits, cls).__new__
393 if new_meth is object.__new__:
393 if new_meth is object.__new__:
394 inst = new_meth(cls)
394 inst = new_meth(cls)
395 else:
395 else:
396 inst = new_meth(cls, **kw)
396 inst = new_meth(cls, **kw)
397 inst._trait_values = {}
397 inst._trait_values = {}
398 inst._trait_notifiers = {}
398 inst._trait_notifiers = {}
399 inst._trait_dyn_inits = {}
399 inst._trait_dyn_inits = {}
400 # Here we tell all the TraitType instances to set their default
400 # Here we tell all the TraitType instances to set their default
401 # values on the instance.
401 # values on the instance.
402 for key in dir(cls):
402 for key in dir(cls):
403 # Some descriptors raise AttributeError like zope.interface's
403 # Some descriptors raise AttributeError like zope.interface's
404 # __provides__ attributes even though they exist. This causes
404 # __provides__ attributes even though they exist. This causes
405 # AttributeErrors even though they are listed in dir(cls).
405 # AttributeErrors even though they are listed in dir(cls).
406 try:
406 try:
407 value = getattr(cls, key)
407 value = getattr(cls, key)
408 except AttributeError:
408 except AttributeError:
409 pass
409 pass
410 else:
410 else:
411 if isinstance(value, TraitType):
411 if isinstance(value, TraitType):
412 value.instance_init(inst)
412 value.instance_init(inst)
413
413
414 return inst
414 return inst
415
415
416 def __init__(self, **kw):
416 def __init__(self, **kw):
417 # Allow trait values to be set using keyword arguments.
417 # Allow trait values to be set using keyword arguments.
418 # We need to use setattr for this to trigger validation and
418 # We need to use setattr for this to trigger validation and
419 # notifications.
419 # notifications.
420 for key, value in kw.iteritems():
420 for key, value in kw.iteritems():
421 setattr(self, key, value)
421 setattr(self, key, value)
422
422
423 def _notify_trait(self, name, old_value, new_value):
423 def _notify_trait(self, name, old_value, new_value):
424
424
425 # First dynamic ones
425 # First dynamic ones
426 callables = self._trait_notifiers.get(name,[])
426 callables = self._trait_notifiers.get(name,[])
427 more_callables = self._trait_notifiers.get('anytrait',[])
427 more_callables = self._trait_notifiers.get('anytrait',[])
428 callables.extend(more_callables)
428 callables.extend(more_callables)
429
429
430 # Now static ones
430 # Now static ones
431 try:
431 try:
432 cb = getattr(self, '_%s_changed' % name)
432 cb = getattr(self, '_%s_changed' % name)
433 except:
433 except:
434 pass
434 pass
435 else:
435 else:
436 callables.append(cb)
436 callables.append(cb)
437
437
438 # Call them all now
438 # Call them all now
439 for c in callables:
439 for c in callables:
440 # Traits catches and logs errors here. I allow them to raise
440 # Traits catches and logs errors here. I allow them to raise
441 if callable(c):
441 if callable(c):
442 argspec = inspect.getargspec(c)
442 argspec = inspect.getargspec(c)
443 nargs = len(argspec[0])
443 nargs = len(argspec[0])
444 # Bound methods have an additional 'self' argument
444 # Bound methods have an additional 'self' argument
445 # I don't know how to treat unbound methods, but they
445 # I don't know how to treat unbound methods, but they
446 # can't really be used for callbacks.
446 # can't really be used for callbacks.
447 if isinstance(c, types.MethodType):
447 if isinstance(c, types.MethodType):
448 offset = -1
448 offset = -1
449 else:
449 else:
450 offset = 0
450 offset = 0
451 if nargs + offset == 0:
451 if nargs + offset == 0:
452 c()
452 c()
453 elif nargs + offset == 1:
453 elif nargs + offset == 1:
454 c(name)
454 c(name)
455 elif nargs + offset == 2:
455 elif nargs + offset == 2:
456 c(name, new_value)
456 c(name, new_value)
457 elif nargs + offset == 3:
457 elif nargs + offset == 3:
458 c(name, old_value, new_value)
458 c(name, old_value, new_value)
459 else:
459 else:
460 raise TraitError('a trait changed callback '
460 raise TraitError('a trait changed callback '
461 'must have 0-3 arguments.')
461 'must have 0-3 arguments.')
462 else:
462 else:
463 raise TraitError('a trait changed callback '
463 raise TraitError('a trait changed callback '
464 'must be callable.')
464 'must be callable.')
465
465
466
466
467 def _add_notifiers(self, handler, name):
467 def _add_notifiers(self, handler, name):
468 if not self._trait_notifiers.has_key(name):
468 if name not in self._trait_notifiers:
469 nlist = []
469 nlist = []
470 self._trait_notifiers[name] = nlist
470 self._trait_notifiers[name] = nlist
471 else:
471 else:
472 nlist = self._trait_notifiers[name]
472 nlist = self._trait_notifiers[name]
473 if handler not in nlist:
473 if handler not in nlist:
474 nlist.append(handler)
474 nlist.append(handler)
475
475
476 def _remove_notifiers(self, handler, name):
476 def _remove_notifiers(self, handler, name):
477 if self._trait_notifiers.has_key(name):
477 if name in self._trait_notifiers:
478 nlist = self._trait_notifiers[name]
478 nlist = self._trait_notifiers[name]
479 try:
479 try:
480 index = nlist.index(handler)
480 index = nlist.index(handler)
481 except ValueError:
481 except ValueError:
482 pass
482 pass
483 else:
483 else:
484 del nlist[index]
484 del nlist[index]
485
485
486 def on_trait_change(self, handler, name=None, remove=False):
486 def on_trait_change(self, handler, name=None, remove=False):
487 """Setup a handler to be called when a trait changes.
487 """Setup a handler to be called when a trait changes.
488
488
489 This is used to setup dynamic notifications of trait changes.
489 This is used to setup dynamic notifications of trait changes.
490
490
491 Static handlers can be created by creating methods on a HasTraits
491 Static handlers can be created by creating methods on a HasTraits
492 subclass with the naming convention '_[traitname]_changed'. Thus,
492 subclass with the naming convention '_[traitname]_changed'. Thus,
493 to create static handler for the trait 'a', create the method
493 to create static handler for the trait 'a', create the method
494 _a_changed(self, name, old, new) (fewer arguments can be used, see
494 _a_changed(self, name, old, new) (fewer arguments can be used, see
495 below).
495 below).
496
496
497 Parameters
497 Parameters
498 ----------
498 ----------
499 handler : callable
499 handler : callable
500 A callable that is called when a trait changes. Its
500 A callable that is called when a trait changes. Its
501 signature can be handler(), handler(name), handler(name, new)
501 signature can be handler(), handler(name), handler(name, new)
502 or handler(name, old, new).
502 or handler(name, old, new).
503 name : list, str, None
503 name : list, str, None
504 If None, the handler will apply to all traits. If a list
504 If None, the handler will apply to all traits. If a list
505 of str, handler will apply to all names in the list. If a
505 of str, handler will apply to all names in the list. If a
506 str, the handler will apply just to that name.
506 str, the handler will apply just to that name.
507 remove : bool
507 remove : bool
508 If False (the default), then install the handler. If True
508 If False (the default), then install the handler. If True
509 then unintall it.
509 then unintall it.
510 """
510 """
511 if remove:
511 if remove:
512 names = parse_notifier_name(name)
512 names = parse_notifier_name(name)
513 for n in names:
513 for n in names:
514 self._remove_notifiers(handler, n)
514 self._remove_notifiers(handler, n)
515 else:
515 else:
516 names = parse_notifier_name(name)
516 names = parse_notifier_name(name)
517 for n in names:
517 for n in names:
518 self._add_notifiers(handler, n)
518 self._add_notifiers(handler, n)
519
519
520 @classmethod
520 @classmethod
521 def class_trait_names(cls, **metadata):
521 def class_trait_names(cls, **metadata):
522 """Get a list of all the names of this classes traits.
522 """Get a list of all the names of this classes traits.
523
523
524 This method is just like the :meth:`trait_names` method, but is unbound.
524 This method is just like the :meth:`trait_names` method, but is unbound.
525 """
525 """
526 return cls.class_traits(**metadata).keys()
526 return cls.class_traits(**metadata).keys()
527
527
528 @classmethod
528 @classmethod
529 def class_traits(cls, **metadata):
529 def class_traits(cls, **metadata):
530 """Get a list of all the traits of this class.
530 """Get a list of all the traits of this class.
531
531
532 This method is just like the :meth:`traits` method, but is unbound.
532 This method is just like the :meth:`traits` method, but is unbound.
533
533
534 The TraitTypes returned don't know anything about the values
534 The TraitTypes returned don't know anything about the values
535 that the various HasTrait's instances are holding.
535 that the various HasTrait's instances are holding.
536
536
537 This follows the same algorithm as traits does and does not allow
537 This follows the same algorithm as traits does and does not allow
538 for any simple way of specifying merely that a metadata name
538 for any simple way of specifying merely that a metadata name
539 exists, but has any value. This is because get_metadata returns
539 exists, but has any value. This is because get_metadata returns
540 None if a metadata key doesn't exist.
540 None if a metadata key doesn't exist.
541 """
541 """
542 traits = dict([memb for memb in getmembers(cls) if \
542 traits = dict([memb for memb in getmembers(cls) if \
543 isinstance(memb[1], TraitType)])
543 isinstance(memb[1], TraitType)])
544
544
545 if len(metadata) == 0:
545 if len(metadata) == 0:
546 return traits
546 return traits
547
547
548 for meta_name, meta_eval in metadata.items():
548 for meta_name, meta_eval in metadata.items():
549 if type(meta_eval) is not FunctionType:
549 if type(meta_eval) is not FunctionType:
550 metadata[meta_name] = _SimpleTest(meta_eval)
550 metadata[meta_name] = _SimpleTest(meta_eval)
551
551
552 result = {}
552 result = {}
553 for name, trait in traits.items():
553 for name, trait in traits.items():
554 for meta_name, meta_eval in metadata.items():
554 for meta_name, meta_eval in metadata.items():
555 if not meta_eval(trait.get_metadata(meta_name)):
555 if not meta_eval(trait.get_metadata(meta_name)):
556 break
556 break
557 else:
557 else:
558 result[name] = trait
558 result[name] = trait
559
559
560 return result
560 return result
561
561
562 def trait_names(self, **metadata):
562 def trait_names(self, **metadata):
563 """Get a list of all the names of this classes traits."""
563 """Get a list of all the names of this classes traits."""
564 return self.traits(**metadata).keys()
564 return self.traits(**metadata).keys()
565
565
566 def traits(self, **metadata):
566 def traits(self, **metadata):
567 """Get a list of all the traits of this class.
567 """Get a list of all the traits of this class.
568
568
569 The TraitTypes returned don't know anything about the values
569 The TraitTypes returned don't know anything about the values
570 that the various HasTrait's instances are holding.
570 that the various HasTrait's instances are holding.
571
571
572 This follows the same algorithm as traits does and does not allow
572 This follows the same algorithm as traits does and does not allow
573 for any simple way of specifying merely that a metadata name
573 for any simple way of specifying merely that a metadata name
574 exists, but has any value. This is because get_metadata returns
574 exists, but has any value. This is because get_metadata returns
575 None if a metadata key doesn't exist.
575 None if a metadata key doesn't exist.
576 """
576 """
577 traits = dict([memb for memb in getmembers(self.__class__) if \
577 traits = dict([memb for memb in getmembers(self.__class__) if \
578 isinstance(memb[1], TraitType)])
578 isinstance(memb[1], TraitType)])
579
579
580 if len(metadata) == 0:
580 if len(metadata) == 0:
581 return traits
581 return traits
582
582
583 for meta_name, meta_eval in metadata.items():
583 for meta_name, meta_eval in metadata.items():
584 if type(meta_eval) is not FunctionType:
584 if type(meta_eval) is not FunctionType:
585 metadata[meta_name] = _SimpleTest(meta_eval)
585 metadata[meta_name] = _SimpleTest(meta_eval)
586
586
587 result = {}
587 result = {}
588 for name, trait in traits.items():
588 for name, trait in traits.items():
589 for meta_name, meta_eval in metadata.items():
589 for meta_name, meta_eval in metadata.items():
590 if not meta_eval(trait.get_metadata(meta_name)):
590 if not meta_eval(trait.get_metadata(meta_name)):
591 break
591 break
592 else:
592 else:
593 result[name] = trait
593 result[name] = trait
594
594
595 return result
595 return result
596
596
597 def trait_metadata(self, traitname, key):
597 def trait_metadata(self, traitname, key):
598 """Get metadata values for trait by key."""
598 """Get metadata values for trait by key."""
599 try:
599 try:
600 trait = getattr(self.__class__, traitname)
600 trait = getattr(self.__class__, traitname)
601 except AttributeError:
601 except AttributeError:
602 raise TraitError("Class %s does not have a trait named %s" %
602 raise TraitError("Class %s does not have a trait named %s" %
603 (self.__class__.__name__, traitname))
603 (self.__class__.__name__, traitname))
604 else:
604 else:
605 return trait.get_metadata(key)
605 return trait.get_metadata(key)
606
606
607 #-----------------------------------------------------------------------------
607 #-----------------------------------------------------------------------------
608 # Actual TraitTypes implementations/subclasses
608 # Actual TraitTypes implementations/subclasses
609 #-----------------------------------------------------------------------------
609 #-----------------------------------------------------------------------------
610
610
611 #-----------------------------------------------------------------------------
611 #-----------------------------------------------------------------------------
612 # TraitTypes subclasses for handling classes and instances of classes
612 # TraitTypes subclasses for handling classes and instances of classes
613 #-----------------------------------------------------------------------------
613 #-----------------------------------------------------------------------------
614
614
615
615
616 class ClassBasedTraitType(TraitType):
616 class ClassBasedTraitType(TraitType):
617 """A trait with error reporting for Type, Instance and This."""
617 """A trait with error reporting for Type, Instance and This."""
618
618
619 def error(self, obj, value):
619 def error(self, obj, value):
620 kind = type(value)
620 kind = type(value)
621 if (not py3compat.PY3) and kind is InstanceType:
621 if (not py3compat.PY3) and kind is InstanceType:
622 msg = 'class %s' % value.__class__.__name__
622 msg = 'class %s' % value.__class__.__name__
623 else:
623 else:
624 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
624 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
625
625
626 if obj is not None:
626 if obj is not None:
627 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
627 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
628 % (self.name, class_of(obj),
628 % (self.name, class_of(obj),
629 self.info(), msg)
629 self.info(), msg)
630 else:
630 else:
631 e = "The '%s' trait must be %s, but a value of %r was specified." \
631 e = "The '%s' trait must be %s, but a value of %r was specified." \
632 % (self.name, self.info(), msg)
632 % (self.name, self.info(), msg)
633
633
634 raise TraitError(e)
634 raise TraitError(e)
635
635
636
636
637 class Type(ClassBasedTraitType):
637 class Type(ClassBasedTraitType):
638 """A trait whose value must be a subclass of a specified class."""
638 """A trait whose value must be a subclass of a specified class."""
639
639
640 def __init__ (self, default_value=None, klass=None, allow_none=True, **metadata ):
640 def __init__ (self, default_value=None, klass=None, allow_none=True, **metadata ):
641 """Construct a Type trait
641 """Construct a Type trait
642
642
643 A Type trait specifies that its values must be subclasses of
643 A Type trait specifies that its values must be subclasses of
644 a particular class.
644 a particular class.
645
645
646 If only ``default_value`` is given, it is used for the ``klass`` as
646 If only ``default_value`` is given, it is used for the ``klass`` as
647 well.
647 well.
648
648
649 Parameters
649 Parameters
650 ----------
650 ----------
651 default_value : class, str or None
651 default_value : class, str or None
652 The default value must be a subclass of klass. If an str,
652 The default value must be a subclass of klass. If an str,
653 the str must be a fully specified class name, like 'foo.bar.Bah'.
653 the str must be a fully specified class name, like 'foo.bar.Bah'.
654 The string is resolved into real class, when the parent
654 The string is resolved into real class, when the parent
655 :class:`HasTraits` class is instantiated.
655 :class:`HasTraits` class is instantiated.
656 klass : class, str, None
656 klass : class, str, None
657 Values of this trait must be a subclass of klass. The klass
657 Values of this trait must be a subclass of klass. The klass
658 may be specified in a string like: 'foo.bar.MyClass'.
658 may be specified in a string like: 'foo.bar.MyClass'.
659 The string is resolved into real class, when the parent
659 The string is resolved into real class, when the parent
660 :class:`HasTraits` class is instantiated.
660 :class:`HasTraits` class is instantiated.
661 allow_none : boolean
661 allow_none : boolean
662 Indicates whether None is allowed as an assignable value. Even if
662 Indicates whether None is allowed as an assignable value. Even if
663 ``False``, the default value may be ``None``.
663 ``False``, the default value may be ``None``.
664 """
664 """
665 if default_value is None:
665 if default_value is None:
666 if klass is None:
666 if klass is None:
667 klass = object
667 klass = object
668 elif klass is None:
668 elif klass is None:
669 klass = default_value
669 klass = default_value
670
670
671 if not (inspect.isclass(klass) or isinstance(klass, basestring)):
671 if not (inspect.isclass(klass) or isinstance(klass, basestring)):
672 raise TraitError("A Type trait must specify a class.")
672 raise TraitError("A Type trait must specify a class.")
673
673
674 self.klass = klass
674 self.klass = klass
675 self._allow_none = allow_none
675 self._allow_none = allow_none
676
676
677 super(Type, self).__init__(default_value, **metadata)
677 super(Type, self).__init__(default_value, **metadata)
678
678
679 def validate(self, obj, value):
679 def validate(self, obj, value):
680 """Validates that the value is a valid object instance."""
680 """Validates that the value is a valid object instance."""
681 try:
681 try:
682 if issubclass(value, self.klass):
682 if issubclass(value, self.klass):
683 return value
683 return value
684 except:
684 except:
685 if (value is None) and (self._allow_none):
685 if (value is None) and (self._allow_none):
686 return value
686 return value
687
687
688 self.error(obj, value)
688 self.error(obj, value)
689
689
690 def info(self):
690 def info(self):
691 """ Returns a description of the trait."""
691 """ Returns a description of the trait."""
692 if isinstance(self.klass, basestring):
692 if isinstance(self.klass, basestring):
693 klass = self.klass
693 klass = self.klass
694 else:
694 else:
695 klass = self.klass.__name__
695 klass = self.klass.__name__
696 result = 'a subclass of ' + klass
696 result = 'a subclass of ' + klass
697 if self._allow_none:
697 if self._allow_none:
698 return result + ' or None'
698 return result + ' or None'
699 return result
699 return result
700
700
701 def instance_init(self, obj):
701 def instance_init(self, obj):
702 self._resolve_classes()
702 self._resolve_classes()
703 super(Type, self).instance_init(obj)
703 super(Type, self).instance_init(obj)
704
704
705 def _resolve_classes(self):
705 def _resolve_classes(self):
706 if isinstance(self.klass, basestring):
706 if isinstance(self.klass, basestring):
707 self.klass = import_item(self.klass)
707 self.klass = import_item(self.klass)
708 if isinstance(self.default_value, basestring):
708 if isinstance(self.default_value, basestring):
709 self.default_value = import_item(self.default_value)
709 self.default_value = import_item(self.default_value)
710
710
711 def get_default_value(self):
711 def get_default_value(self):
712 return self.default_value
712 return self.default_value
713
713
714
714
715 class DefaultValueGenerator(object):
715 class DefaultValueGenerator(object):
716 """A class for generating new default value instances."""
716 """A class for generating new default value instances."""
717
717
718 def __init__(self, *args, **kw):
718 def __init__(self, *args, **kw):
719 self.args = args
719 self.args = args
720 self.kw = kw
720 self.kw = kw
721
721
722 def generate(self, klass):
722 def generate(self, klass):
723 return klass(*self.args, **self.kw)
723 return klass(*self.args, **self.kw)
724
724
725
725
726 class Instance(ClassBasedTraitType):
726 class Instance(ClassBasedTraitType):
727 """A trait whose value must be an instance of a specified class.
727 """A trait whose value must be an instance of a specified class.
728
728
729 The value can also be an instance of a subclass of the specified class.
729 The value can also be an instance of a subclass of the specified class.
730 """
730 """
731
731
732 def __init__(self, klass=None, args=None, kw=None,
732 def __init__(self, klass=None, args=None, kw=None,
733 allow_none=True, **metadata ):
733 allow_none=True, **metadata ):
734 """Construct an Instance trait.
734 """Construct an Instance trait.
735
735
736 This trait allows values that are instances of a particular
736 This trait allows values that are instances of a particular
737 class or its sublclasses. Our implementation is quite different
737 class or its sublclasses. Our implementation is quite different
738 from that of enthough.traits as we don't allow instances to be used
738 from that of enthough.traits as we don't allow instances to be used
739 for klass and we handle the ``args`` and ``kw`` arguments differently.
739 for klass and we handle the ``args`` and ``kw`` arguments differently.
740
740
741 Parameters
741 Parameters
742 ----------
742 ----------
743 klass : class, str
743 klass : class, str
744 The class that forms the basis for the trait. Class names
744 The class that forms the basis for the trait. Class names
745 can also be specified as strings, like 'foo.bar.Bar'.
745 can also be specified as strings, like 'foo.bar.Bar'.
746 args : tuple
746 args : tuple
747 Positional arguments for generating the default value.
747 Positional arguments for generating the default value.
748 kw : dict
748 kw : dict
749 Keyword arguments for generating the default value.
749 Keyword arguments for generating the default value.
750 allow_none : bool
750 allow_none : bool
751 Indicates whether None is allowed as a value.
751 Indicates whether None is allowed as a value.
752
752
753 Default Value
753 Default Value
754 -------------
754 -------------
755 If both ``args`` and ``kw`` are None, then the default value is None.
755 If both ``args`` and ``kw`` are None, then the default value is None.
756 If ``args`` is a tuple and ``kw`` is a dict, then the default is
756 If ``args`` is a tuple and ``kw`` is a dict, then the default is
757 created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
757 created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
758 not (but not both), None is replace by ``()`` or ``{}``.
758 not (but not both), None is replace by ``()`` or ``{}``.
759 """
759 """
760
760
761 self._allow_none = allow_none
761 self._allow_none = allow_none
762
762
763 if (klass is None) or (not (inspect.isclass(klass) or isinstance(klass, basestring))):
763 if (klass is None) or (not (inspect.isclass(klass) or isinstance(klass, basestring))):
764 raise TraitError('The klass argument must be a class'
764 raise TraitError('The klass argument must be a class'
765 ' you gave: %r' % klass)
765 ' you gave: %r' % klass)
766 self.klass = klass
766 self.klass = klass
767
767
768 # self.klass is a class, so handle default_value
768 # self.klass is a class, so handle default_value
769 if args is None and kw is None:
769 if args is None and kw is None:
770 default_value = None
770 default_value = None
771 else:
771 else:
772 if args is None:
772 if args is None:
773 # kw is not None
773 # kw is not None
774 args = ()
774 args = ()
775 elif kw is None:
775 elif kw is None:
776 # args is not None
776 # args is not None
777 kw = {}
777 kw = {}
778
778
779 if not isinstance(kw, dict):
779 if not isinstance(kw, dict):
780 raise TraitError("The 'kw' argument must be a dict or None.")
780 raise TraitError("The 'kw' argument must be a dict or None.")
781 if not isinstance(args, tuple):
781 if not isinstance(args, tuple):
782 raise TraitError("The 'args' argument must be a tuple or None.")
782 raise TraitError("The 'args' argument must be a tuple or None.")
783
783
784 default_value = DefaultValueGenerator(*args, **kw)
784 default_value = DefaultValueGenerator(*args, **kw)
785
785
786 super(Instance, self).__init__(default_value, **metadata)
786 super(Instance, self).__init__(default_value, **metadata)
787
787
788 def validate(self, obj, value):
788 def validate(self, obj, value):
789 if value is None:
789 if value is None:
790 if self._allow_none:
790 if self._allow_none:
791 return value
791 return value
792 self.error(obj, value)
792 self.error(obj, value)
793
793
794 if isinstance(value, self.klass):
794 if isinstance(value, self.klass):
795 return value
795 return value
796 else:
796 else:
797 self.error(obj, value)
797 self.error(obj, value)
798
798
799 def info(self):
799 def info(self):
800 if isinstance(self.klass, basestring):
800 if isinstance(self.klass, basestring):
801 klass = self.klass
801 klass = self.klass
802 else:
802 else:
803 klass = self.klass.__name__
803 klass = self.klass.__name__
804 result = class_of(klass)
804 result = class_of(klass)
805 if self._allow_none:
805 if self._allow_none:
806 return result + ' or None'
806 return result + ' or None'
807
807
808 return result
808 return result
809
809
810 def instance_init(self, obj):
810 def instance_init(self, obj):
811 self._resolve_classes()
811 self._resolve_classes()
812 super(Instance, self).instance_init(obj)
812 super(Instance, self).instance_init(obj)
813
813
814 def _resolve_classes(self):
814 def _resolve_classes(self):
815 if isinstance(self.klass, basestring):
815 if isinstance(self.klass, basestring):
816 self.klass = import_item(self.klass)
816 self.klass = import_item(self.klass)
817
817
818 def get_default_value(self):
818 def get_default_value(self):
819 """Instantiate a default value instance.
819 """Instantiate a default value instance.
820
820
821 This is called when the containing HasTraits classes'
821 This is called when the containing HasTraits classes'
822 :meth:`__new__` method is called to ensure that a unique instance
822 :meth:`__new__` method is called to ensure that a unique instance
823 is created for each HasTraits instance.
823 is created for each HasTraits instance.
824 """
824 """
825 dv = self.default_value
825 dv = self.default_value
826 if isinstance(dv, DefaultValueGenerator):
826 if isinstance(dv, DefaultValueGenerator):
827 return dv.generate(self.klass)
827 return dv.generate(self.klass)
828 else:
828 else:
829 return dv
829 return dv
830
830
831
831
832 class This(ClassBasedTraitType):
832 class This(ClassBasedTraitType):
833 """A trait for instances of the class containing this trait.
833 """A trait for instances of the class containing this trait.
834
834
835 Because how how and when class bodies are executed, the ``This``
835 Because how how and when class bodies are executed, the ``This``
836 trait can only have a default value of None. This, and because we
836 trait can only have a default value of None. This, and because we
837 always validate default values, ``allow_none`` is *always* true.
837 always validate default values, ``allow_none`` is *always* true.
838 """
838 """
839
839
840 info_text = 'an instance of the same type as the receiver or None'
840 info_text = 'an instance of the same type as the receiver or None'
841
841
842 def __init__(self, **metadata):
842 def __init__(self, **metadata):
843 super(This, self).__init__(None, **metadata)
843 super(This, self).__init__(None, **metadata)
844
844
845 def validate(self, obj, value):
845 def validate(self, obj, value):
846 # What if value is a superclass of obj.__class__? This is
846 # What if value is a superclass of obj.__class__? This is
847 # complicated if it was the superclass that defined the This
847 # complicated if it was the superclass that defined the This
848 # trait.
848 # trait.
849 if isinstance(value, self.this_class) or (value is None):
849 if isinstance(value, self.this_class) or (value is None):
850 return value
850 return value
851 else:
851 else:
852 self.error(obj, value)
852 self.error(obj, value)
853
853
854
854
855 #-----------------------------------------------------------------------------
855 #-----------------------------------------------------------------------------
856 # Basic TraitTypes implementations/subclasses
856 # Basic TraitTypes implementations/subclasses
857 #-----------------------------------------------------------------------------
857 #-----------------------------------------------------------------------------
858
858
859
859
860 class Any(TraitType):
860 class Any(TraitType):
861 default_value = None
861 default_value = None
862 info_text = 'any value'
862 info_text = 'any value'
863
863
864
864
865 class Int(TraitType):
865 class Int(TraitType):
866 """An int trait."""
866 """An int trait."""
867
867
868 default_value = 0
868 default_value = 0
869 info_text = 'an int'
869 info_text = 'an int'
870
870
871 def validate(self, obj, value):
871 def validate(self, obj, value):
872 if isinstance(value, int):
872 if isinstance(value, int):
873 return value
873 return value
874 self.error(obj, value)
874 self.error(obj, value)
875
875
876 class CInt(Int):
876 class CInt(Int):
877 """A casting version of the int trait."""
877 """A casting version of the int trait."""
878
878
879 def validate(self, obj, value):
879 def validate(self, obj, value):
880 try:
880 try:
881 return int(value)
881 return int(value)
882 except:
882 except:
883 self.error(obj, value)
883 self.error(obj, value)
884
884
885 if py3compat.PY3:
885 if py3compat.PY3:
886 Long, CLong = Int, CInt
886 Long, CLong = Int, CInt
887 Integer = Int
887 Integer = Int
888 else:
888 else:
889 class Long(TraitType):
889 class Long(TraitType):
890 """A long integer trait."""
890 """A long integer trait."""
891
891
892 default_value = 0L
892 default_value = 0L
893 info_text = 'a long'
893 info_text = 'a long'
894
894
895 def validate(self, obj, value):
895 def validate(self, obj, value):
896 if isinstance(value, long):
896 if isinstance(value, long):
897 return value
897 return value
898 if isinstance(value, int):
898 if isinstance(value, int):
899 return long(value)
899 return long(value)
900 self.error(obj, value)
900 self.error(obj, value)
901
901
902
902
903 class CLong(Long):
903 class CLong(Long):
904 """A casting version of the long integer trait."""
904 """A casting version of the long integer trait."""
905
905
906 def validate(self, obj, value):
906 def validate(self, obj, value):
907 try:
907 try:
908 return long(value)
908 return long(value)
909 except:
909 except:
910 self.error(obj, value)
910 self.error(obj, value)
911
911
912 class Integer(TraitType):
912 class Integer(TraitType):
913 """An integer trait.
913 """An integer trait.
914
914
915 Longs that are unnecessary (<= sys.maxint) are cast to ints."""
915 Longs that are unnecessary (<= sys.maxint) are cast to ints."""
916
916
917 default_value = 0
917 default_value = 0
918 info_text = 'an integer'
918 info_text = 'an integer'
919
919
920 def validate(self, obj, value):
920 def validate(self, obj, value):
921 if isinstance(value, int):
921 if isinstance(value, int):
922 return value
922 return value
923 elif isinstance(value, long):
923 elif isinstance(value, long):
924 # downcast longs that fit in int:
924 # downcast longs that fit in int:
925 # note that int(n > sys.maxint) returns a long, so
925 # note that int(n > sys.maxint) returns a long, so
926 # we don't need a condition on this cast
926 # we don't need a condition on this cast
927 return int(value)
927 return int(value)
928 self.error(obj, value)
928 self.error(obj, value)
929
929
930
930
931 class Float(TraitType):
931 class Float(TraitType):
932 """A float trait."""
932 """A float trait."""
933
933
934 default_value = 0.0
934 default_value = 0.0
935 info_text = 'a float'
935 info_text = 'a float'
936
936
937 def validate(self, obj, value):
937 def validate(self, obj, value):
938 if isinstance(value, float):
938 if isinstance(value, float):
939 return value
939 return value
940 if isinstance(value, int):
940 if isinstance(value, int):
941 return float(value)
941 return float(value)
942 self.error(obj, value)
942 self.error(obj, value)
943
943
944
944
945 class CFloat(Float):
945 class CFloat(Float):
946 """A casting version of the float trait."""
946 """A casting version of the float trait."""
947
947
948 def validate(self, obj, value):
948 def validate(self, obj, value):
949 try:
949 try:
950 return float(value)
950 return float(value)
951 except:
951 except:
952 self.error(obj, value)
952 self.error(obj, value)
953
953
954 class Complex(TraitType):
954 class Complex(TraitType):
955 """A trait for complex numbers."""
955 """A trait for complex numbers."""
956
956
957 default_value = 0.0 + 0.0j
957 default_value = 0.0 + 0.0j
958 info_text = 'a complex number'
958 info_text = 'a complex number'
959
959
960 def validate(self, obj, value):
960 def validate(self, obj, value):
961 if isinstance(value, complex):
961 if isinstance(value, complex):
962 return value
962 return value
963 if isinstance(value, (float, int)):
963 if isinstance(value, (float, int)):
964 return complex(value)
964 return complex(value)
965 self.error(obj, value)
965 self.error(obj, value)
966
966
967
967
968 class CComplex(Complex):
968 class CComplex(Complex):
969 """A casting version of the complex number trait."""
969 """A casting version of the complex number trait."""
970
970
971 def validate (self, obj, value):
971 def validate (self, obj, value):
972 try:
972 try:
973 return complex(value)
973 return complex(value)
974 except:
974 except:
975 self.error(obj, value)
975 self.error(obj, value)
976
976
977 # We should always be explicit about whether we're using bytes or unicode, both
977 # We should always be explicit about whether we're using bytes or unicode, both
978 # for Python 3 conversion and for reliable unicode behaviour on Python 2. So
978 # for Python 3 conversion and for reliable unicode behaviour on Python 2. So
979 # we don't have a Str type.
979 # we don't have a Str type.
980 class Bytes(TraitType):
980 class Bytes(TraitType):
981 """A trait for byte strings."""
981 """A trait for byte strings."""
982
982
983 default_value = b''
983 default_value = b''
984 info_text = 'a string'
984 info_text = 'a string'
985
985
986 def validate(self, obj, value):
986 def validate(self, obj, value):
987 if isinstance(value, bytes):
987 if isinstance(value, bytes):
988 return value
988 return value
989 self.error(obj, value)
989 self.error(obj, value)
990
990
991
991
992 class CBytes(Bytes):
992 class CBytes(Bytes):
993 """A casting version of the byte string trait."""
993 """A casting version of the byte string trait."""
994
994
995 def validate(self, obj, value):
995 def validate(self, obj, value):
996 try:
996 try:
997 return bytes(value)
997 return bytes(value)
998 except:
998 except:
999 self.error(obj, value)
999 self.error(obj, value)
1000
1000
1001
1001
1002 class Unicode(TraitType):
1002 class Unicode(TraitType):
1003 """A trait for unicode strings."""
1003 """A trait for unicode strings."""
1004
1004
1005 default_value = u''
1005 default_value = u''
1006 info_text = 'a unicode string'
1006 info_text = 'a unicode string'
1007
1007
1008 def validate(self, obj, value):
1008 def validate(self, obj, value):
1009 if isinstance(value, unicode):
1009 if isinstance(value, unicode):
1010 return value
1010 return value
1011 if isinstance(value, bytes):
1011 if isinstance(value, bytes):
1012 return unicode(value)
1012 return unicode(value)
1013 self.error(obj, value)
1013 self.error(obj, value)
1014
1014
1015
1015
1016 class CUnicode(Unicode):
1016 class CUnicode(Unicode):
1017 """A casting version of the unicode trait."""
1017 """A casting version of the unicode trait."""
1018
1018
1019 def validate(self, obj, value):
1019 def validate(self, obj, value):
1020 try:
1020 try:
1021 return unicode(value)
1021 return unicode(value)
1022 except:
1022 except:
1023 self.error(obj, value)
1023 self.error(obj, value)
1024
1024
1025
1025
1026 class ObjectName(TraitType):
1026 class ObjectName(TraitType):
1027 """A string holding a valid object name in this version of Python.
1027 """A string holding a valid object name in this version of Python.
1028
1028
1029 This does not check that the name exists in any scope."""
1029 This does not check that the name exists in any scope."""
1030 info_text = "a valid object identifier in Python"
1030 info_text = "a valid object identifier in Python"
1031
1031
1032 if py3compat.PY3:
1032 if py3compat.PY3:
1033 # Python 3:
1033 # Python 3:
1034 coerce_str = staticmethod(lambda _,s: s)
1034 coerce_str = staticmethod(lambda _,s: s)
1035
1035
1036 else:
1036 else:
1037 # Python 2:
1037 # Python 2:
1038 def coerce_str(self, obj, value):
1038 def coerce_str(self, obj, value):
1039 "In Python 2, coerce ascii-only unicode to str"
1039 "In Python 2, coerce ascii-only unicode to str"
1040 if isinstance(value, unicode):
1040 if isinstance(value, unicode):
1041 try:
1041 try:
1042 return str(value)
1042 return str(value)
1043 except UnicodeEncodeError:
1043 except UnicodeEncodeError:
1044 self.error(obj, value)
1044 self.error(obj, value)
1045 return value
1045 return value
1046
1046
1047 def validate(self, obj, value):
1047 def validate(self, obj, value):
1048 value = self.coerce_str(obj, value)
1048 value = self.coerce_str(obj, value)
1049
1049
1050 if isinstance(value, str) and py3compat.isidentifier(value):
1050 if isinstance(value, str) and py3compat.isidentifier(value):
1051 return value
1051 return value
1052 self.error(obj, value)
1052 self.error(obj, value)
1053
1053
1054 class DottedObjectName(ObjectName):
1054 class DottedObjectName(ObjectName):
1055 """A string holding a valid dotted object name in Python, such as A.b3._c"""
1055 """A string holding a valid dotted object name in Python, such as A.b3._c"""
1056 def validate(self, obj, value):
1056 def validate(self, obj, value):
1057 value = self.coerce_str(obj, value)
1057 value = self.coerce_str(obj, value)
1058
1058
1059 if isinstance(value, str) and py3compat.isidentifier(value, dotted=True):
1059 if isinstance(value, str) and py3compat.isidentifier(value, dotted=True):
1060 return value
1060 return value
1061 self.error(obj, value)
1061 self.error(obj, value)
1062
1062
1063
1063
1064 class Bool(TraitType):
1064 class Bool(TraitType):
1065 """A boolean (True, False) trait."""
1065 """A boolean (True, False) trait."""
1066
1066
1067 default_value = False
1067 default_value = False
1068 info_text = 'a boolean'
1068 info_text = 'a boolean'
1069
1069
1070 def validate(self, obj, value):
1070 def validate(self, obj, value):
1071 if isinstance(value, bool):
1071 if isinstance(value, bool):
1072 return value
1072 return value
1073 self.error(obj, value)
1073 self.error(obj, value)
1074
1074
1075
1075
1076 class CBool(Bool):
1076 class CBool(Bool):
1077 """A casting version of the boolean trait."""
1077 """A casting version of the boolean trait."""
1078
1078
1079 def validate(self, obj, value):
1079 def validate(self, obj, value):
1080 try:
1080 try:
1081 return bool(value)
1081 return bool(value)
1082 except:
1082 except:
1083 self.error(obj, value)
1083 self.error(obj, value)
1084
1084
1085
1085
1086 class Enum(TraitType):
1086 class Enum(TraitType):
1087 """An enum that whose value must be in a given sequence."""
1087 """An enum that whose value must be in a given sequence."""
1088
1088
1089 def __init__(self, values, default_value=None, allow_none=True, **metadata):
1089 def __init__(self, values, default_value=None, allow_none=True, **metadata):
1090 self.values = values
1090 self.values = values
1091 self._allow_none = allow_none
1091 self._allow_none = allow_none
1092 super(Enum, self).__init__(default_value, **metadata)
1092 super(Enum, self).__init__(default_value, **metadata)
1093
1093
1094 def validate(self, obj, value):
1094 def validate(self, obj, value):
1095 if value is None:
1095 if value is None:
1096 if self._allow_none:
1096 if self._allow_none:
1097 return value
1097 return value
1098
1098
1099 if value in self.values:
1099 if value in self.values:
1100 return value
1100 return value
1101 self.error(obj, value)
1101 self.error(obj, value)
1102
1102
1103 def info(self):
1103 def info(self):
1104 """ Returns a description of the trait."""
1104 """ Returns a description of the trait."""
1105 result = 'any of ' + repr(self.values)
1105 result = 'any of ' + repr(self.values)
1106 if self._allow_none:
1106 if self._allow_none:
1107 return result + ' or None'
1107 return result + ' or None'
1108 return result
1108 return result
1109
1109
1110 class CaselessStrEnum(Enum):
1110 class CaselessStrEnum(Enum):
1111 """An enum of strings that are caseless in validate."""
1111 """An enum of strings that are caseless in validate."""
1112
1112
1113 def validate(self, obj, value):
1113 def validate(self, obj, value):
1114 if value is None:
1114 if value is None:
1115 if self._allow_none:
1115 if self._allow_none:
1116 return value
1116 return value
1117
1117
1118 if not isinstance(value, basestring):
1118 if not isinstance(value, basestring):
1119 self.error(obj, value)
1119 self.error(obj, value)
1120
1120
1121 for v in self.values:
1121 for v in self.values:
1122 if v.lower() == value.lower():
1122 if v.lower() == value.lower():
1123 return v
1123 return v
1124 self.error(obj, value)
1124 self.error(obj, value)
1125
1125
1126 class Container(Instance):
1126 class Container(Instance):
1127 """An instance of a container (list, set, etc.)
1127 """An instance of a container (list, set, etc.)
1128
1128
1129 To be subclassed by overriding klass.
1129 To be subclassed by overriding klass.
1130 """
1130 """
1131 klass = None
1131 klass = None
1132 _valid_defaults = SequenceTypes
1132 _valid_defaults = SequenceTypes
1133 _trait = None
1133 _trait = None
1134
1134
1135 def __init__(self, trait=None, default_value=None, allow_none=True,
1135 def __init__(self, trait=None, default_value=None, allow_none=True,
1136 **metadata):
1136 **metadata):
1137 """Create a container trait type from a list, set, or tuple.
1137 """Create a container trait type from a list, set, or tuple.
1138
1138
1139 The default value is created by doing ``List(default_value)``,
1139 The default value is created by doing ``List(default_value)``,
1140 which creates a copy of the ``default_value``.
1140 which creates a copy of the ``default_value``.
1141
1141
1142 ``trait`` can be specified, which restricts the type of elements
1142 ``trait`` can be specified, which restricts the type of elements
1143 in the container to that TraitType.
1143 in the container to that TraitType.
1144
1144
1145 If only one arg is given and it is not a Trait, it is taken as
1145 If only one arg is given and it is not a Trait, it is taken as
1146 ``default_value``:
1146 ``default_value``:
1147
1147
1148 ``c = List([1,2,3])``
1148 ``c = List([1,2,3])``
1149
1149
1150 Parameters
1150 Parameters
1151 ----------
1151 ----------
1152
1152
1153 trait : TraitType [ optional ]
1153 trait : TraitType [ optional ]
1154 the type for restricting the contents of the Container. If unspecified,
1154 the type for restricting the contents of the Container. If unspecified,
1155 types are not checked.
1155 types are not checked.
1156
1156
1157 default_value : SequenceType [ optional ]
1157 default_value : SequenceType [ optional ]
1158 The default value for the Trait. Must be list/tuple/set, and
1158 The default value for the Trait. Must be list/tuple/set, and
1159 will be cast to the container type.
1159 will be cast to the container type.
1160
1160
1161 allow_none : Bool [ default True ]
1161 allow_none : Bool [ default True ]
1162 Whether to allow the value to be None
1162 Whether to allow the value to be None
1163
1163
1164 **metadata : any
1164 **metadata : any
1165 further keys for extensions to the Trait (e.g. config)
1165 further keys for extensions to the Trait (e.g. config)
1166
1166
1167 """
1167 """
1168 istrait = lambda t: isinstance(t, type) and issubclass(t, TraitType)
1168 istrait = lambda t: isinstance(t, type) and issubclass(t, TraitType)
1169
1169
1170 # allow List([values]):
1170 # allow List([values]):
1171 if default_value is None and not istrait(trait):
1171 if default_value is None and not istrait(trait):
1172 default_value = trait
1172 default_value = trait
1173 trait = None
1173 trait = None
1174
1174
1175 if default_value is None:
1175 if default_value is None:
1176 args = ()
1176 args = ()
1177 elif isinstance(default_value, self._valid_defaults):
1177 elif isinstance(default_value, self._valid_defaults):
1178 args = (default_value,)
1178 args = (default_value,)
1179 else:
1179 else:
1180 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1180 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1181
1181
1182 if istrait(trait):
1182 if istrait(trait):
1183 self._trait = trait()
1183 self._trait = trait()
1184 self._trait.name = 'element'
1184 self._trait.name = 'element'
1185 elif trait is not None:
1185 elif trait is not None:
1186 raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
1186 raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
1187
1187
1188 super(Container,self).__init__(klass=self.klass, args=args,
1188 super(Container,self).__init__(klass=self.klass, args=args,
1189 allow_none=allow_none, **metadata)
1189 allow_none=allow_none, **metadata)
1190
1190
1191 def element_error(self, obj, element, validator):
1191 def element_error(self, obj, element, validator):
1192 e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
1192 e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
1193 % (self.name, class_of(obj), validator.info(), repr_type(element))
1193 % (self.name, class_of(obj), validator.info(), repr_type(element))
1194 raise TraitError(e)
1194 raise TraitError(e)
1195
1195
1196 def validate(self, obj, value):
1196 def validate(self, obj, value):
1197 value = super(Container, self).validate(obj, value)
1197 value = super(Container, self).validate(obj, value)
1198 if value is None:
1198 if value is None:
1199 return value
1199 return value
1200
1200
1201 value = self.validate_elements(obj, value)
1201 value = self.validate_elements(obj, value)
1202
1202
1203 return value
1203 return value
1204
1204
1205 def validate_elements(self, obj, value):
1205 def validate_elements(self, obj, value):
1206 validated = []
1206 validated = []
1207 if self._trait is None or isinstance(self._trait, Any):
1207 if self._trait is None or isinstance(self._trait, Any):
1208 return value
1208 return value
1209 for v in value:
1209 for v in value:
1210 try:
1210 try:
1211 v = self._trait.validate(obj, v)
1211 v = self._trait.validate(obj, v)
1212 except TraitError:
1212 except TraitError:
1213 self.element_error(obj, v, self._trait)
1213 self.element_error(obj, v, self._trait)
1214 else:
1214 else:
1215 validated.append(v)
1215 validated.append(v)
1216 return self.klass(validated)
1216 return self.klass(validated)
1217
1217
1218
1218
1219 class List(Container):
1219 class List(Container):
1220 """An instance of a Python list."""
1220 """An instance of a Python list."""
1221 klass = list
1221 klass = list
1222
1222
1223 def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxint,
1223 def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxint,
1224 allow_none=True, **metadata):
1224 allow_none=True, **metadata):
1225 """Create a List trait type from a list, set, or tuple.
1225 """Create a List trait type from a list, set, or tuple.
1226
1226
1227 The default value is created by doing ``List(default_value)``,
1227 The default value is created by doing ``List(default_value)``,
1228 which creates a copy of the ``default_value``.
1228 which creates a copy of the ``default_value``.
1229
1229
1230 ``trait`` can be specified, which restricts the type of elements
1230 ``trait`` can be specified, which restricts the type of elements
1231 in the container to that TraitType.
1231 in the container to that TraitType.
1232
1232
1233 If only one arg is given and it is not a Trait, it is taken as
1233 If only one arg is given and it is not a Trait, it is taken as
1234 ``default_value``:
1234 ``default_value``:
1235
1235
1236 ``c = List([1,2,3])``
1236 ``c = List([1,2,3])``
1237
1237
1238 Parameters
1238 Parameters
1239 ----------
1239 ----------
1240
1240
1241 trait : TraitType [ optional ]
1241 trait : TraitType [ optional ]
1242 the type for restricting the contents of the Container. If unspecified,
1242 the type for restricting the contents of the Container. If unspecified,
1243 types are not checked.
1243 types are not checked.
1244
1244
1245 default_value : SequenceType [ optional ]
1245 default_value : SequenceType [ optional ]
1246 The default value for the Trait. Must be list/tuple/set, and
1246 The default value for the Trait. Must be list/tuple/set, and
1247 will be cast to the container type.
1247 will be cast to the container type.
1248
1248
1249 minlen : Int [ default 0 ]
1249 minlen : Int [ default 0 ]
1250 The minimum length of the input list
1250 The minimum length of the input list
1251
1251
1252 maxlen : Int [ default sys.maxint ]
1252 maxlen : Int [ default sys.maxint ]
1253 The maximum length of the input list
1253 The maximum length of the input list
1254
1254
1255 allow_none : Bool [ default True ]
1255 allow_none : Bool [ default True ]
1256 Whether to allow the value to be None
1256 Whether to allow the value to be None
1257
1257
1258 **metadata : any
1258 **metadata : any
1259 further keys for extensions to the Trait (e.g. config)
1259 further keys for extensions to the Trait (e.g. config)
1260
1260
1261 """
1261 """
1262 self._minlen = minlen
1262 self._minlen = minlen
1263 self._maxlen = maxlen
1263 self._maxlen = maxlen
1264 super(List, self).__init__(trait=trait, default_value=default_value,
1264 super(List, self).__init__(trait=trait, default_value=default_value,
1265 allow_none=allow_none, **metadata)
1265 allow_none=allow_none, **metadata)
1266
1266
1267 def length_error(self, obj, value):
1267 def length_error(self, obj, value):
1268 e = "The '%s' trait of %s instance must be of length %i <= L <= %i, but a value of %s was specified." \
1268 e = "The '%s' trait of %s instance must be of length %i <= L <= %i, but a value of %s was specified." \
1269 % (self.name, class_of(obj), self._minlen, self._maxlen, value)
1269 % (self.name, class_of(obj), self._minlen, self._maxlen, value)
1270 raise TraitError(e)
1270 raise TraitError(e)
1271
1271
1272 def validate_elements(self, obj, value):
1272 def validate_elements(self, obj, value):
1273 length = len(value)
1273 length = len(value)
1274 if length < self._minlen or length > self._maxlen:
1274 if length < self._minlen or length > self._maxlen:
1275 self.length_error(obj, value)
1275 self.length_error(obj, value)
1276
1276
1277 return super(List, self).validate_elements(obj, value)
1277 return super(List, self).validate_elements(obj, value)
1278
1278
1279
1279
1280 class Set(Container):
1280 class Set(Container):
1281 """An instance of a Python set."""
1281 """An instance of a Python set."""
1282 klass = set
1282 klass = set
1283
1283
1284 class Tuple(Container):
1284 class Tuple(Container):
1285 """An instance of a Python tuple."""
1285 """An instance of a Python tuple."""
1286 klass = tuple
1286 klass = tuple
1287
1287
1288 def __init__(self, *traits, **metadata):
1288 def __init__(self, *traits, **metadata):
1289 """Tuple(*traits, default_value=None, allow_none=True, **medatata)
1289 """Tuple(*traits, default_value=None, allow_none=True, **medatata)
1290
1290
1291 Create a tuple from a list, set, or tuple.
1291 Create a tuple from a list, set, or tuple.
1292
1292
1293 Create a fixed-type tuple with Traits:
1293 Create a fixed-type tuple with Traits:
1294
1294
1295 ``t = Tuple(Int, Str, CStr)``
1295 ``t = Tuple(Int, Str, CStr)``
1296
1296
1297 would be length 3, with Int,Str,CStr for each element.
1297 would be length 3, with Int,Str,CStr for each element.
1298
1298
1299 If only one arg is given and it is not a Trait, it is taken as
1299 If only one arg is given and it is not a Trait, it is taken as
1300 default_value:
1300 default_value:
1301
1301
1302 ``t = Tuple((1,2,3))``
1302 ``t = Tuple((1,2,3))``
1303
1303
1304 Otherwise, ``default_value`` *must* be specified by keyword.
1304 Otherwise, ``default_value`` *must* be specified by keyword.
1305
1305
1306 Parameters
1306 Parameters
1307 ----------
1307 ----------
1308
1308
1309 *traits : TraitTypes [ optional ]
1309 *traits : TraitTypes [ optional ]
1310 the tsype for restricting the contents of the Tuple. If unspecified,
1310 the tsype for restricting the contents of the Tuple. If unspecified,
1311 types are not checked. If specified, then each positional argument
1311 types are not checked. If specified, then each positional argument
1312 corresponds to an element of the tuple. Tuples defined with traits
1312 corresponds to an element of the tuple. Tuples defined with traits
1313 are of fixed length.
1313 are of fixed length.
1314
1314
1315 default_value : SequenceType [ optional ]
1315 default_value : SequenceType [ optional ]
1316 The default value for the Tuple. Must be list/tuple/set, and
1316 The default value for the Tuple. Must be list/tuple/set, and
1317 will be cast to a tuple. If `traits` are specified, the
1317 will be cast to a tuple. If `traits` are specified, the
1318 `default_value` must conform to the shape and type they specify.
1318 `default_value` must conform to the shape and type they specify.
1319
1319
1320 allow_none : Bool [ default True ]
1320 allow_none : Bool [ default True ]
1321 Whether to allow the value to be None
1321 Whether to allow the value to be None
1322
1322
1323 **metadata : any
1323 **metadata : any
1324 further keys for extensions to the Trait (e.g. config)
1324 further keys for extensions to the Trait (e.g. config)
1325
1325
1326 """
1326 """
1327 default_value = metadata.pop('default_value', None)
1327 default_value = metadata.pop('default_value', None)
1328 allow_none = metadata.pop('allow_none', True)
1328 allow_none = metadata.pop('allow_none', True)
1329
1329
1330 istrait = lambda t: isinstance(t, type) and issubclass(t, TraitType)
1330 istrait = lambda t: isinstance(t, type) and issubclass(t, TraitType)
1331
1331
1332 # allow Tuple((values,)):
1332 # allow Tuple((values,)):
1333 if len(traits) == 1 and default_value is None and not istrait(traits[0]):
1333 if len(traits) == 1 and default_value is None and not istrait(traits[0]):
1334 default_value = traits[0]
1334 default_value = traits[0]
1335 traits = ()
1335 traits = ()
1336
1336
1337 if default_value is None:
1337 if default_value is None:
1338 args = ()
1338 args = ()
1339 elif isinstance(default_value, self._valid_defaults):
1339 elif isinstance(default_value, self._valid_defaults):
1340 args = (default_value,)
1340 args = (default_value,)
1341 else:
1341 else:
1342 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1342 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1343
1343
1344 self._traits = []
1344 self._traits = []
1345 for trait in traits:
1345 for trait in traits:
1346 t = trait()
1346 t = trait()
1347 t.name = 'element'
1347 t.name = 'element'
1348 self._traits.append(t)
1348 self._traits.append(t)
1349
1349
1350 if self._traits and default_value is None:
1350 if self._traits and default_value is None:
1351 # don't allow default to be an empty container if length is specified
1351 # don't allow default to be an empty container if length is specified
1352 args = None
1352 args = None
1353 super(Container,self).__init__(klass=self.klass, args=args,
1353 super(Container,self).__init__(klass=self.klass, args=args,
1354 allow_none=allow_none, **metadata)
1354 allow_none=allow_none, **metadata)
1355
1355
1356 def validate_elements(self, obj, value):
1356 def validate_elements(self, obj, value):
1357 if not self._traits:
1357 if not self._traits:
1358 # nothing to validate
1358 # nothing to validate
1359 return value
1359 return value
1360 if len(value) != len(self._traits):
1360 if len(value) != len(self._traits):
1361 e = "The '%s' trait of %s instance requires %i elements, but a value of %s was specified." \
1361 e = "The '%s' trait of %s instance requires %i elements, but a value of %s was specified." \
1362 % (self.name, class_of(obj), len(self._traits), repr_type(value))
1362 % (self.name, class_of(obj), len(self._traits), repr_type(value))
1363 raise TraitError(e)
1363 raise TraitError(e)
1364
1364
1365 validated = []
1365 validated = []
1366 for t,v in zip(self._traits, value):
1366 for t,v in zip(self._traits, value):
1367 try:
1367 try:
1368 v = t.validate(obj, v)
1368 v = t.validate(obj, v)
1369 except TraitError:
1369 except TraitError:
1370 self.element_error(obj, v, t)
1370 self.element_error(obj, v, t)
1371 else:
1371 else:
1372 validated.append(v)
1372 validated.append(v)
1373 return tuple(validated)
1373 return tuple(validated)
1374
1374
1375
1375
1376 class Dict(Instance):
1376 class Dict(Instance):
1377 """An instance of a Python dict."""
1377 """An instance of a Python dict."""
1378
1378
1379 def __init__(self, default_value=None, allow_none=True, **metadata):
1379 def __init__(self, default_value=None, allow_none=True, **metadata):
1380 """Create a dict trait type from a dict.
1380 """Create a dict trait type from a dict.
1381
1381
1382 The default value is created by doing ``dict(default_value)``,
1382 The default value is created by doing ``dict(default_value)``,
1383 which creates a copy of the ``default_value``.
1383 which creates a copy of the ``default_value``.
1384 """
1384 """
1385 if default_value is None:
1385 if default_value is None:
1386 args = ((),)
1386 args = ((),)
1387 elif isinstance(default_value, dict):
1387 elif isinstance(default_value, dict):
1388 args = (default_value,)
1388 args = (default_value,)
1389 elif isinstance(default_value, SequenceTypes):
1389 elif isinstance(default_value, SequenceTypes):
1390 args = (default_value,)
1390 args = (default_value,)
1391 else:
1391 else:
1392 raise TypeError('default value of Dict was %s' % default_value)
1392 raise TypeError('default value of Dict was %s' % default_value)
1393
1393
1394 super(Dict,self).__init__(klass=dict, args=args,
1394 super(Dict,self).__init__(klass=dict, args=args,
1395 allow_none=allow_none, **metadata)
1395 allow_none=allow_none, **metadata)
1396
1396
1397 class TCPAddress(TraitType):
1397 class TCPAddress(TraitType):
1398 """A trait for an (ip, port) tuple.
1398 """A trait for an (ip, port) tuple.
1399
1399
1400 This allows for both IPv4 IP addresses as well as hostnames.
1400 This allows for both IPv4 IP addresses as well as hostnames.
1401 """
1401 """
1402
1402
1403 default_value = ('127.0.0.1', 0)
1403 default_value = ('127.0.0.1', 0)
1404 info_text = 'an (ip, port) tuple'
1404 info_text = 'an (ip, port) tuple'
1405
1405
1406 def validate(self, obj, value):
1406 def validate(self, obj, value):
1407 if isinstance(value, tuple):
1407 if isinstance(value, tuple):
1408 if len(value) == 2:
1408 if len(value) == 2:
1409 if isinstance(value[0], basestring) and isinstance(value[1], int):
1409 if isinstance(value[0], basestring) and isinstance(value[1], int):
1410 port = value[1]
1410 port = value[1]
1411 if port >= 0 and port <= 65535:
1411 if port >= 0 and port <= 65535:
1412 return value
1412 return value
1413 self.error(obj, value)
1413 self.error(obj, value)
1414
1414
1415 class CRegExp(TraitType):
1415 class CRegExp(TraitType):
1416 """A casting compiled regular expression trait.
1416 """A casting compiled regular expression trait.
1417
1417
1418 Accepts both strings and compiled regular expressions. The resulting
1418 Accepts both strings and compiled regular expressions. The resulting
1419 attribute will be a compiled regular expression."""
1419 attribute will be a compiled regular expression."""
1420
1420
1421 info_text = 'a regular expression'
1421 info_text = 'a regular expression'
1422
1422
1423 def validate(self, obj, value):
1423 def validate(self, obj, value):
1424 try:
1424 try:
1425 return re.compile(value)
1425 return re.compile(value)
1426 except:
1426 except:
1427 self.error(obj, value)
1427 self.error(obj, value)
@@ -1,299 +1,300 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
2 # -*- coding: utf-8 -*-
3 """Setup script for IPython.
3 """Setup script for IPython.
4
4
5 Under Posix environments it works like a typical setup.py script.
5 Under Posix environments it works like a typical setup.py script.
6 Under Windows, the command sdist is not supported, since IPython
6 Under Windows, the command sdist is not supported, since IPython
7 requires utilities which are not available under Windows."""
7 requires utilities which are not available under Windows."""
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (c) 2008-2011, IPython Development Team.
10 # Copyright (c) 2008-2011, IPython Development Team.
11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
14 #
14 #
15 # Distributed under the terms of the Modified BSD License.
15 # Distributed under the terms of the Modified BSD License.
16 #
16 #
17 # The full license is in the file COPYING.txt, distributed with this software.
17 # The full license is in the file COPYING.txt, distributed with this software.
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Minimal Python version sanity check
21 # Minimal Python version sanity check
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 from __future__ import print_function
23 from __future__ import print_function
24
24
25 import sys
25 import sys
26
26
27 # This check is also made in IPython/__init__, don't forget to update both when
27 # This check is also made in IPython/__init__, don't forget to update both when
28 # changing Python version requirements.
28 # changing Python version requirements.
29 #~ if sys.version[0:3] < '2.6':
29 #~ if sys.version[0:3] < '2.6':
30 #~ error = """\
30 #~ error = """\
31 #~ ERROR: 'IPython requires Python Version 2.6 or above.'
31 #~ ERROR: 'IPython requires Python Version 2.6 or above.'
32 #~ Exiting."""
32 #~ Exiting."""
33 #~ print >> sys.stderr, error
33 #~ print >> sys.stderr, error
34 #~ sys.exit(1)
34 #~ sys.exit(1)
35
35
36 PY3 = (sys.version_info[0] >= 3)
36 PY3 = (sys.version_info[0] >= 3)
37
37
38 # At least we're on the python version we need, move on.
38 # At least we're on the python version we need, move on.
39
39
40 #-------------------------------------------------------------------------------
40 #-------------------------------------------------------------------------------
41 # Imports
41 # Imports
42 #-------------------------------------------------------------------------------
42 #-------------------------------------------------------------------------------
43
43
44 # Stdlib imports
44 # Stdlib imports
45 import os
45 import os
46 import shutil
46 import shutil
47
47
48 from glob import glob
48 from glob import glob
49
49
50 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
50 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
51 # update it when the contents of directories change.
51 # update it when the contents of directories change.
52 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
52 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
53
53
54 from distutils.core import setup
54 from distutils.core import setup
55
55
56 # On Python 3, we need distribute (new setuptools) to do the 2to3 conversion
56 # On Python 3, we need distribute (new setuptools) to do the 2to3 conversion
57 if PY3:
57 if PY3:
58 import setuptools
58 import setuptools
59
59
60 # Our own imports
60 # Our own imports
61 from setupbase import target_update
61 from setupbase import target_update
62
62
63 from setupbase import (
63 from setupbase import (
64 setup_args,
64 setup_args,
65 find_packages,
65 find_packages,
66 find_package_data,
66 find_package_data,
67 find_scripts,
67 find_scripts,
68 find_data_files,
68 find_data_files,
69 check_for_dependencies,
69 check_for_dependencies,
70 record_commit_info,
70 record_commit_info,
71 )
71 )
72 from setupext import setupext
72 from setupext import setupext
73
73
74 isfile = os.path.isfile
74 isfile = os.path.isfile
75 pjoin = os.path.join
75 pjoin = os.path.join
76
76
77 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
78 # Function definitions
78 # Function definitions
79 #-----------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
80
80
81 def cleanup():
81 def cleanup():
82 """Clean up the junk left around by the build process"""
82 """Clean up the junk left around by the build process"""
83 if "develop" not in sys.argv:
83 if "develop" not in sys.argv:
84 try:
84 try:
85 shutil.rmtree('ipython.egg-info')
85 shutil.rmtree('ipython.egg-info')
86 except:
86 except:
87 try:
87 try:
88 os.unlink('ipython.egg-info')
88 os.unlink('ipython.egg-info')
89 except:
89 except:
90 pass
90 pass
91
91
92 #-------------------------------------------------------------------------------
92 #-------------------------------------------------------------------------------
93 # Handle OS specific things
93 # Handle OS specific things
94 #-------------------------------------------------------------------------------
94 #-------------------------------------------------------------------------------
95
95
96 if os.name == 'posix':
96 if os.name == 'posix':
97 os_name = 'posix'
97 os_name = 'posix'
98 elif os.name in ['nt','dos']:
98 elif os.name in ['nt','dos']:
99 os_name = 'windows'
99 os_name = 'windows'
100 else:
100 else:
101 print('Unsupported operating system:',os.name)
101 print('Unsupported operating system:',os.name)
102 sys.exit(1)
102 sys.exit(1)
103
103
104 # Under Windows, 'sdist' has not been supported. Now that the docs build with
104 # Under Windows, 'sdist' has not been supported. Now that the docs build with
105 # Sphinx it might work, but let's not turn it on until someone confirms that it
105 # Sphinx it might work, but let's not turn it on until someone confirms that it
106 # actually works.
106 # actually works.
107 if os_name == 'windows' and 'sdist' in sys.argv:
107 if os_name == 'windows' and 'sdist' in sys.argv:
108 print('The sdist command is not available under Windows. Exiting.')
108 print('The sdist command is not available under Windows. Exiting.')
109 sys.exit(1)
109 sys.exit(1)
110
110
111 #-------------------------------------------------------------------------------
111 #-------------------------------------------------------------------------------
112 # Things related to the IPython documentation
112 # Things related to the IPython documentation
113 #-------------------------------------------------------------------------------
113 #-------------------------------------------------------------------------------
114
114
115 # update the manuals when building a source dist
115 # update the manuals when building a source dist
116 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
116 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
117 import textwrap
117 import textwrap
118
118
119 # List of things to be updated. Each entry is a triplet of args for
119 # List of things to be updated. Each entry is a triplet of args for
120 # target_update()
120 # target_update()
121 to_update = [
121 to_update = [
122 # FIXME - Disabled for now: we need to redo an automatic way
122 # FIXME - Disabled for now: we need to redo an automatic way
123 # of generating the magic info inside the rst.
123 # of generating the magic info inside the rst.
124 #('docs/magic.tex',
124 #('docs/magic.tex',
125 #['IPython/Magic.py'],
125 #['IPython/Magic.py'],
126 #"cd doc && ./update_magic.sh" ),
126 #"cd doc && ./update_magic.sh" ),
127
127
128 ('docs/man/ipcluster.1.gz',
128 ('docs/man/ipcluster.1.gz',
129 ['docs/man/ipcluster.1'],
129 ['docs/man/ipcluster.1'],
130 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
130 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
131
131
132 ('docs/man/ipcontroller.1.gz',
132 ('docs/man/ipcontroller.1.gz',
133 ['docs/man/ipcontroller.1'],
133 ['docs/man/ipcontroller.1'],
134 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
134 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
135
135
136 ('docs/man/ipengine.1.gz',
136 ('docs/man/ipengine.1.gz',
137 ['docs/man/ipengine.1'],
137 ['docs/man/ipengine.1'],
138 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
138 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
139
139
140 ('docs/man/iplogger.1.gz',
140 ('docs/man/iplogger.1.gz',
141 ['docs/man/iplogger.1'],
141 ['docs/man/iplogger.1'],
142 'cd docs/man && gzip -9c iplogger.1 > iplogger.1.gz'),
142 'cd docs/man && gzip -9c iplogger.1 > iplogger.1.gz'),
143
143
144 ('docs/man/ipython.1.gz',
144 ('docs/man/ipython.1.gz',
145 ['docs/man/ipython.1'],
145 ['docs/man/ipython.1'],
146 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
146 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
147
147
148 ('docs/man/irunner.1.gz',
148 ('docs/man/irunner.1.gz',
149 ['docs/man/irunner.1'],
149 ['docs/man/irunner.1'],
150 'cd docs/man && gzip -9c irunner.1 > irunner.1.gz'),
150 'cd docs/man && gzip -9c irunner.1 > irunner.1.gz'),
151
151
152 ('docs/man/pycolor.1.gz',
152 ('docs/man/pycolor.1.gz',
153 ['docs/man/pycolor.1'],
153 ['docs/man/pycolor.1'],
154 'cd docs/man && gzip -9c pycolor.1 > pycolor.1.gz'),
154 'cd docs/man && gzip -9c pycolor.1 > pycolor.1.gz'),
155 ]
155 ]
156
156
157
157
158 [ target_update(*t) for t in to_update ]
158 [ target_update(*t) for t in to_update ]
159
159
160 #---------------------------------------------------------------------------
160 #---------------------------------------------------------------------------
161 # Find all the packages, package data, and data_files
161 # Find all the packages, package data, and data_files
162 #---------------------------------------------------------------------------
162 #---------------------------------------------------------------------------
163
163
164 packages = find_packages()
164 packages = find_packages()
165 package_data = find_package_data()
165 package_data = find_package_data()
166 data_files = find_data_files()
166 data_files = find_data_files()
167
167
168 setup_args['packages'] = packages
168 setup_args['packages'] = packages
169 setup_args['package_data'] = package_data
169 setup_args['package_data'] = package_data
170 setup_args['data_files'] = data_files
170 setup_args['data_files'] = data_files
171
171
172 #---------------------------------------------------------------------------
172 #---------------------------------------------------------------------------
173 # custom distutils commands
173 # custom distutils commands
174 #---------------------------------------------------------------------------
174 #---------------------------------------------------------------------------
175 # imports here, so they are after setuptools import if there was one
175 # imports here, so they are after setuptools import if there was one
176 from distutils.command.sdist import sdist
176 from distutils.command.sdist import sdist
177 from distutils.command.upload import upload
177 from distutils.command.upload import upload
178
178
179 class UploadWindowsInstallers(upload):
179 class UploadWindowsInstallers(upload):
180
180
181 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
181 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
182 user_options = upload.user_options + [
182 user_options = upload.user_options + [
183 ('files=', 'f', 'exe file (or glob) to upload')
183 ('files=', 'f', 'exe file (or glob) to upload')
184 ]
184 ]
185 def initialize_options(self):
185 def initialize_options(self):
186 upload.initialize_options(self)
186 upload.initialize_options(self)
187 meta = self.distribution.metadata
187 meta = self.distribution.metadata
188 base = '{name}-{version}'.format(
188 base = '{name}-{version}'.format(
189 name=meta.get_name(),
189 name=meta.get_name(),
190 version=meta.get_version()
190 version=meta.get_version()
191 )
191 )
192 self.files = os.path.join('dist', '%s.*.exe' % base)
192 self.files = os.path.join('dist', '%s.*.exe' % base)
193
193
194 def run(self):
194 def run(self):
195 for dist_file in glob(self.files):
195 for dist_file in glob(self.files):
196 self.upload_file('bdist_wininst', 'any', dist_file)
196 self.upload_file('bdist_wininst', 'any', dist_file)
197
197
198 setup_args['cmdclass'] = {
198 setup_args['cmdclass'] = {
199 'build_py': record_commit_info('IPython'),
199 'build_py': record_commit_info('IPython'),
200 'sdist' : record_commit_info('IPython', sdist),
200 'sdist' : record_commit_info('IPython', sdist),
201 'upload_wininst' : UploadWindowsInstallers,
201 'upload_wininst' : UploadWindowsInstallers,
202 }
202 }
203
203
204 #---------------------------------------------------------------------------
204 #---------------------------------------------------------------------------
205 # Handle scripts, dependencies, and setuptools specific things
205 # Handle scripts, dependencies, and setuptools specific things
206 #---------------------------------------------------------------------------
206 #---------------------------------------------------------------------------
207
207
208 # For some commands, use setuptools. Note that we do NOT list install here!
208 # For some commands, use setuptools. Note that we do NOT list install here!
209 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
209 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
210 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
210 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
211 'bdist', 'bdist_dumb', 'bdist_wininst', 'install_egg_info',
211 'bdist', 'bdist_dumb', 'bdist_wininst', 'install_egg_info',
212 'egg_info', 'easy_install', 'upload',
212 'egg_info', 'easy_install', 'upload',
213 ))
213 ))
214 if sys.platform == 'win32':
214 if sys.platform == 'win32':
215 # Depend on setuptools for install on *Windows only*
215 # Depend on setuptools for install on *Windows only*
216 # If we get script-installation working without setuptools,
216 # If we get script-installation working without setuptools,
217 # then we can back off, but until then use it.
217 # then we can back off, but until then use it.
218 # See Issue #369 on GitHub for more
218 # See Issue #369 on GitHub for more
219 needs_setuptools.add('install')
219 needs_setuptools.add('install')
220
220
221 if len(needs_setuptools.intersection(sys.argv)) > 0:
221 if len(needs_setuptools.intersection(sys.argv)) > 0:
222 import setuptools
222 import setuptools
223
223
224 # This dict is used for passing extra arguments that are setuptools
224 # This dict is used for passing extra arguments that are setuptools
225 # specific to setup
225 # specific to setup
226 setuptools_extra_args = {}
226 setuptools_extra_args = {}
227
227
228 if 'setuptools' in sys.modules:
228 if 'setuptools' in sys.modules:
229 setuptools_extra_args['zip_safe'] = False
229 setuptools_extra_args['zip_safe'] = False
230 setuptools_extra_args['entry_points'] = find_scripts(True)
230 setuptools_extra_args['entry_points'] = find_scripts(True)
231 setup_args['extras_require'] = dict(
231 setup_args['extras_require'] = dict(
232 parallel = 'pyzmq>=2.1.4',
232 parallel = 'pyzmq>=2.1.4',
233 zmq = 'pyzmq>=2.1.4',
233 zmq = 'pyzmq>=2.1.4',
234 doc = 'Sphinx>=0.3',
234 doc = 'Sphinx>=0.3',
235 test = 'nose>=0.10.1',
235 test = 'nose>=0.10.1',
236 notebook = 'tornado>=2.0'
236 notebook = 'tornado>=2.0'
237 )
237 )
238 requires = setup_args.setdefault('install_requires', [])
238 requires = setup_args.setdefault('install_requires', [])
239 setupext.display_status = False
239 setupext.display_status = False
240 if not setupext.check_for_readline():
240 if not setupext.check_for_readline():
241 if sys.platform == 'darwin':
241 if sys.platform == 'darwin':
242 requires.append('readline')
242 requires.append('readline')
243 elif sys.platform.startswith('win'):
243 elif sys.platform.startswith('win'):
244 # Pyreadline 64 bit windows issue solved in versions >=1.7.1
244 # Pyreadline 64 bit windows issue solved in versions >=1.7.1
245 # Also solves issues with some older versions of pyreadline that
245 # Also solves issues with some older versions of pyreadline that
246 # satisfy the unconstrained depdendency.
246 # satisfy the unconstrained depdendency.
247 requires.append('pyreadline>=1.7.1')
247 requires.append('pyreadline>=1.7.1')
248 else:
248 else:
249 pass
249 pass
250 # do we want to install readline here?
250 # do we want to install readline here?
251
251
252 # Script to be run by the windows binary installer after the default setup
252 # Script to be run by the windows binary installer after the default setup
253 # routine, to add shortcuts and similar windows-only things. Windows
253 # routine, to add shortcuts and similar windows-only things. Windows
254 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
254 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
255 # doesn't find them.
255 # doesn't find them.
256 if 'bdist_wininst' in sys.argv:
256 if 'bdist_wininst' in sys.argv:
257 if len(sys.argv) > 2 and \
257 if len(sys.argv) > 2 and \
258 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
258 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
259 print >> sys.stderr, "ERROR: bdist_wininst must be run alone. Exiting."
259 print >> sys.stderr, "ERROR: bdist_wininst must be run alone. Exiting."
260 sys.exit(1)
260 sys.exit(1)
261 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
261 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
262 setup_args['options'] = {"bdist_wininst":
262 setup_args['options'] = {"bdist_wininst":
263 {"install_script":
263 {"install_script":
264 "ipython_win_post_install.py"}}
264 "ipython_win_post_install.py"}}
265
265
266 if PY3:
266 if PY3:
267 setuptools_extra_args['use_2to3'] = True
267 setuptools_extra_args['use_2to3'] = True
268 # we try to make a 2.6, 2.7, and 3.1 to 3.3 python compatible code
268 # we try to make a 2.6, 2.7, and 3.1 to 3.3 python compatible code
269 # so we explicitly disable some 2to3 fixes to be sure we aren't forgetting
269 # so we explicitly disable some 2to3 fixes to be sure we aren't forgetting
270 # anything.
270 # anything.
271 setuptools_extra_args['use_2to3_exclude_fixers'] = [
271 setuptools_extra_args['use_2to3_exclude_fixers'] = [
272 'lib2to3.fixes.fix_except',
273 'lib2to3.fixes.fix_apply',
272 'lib2to3.fixes.fix_apply',
274 'lib2to3.fixes.fix_repr',
273 'lib2to3.fixes.fix_except',
274 'lib2to3.fixes.fix_has_key',
275 'lib2to3.fixes.fix_next',
275 'lib2to3.fixes.fix_next',
276 'lib2to3.fixes.fix_repr',
276 ]
277 ]
277 from setuptools.command.build_py import build_py
278 from setuptools.command.build_py import build_py
278 setup_args['cmdclass'] = {'build_py': record_commit_info('IPython', build_cmd=build_py)}
279 setup_args['cmdclass'] = {'build_py': record_commit_info('IPython', build_cmd=build_py)}
279 setuptools_extra_args['entry_points'] = find_scripts(True, suffix='3')
280 setuptools_extra_args['entry_points'] = find_scripts(True, suffix='3')
280 setuptools._dont_write_bytecode = True
281 setuptools._dont_write_bytecode = True
281 else:
282 else:
282 # If we are running without setuptools, call this function which will
283 # If we are running without setuptools, call this function which will
283 # check for dependencies an inform the user what is needed. This is
284 # check for dependencies an inform the user what is needed. This is
284 # just to make life easy for users.
285 # just to make life easy for users.
285 check_for_dependencies()
286 check_for_dependencies()
286 setup_args['scripts'] = find_scripts(False)
287 setup_args['scripts'] = find_scripts(False)
287
288
288 #---------------------------------------------------------------------------
289 #---------------------------------------------------------------------------
289 # Do the actual setup now
290 # Do the actual setup now
290 #---------------------------------------------------------------------------
291 #---------------------------------------------------------------------------
291
292
292 setup_args.update(setuptools_extra_args)
293 setup_args.update(setuptools_extra_args)
293
294
294 def main():
295 def main():
295 setup(**setup_args)
296 setup(**setup_args)
296 cleanup()
297 cleanup()
297
298
298 if __name__ == '__main__':
299 if __name__ == '__main__':
299 main()
300 main()
General Comments 0
You need to be logged in to leave comments. Login now