##// END OF EJS Templates
conform to pep 3110...
Matthias BUSSONNIER -
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 not self.has_key(k):
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, 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, 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, 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 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, 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 self.alias_table.has_key(name):
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,3009 +1,3009 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Main IPython class."""
2 """Main IPython class."""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
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 from __future__ import with_statement
17 from __future__ import with_statement
18 from __future__ import absolute_import
18 from __future__ import absolute_import
19
19
20 import __builtin__ as builtin_mod
20 import __builtin__ as builtin_mod
21 import __future__
21 import __future__
22 import abc
22 import abc
23 import ast
23 import ast
24 import atexit
24 import atexit
25 import os
25 import os
26 import re
26 import re
27 import runpy
27 import runpy
28 import sys
28 import sys
29 import tempfile
29 import tempfile
30 import types
30 import types
31
31
32 # We need to use nested to support python 2.6, once we move to >=2.7, we can
32 # We need to use nested to support python 2.6, once we move to >=2.7, we can
33 # use the with keyword's new builtin support for nested managers
33 # use the with keyword's new builtin support for nested managers
34 try:
34 try:
35 from contextlib import nested
35 from contextlib import nested
36 except:
36 except:
37 from IPython.utils.nested_context import nested
37 from IPython.utils.nested_context import nested
38
38
39 from IPython.config.configurable import SingletonConfigurable
39 from IPython.config.configurable import SingletonConfigurable
40 from IPython.core import debugger, oinspect
40 from IPython.core import debugger, oinspect
41 from IPython.core import history as ipcorehist
41 from IPython.core import history as ipcorehist
42 from IPython.core import magic
42 from IPython.core import magic
43 from IPython.core import page
43 from IPython.core import page
44 from IPython.core import prefilter
44 from IPython.core import prefilter
45 from IPython.core import shadowns
45 from IPython.core import shadowns
46 from IPython.core import ultratb
46 from IPython.core import ultratb
47 from IPython.core.alias import AliasManager, AliasError
47 from IPython.core.alias import AliasManager, AliasError
48 from IPython.core.autocall import ExitAutocall
48 from IPython.core.autocall import ExitAutocall
49 from IPython.core.builtin_trap import BuiltinTrap
49 from IPython.core.builtin_trap import BuiltinTrap
50 from IPython.core.compilerop import CachingCompiler
50 from IPython.core.compilerop import CachingCompiler
51 from IPython.core.display_trap import DisplayTrap
51 from IPython.core.display_trap import DisplayTrap
52 from IPython.core.displayhook import DisplayHook
52 from IPython.core.displayhook import DisplayHook
53 from IPython.core.displaypub import DisplayPublisher
53 from IPython.core.displaypub import DisplayPublisher
54 from IPython.core.error import UsageError
54 from IPython.core.error import UsageError
55 from IPython.core.extensions import ExtensionManager
55 from IPython.core.extensions import ExtensionManager
56 from IPython.core.fakemodule import FakeModule, init_fakemod_dict
56 from IPython.core.fakemodule import FakeModule, init_fakemod_dict
57 from IPython.core.formatters import DisplayFormatter
57 from IPython.core.formatters import DisplayFormatter
58 from IPython.core.history import HistoryManager
58 from IPython.core.history import HistoryManager
59 from IPython.core.inputsplitter import IPythonInputSplitter, ESC_MAGIC, ESC_MAGIC2
59 from IPython.core.inputsplitter import IPythonInputSplitter, ESC_MAGIC, ESC_MAGIC2
60 from IPython.core.logger import Logger
60 from IPython.core.logger import Logger
61 from IPython.core.macro import Macro
61 from IPython.core.macro import Macro
62 from IPython.core.payload import PayloadManager
62 from IPython.core.payload import PayloadManager
63 from IPython.core.plugin import PluginManager
63 from IPython.core.plugin import PluginManager
64 from IPython.core.prefilter import PrefilterManager
64 from IPython.core.prefilter import PrefilterManager
65 from IPython.core.profiledir import ProfileDir
65 from IPython.core.profiledir import ProfileDir
66 from IPython.core.pylabtools import pylab_activate
66 from IPython.core.pylabtools import pylab_activate
67 from IPython.core.prompts import PromptManager
67 from IPython.core.prompts import PromptManager
68 from IPython.utils import PyColorize
68 from IPython.utils import PyColorize
69 from IPython.utils import io
69 from IPython.utils import io
70 from IPython.utils import py3compat
70 from IPython.utils import py3compat
71 from IPython.utils import openpy
71 from IPython.utils import openpy
72 from IPython.utils.doctestreload import doctest_reload
72 from IPython.utils.doctestreload import doctest_reload
73 from IPython.utils.io import ask_yes_no
73 from IPython.utils.io import ask_yes_no
74 from IPython.utils.ipstruct import Struct
74 from IPython.utils.ipstruct import Struct
75 from IPython.utils.path import get_home_dir, get_ipython_dir, get_py_filename, unquote_filename
75 from IPython.utils.path import get_home_dir, get_ipython_dir, get_py_filename, unquote_filename
76 from IPython.utils.pickleshare import PickleShareDB
76 from IPython.utils.pickleshare import PickleShareDB
77 from IPython.utils.process import system, getoutput
77 from IPython.utils.process import system, getoutput
78 from IPython.utils.strdispatch import StrDispatch
78 from IPython.utils.strdispatch import StrDispatch
79 from IPython.utils.syspathcontext import prepended_to_syspath
79 from IPython.utils.syspathcontext import prepended_to_syspath
80 from IPython.utils.text import (format_screen, LSString, SList,
80 from IPython.utils.text import (format_screen, LSString, SList,
81 DollarFormatter)
81 DollarFormatter)
82 from IPython.utils.traitlets import (Integer, CBool, CaselessStrEnum, Enum,
82 from IPython.utils.traitlets import (Integer, CBool, CaselessStrEnum, Enum,
83 List, Unicode, Instance, Type)
83 List, Unicode, Instance, Type)
84 from IPython.utils.warn import warn, error
84 from IPython.utils.warn import warn, error
85 import IPython.core.hooks
85 import IPython.core.hooks
86
86
87 # FIXME: do this in a function to avoid circular dependencies
87 # FIXME: do this in a function to avoid circular dependencies
88 # A better solution is to remove IPython.parallel.error,
88 # A better solution is to remove IPython.parallel.error,
89 # and place those classes in IPython.core.error.
89 # and place those classes in IPython.core.error.
90
90
91 class RemoteError(Exception):
91 class RemoteError(Exception):
92 pass
92 pass
93
93
94 def _import_remote_error():
94 def _import_remote_error():
95 global RemoteError
95 global RemoteError
96 try:
96 try:
97 from IPython.parallel.error import RemoteError
97 from IPython.parallel.error import RemoteError
98 except:
98 except:
99 pass
99 pass
100
100
101 _import_remote_error()
101 _import_remote_error()
102
102
103 #-----------------------------------------------------------------------------
103 #-----------------------------------------------------------------------------
104 # Globals
104 # Globals
105 #-----------------------------------------------------------------------------
105 #-----------------------------------------------------------------------------
106
106
107 # compiled regexps for autoindent management
107 # compiled regexps for autoindent management
108 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
108 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
109
109
110 #-----------------------------------------------------------------------------
110 #-----------------------------------------------------------------------------
111 # Utilities
111 # Utilities
112 #-----------------------------------------------------------------------------
112 #-----------------------------------------------------------------------------
113
113
114 def softspace(file, newvalue):
114 def softspace(file, newvalue):
115 """Copied from code.py, to remove the dependency"""
115 """Copied from code.py, to remove the dependency"""
116
116
117 oldvalue = 0
117 oldvalue = 0
118 try:
118 try:
119 oldvalue = file.softspace
119 oldvalue = file.softspace
120 except AttributeError:
120 except AttributeError:
121 pass
121 pass
122 try:
122 try:
123 file.softspace = newvalue
123 file.softspace = newvalue
124 except (AttributeError, TypeError):
124 except (AttributeError, TypeError):
125 # "attribute-less object" or "read-only attributes"
125 # "attribute-less object" or "read-only attributes"
126 pass
126 pass
127 return oldvalue
127 return oldvalue
128
128
129
129
130 def no_op(*a, **kw): pass
130 def no_op(*a, **kw): pass
131
131
132 class NoOpContext(object):
132 class NoOpContext(object):
133 def __enter__(self): pass
133 def __enter__(self): pass
134 def __exit__(self, type, value, traceback): pass
134 def __exit__(self, type, value, traceback): pass
135 no_op_context = NoOpContext()
135 no_op_context = NoOpContext()
136
136
137 class SpaceInInput(Exception): pass
137 class SpaceInInput(Exception): pass
138
138
139 class Bunch: pass
139 class Bunch: pass
140
140
141
141
142 def get_default_colors():
142 def get_default_colors():
143 if sys.platform=='darwin':
143 if sys.platform=='darwin':
144 return "LightBG"
144 return "LightBG"
145 elif os.name=='nt':
145 elif os.name=='nt':
146 return 'Linux'
146 return 'Linux'
147 else:
147 else:
148 return 'Linux'
148 return 'Linux'
149
149
150
150
151 class SeparateUnicode(Unicode):
151 class SeparateUnicode(Unicode):
152 """A Unicode subclass to validate separate_in, separate_out, etc.
152 """A Unicode subclass to validate separate_in, separate_out, etc.
153
153
154 This is a Unicode based trait that converts '0'->'' and '\\n'->'\n'.
154 This is a Unicode based trait that converts '0'->'' and '\\n'->'\n'.
155 """
155 """
156
156
157 def validate(self, obj, value):
157 def validate(self, obj, value):
158 if value == '0': value = ''
158 if value == '0': value = ''
159 value = value.replace('\\n','\n')
159 value = value.replace('\\n','\n')
160 return super(SeparateUnicode, self).validate(obj, value)
160 return super(SeparateUnicode, self).validate(obj, value)
161
161
162
162
163 class ReadlineNoRecord(object):
163 class ReadlineNoRecord(object):
164 """Context manager to execute some code, then reload readline history
164 """Context manager to execute some code, then reload readline history
165 so that interactive input to the code doesn't appear when pressing up."""
165 so that interactive input to the code doesn't appear when pressing up."""
166 def __init__(self, shell):
166 def __init__(self, shell):
167 self.shell = shell
167 self.shell = shell
168 self._nested_level = 0
168 self._nested_level = 0
169
169
170 def __enter__(self):
170 def __enter__(self):
171 if self._nested_level == 0:
171 if self._nested_level == 0:
172 try:
172 try:
173 self.orig_length = self.current_length()
173 self.orig_length = self.current_length()
174 self.readline_tail = self.get_readline_tail()
174 self.readline_tail = self.get_readline_tail()
175 except (AttributeError, IndexError): # Can fail with pyreadline
175 except (AttributeError, IndexError): # Can fail with pyreadline
176 self.orig_length, self.readline_tail = 999999, []
176 self.orig_length, self.readline_tail = 999999, []
177 self._nested_level += 1
177 self._nested_level += 1
178
178
179 def __exit__(self, type, value, traceback):
179 def __exit__(self, type, value, traceback):
180 self._nested_level -= 1
180 self._nested_level -= 1
181 if self._nested_level == 0:
181 if self._nested_level == 0:
182 # Try clipping the end if it's got longer
182 # Try clipping the end if it's got longer
183 try:
183 try:
184 e = self.current_length() - self.orig_length
184 e = self.current_length() - self.orig_length
185 if e > 0:
185 if e > 0:
186 for _ in range(e):
186 for _ in range(e):
187 self.shell.readline.remove_history_item(self.orig_length)
187 self.shell.readline.remove_history_item(self.orig_length)
188
188
189 # If it still doesn't match, just reload readline history.
189 # If it still doesn't match, just reload readline history.
190 if self.current_length() != self.orig_length \
190 if self.current_length() != self.orig_length \
191 or self.get_readline_tail() != self.readline_tail:
191 or self.get_readline_tail() != self.readline_tail:
192 self.shell.refill_readline_hist()
192 self.shell.refill_readline_hist()
193 except (AttributeError, IndexError):
193 except (AttributeError, IndexError):
194 pass
194 pass
195 # Returning False will cause exceptions to propagate
195 # Returning False will cause exceptions to propagate
196 return False
196 return False
197
197
198 def current_length(self):
198 def current_length(self):
199 return self.shell.readline.get_current_history_length()
199 return self.shell.readline.get_current_history_length()
200
200
201 def get_readline_tail(self, n=10):
201 def get_readline_tail(self, n=10):
202 """Get the last n items in readline history."""
202 """Get the last n items in readline history."""
203 end = self.shell.readline.get_current_history_length() + 1
203 end = self.shell.readline.get_current_history_length() + 1
204 start = max(end-n, 1)
204 start = max(end-n, 1)
205 ghi = self.shell.readline.get_history_item
205 ghi = self.shell.readline.get_history_item
206 return [ghi(x) for x in range(start, end)]
206 return [ghi(x) for x in range(start, end)]
207
207
208 #-----------------------------------------------------------------------------
208 #-----------------------------------------------------------------------------
209 # Main IPython class
209 # Main IPython class
210 #-----------------------------------------------------------------------------
210 #-----------------------------------------------------------------------------
211
211
212 class InteractiveShell(SingletonConfigurable):
212 class InteractiveShell(SingletonConfigurable):
213 """An enhanced, interactive shell for Python."""
213 """An enhanced, interactive shell for Python."""
214
214
215 _instance = None
215 _instance = None
216
216
217 autocall = Enum((0,1,2), default_value=0, config=True, help=
217 autocall = Enum((0,1,2), default_value=0, config=True, help=
218 """
218 """
219 Make IPython automatically call any callable object even if you didn't
219 Make IPython automatically call any callable object even if you didn't
220 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
220 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
221 automatically. The value can be '0' to disable the feature, '1' for
221 automatically. The value can be '0' to disable the feature, '1' for
222 'smart' autocall, where it is not applied if there are no more
222 'smart' autocall, where it is not applied if there are no more
223 arguments on the line, and '2' for 'full' autocall, where all callable
223 arguments on the line, and '2' for 'full' autocall, where all callable
224 objects are automatically called (even if no arguments are present).
224 objects are automatically called (even if no arguments are present).
225 """
225 """
226 )
226 )
227 # TODO: remove all autoindent logic and put into frontends.
227 # TODO: remove all autoindent logic and put into frontends.
228 # We can't do this yet because even runlines uses the autoindent.
228 # We can't do this yet because even runlines uses the autoindent.
229 autoindent = CBool(True, config=True, help=
229 autoindent = CBool(True, config=True, help=
230 """
230 """
231 Autoindent IPython code entered interactively.
231 Autoindent IPython code entered interactively.
232 """
232 """
233 )
233 )
234 automagic = CBool(True, config=True, help=
234 automagic = CBool(True, config=True, help=
235 """
235 """
236 Enable magic commands to be called without the leading %.
236 Enable magic commands to be called without the leading %.
237 """
237 """
238 )
238 )
239 cache_size = Integer(1000, config=True, help=
239 cache_size = Integer(1000, config=True, help=
240 """
240 """
241 Set the size of the output cache. The default is 1000, you can
241 Set the size of the output cache. The default is 1000, you can
242 change it permanently in your config file. Setting it to 0 completely
242 change it permanently in your config file. Setting it to 0 completely
243 disables the caching system, and the minimum value accepted is 20 (if
243 disables the caching system, and the minimum value accepted is 20 (if
244 you provide a value less than 20, it is reset to 0 and a warning is
244 you provide a value less than 20, it is reset to 0 and a warning is
245 issued). This limit is defined because otherwise you'll spend more
245 issued). This limit is defined because otherwise you'll spend more
246 time re-flushing a too small cache than working
246 time re-flushing a too small cache than working
247 """
247 """
248 )
248 )
249 color_info = CBool(True, config=True, help=
249 color_info = CBool(True, config=True, help=
250 """
250 """
251 Use colors for displaying information about objects. Because this
251 Use colors for displaying information about objects. Because this
252 information is passed through a pager (like 'less'), and some pagers
252 information is passed through a pager (like 'less'), and some pagers
253 get confused with color codes, this capability can be turned off.
253 get confused with color codes, this capability can be turned off.
254 """
254 """
255 )
255 )
256 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
256 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
257 default_value=get_default_colors(), config=True,
257 default_value=get_default_colors(), config=True,
258 help="Set the color scheme (NoColor, Linux, or LightBG)."
258 help="Set the color scheme (NoColor, Linux, or LightBG)."
259 )
259 )
260 colors_force = CBool(False, help=
260 colors_force = CBool(False, help=
261 """
261 """
262 Force use of ANSI color codes, regardless of OS and readline
262 Force use of ANSI color codes, regardless of OS and readline
263 availability.
263 availability.
264 """
264 """
265 # FIXME: This is essentially a hack to allow ZMQShell to show colors
265 # FIXME: This is essentially a hack to allow ZMQShell to show colors
266 # without readline on Win32. When the ZMQ formatting system is
266 # without readline on Win32. When the ZMQ formatting system is
267 # refactored, this should be removed.
267 # refactored, this should be removed.
268 )
268 )
269 debug = CBool(False, config=True)
269 debug = CBool(False, config=True)
270 deep_reload = CBool(False, config=True, help=
270 deep_reload = CBool(False, config=True, help=
271 """
271 """
272 Enable deep (recursive) reloading by default. IPython can use the
272 Enable deep (recursive) reloading by default. IPython can use the
273 deep_reload module which reloads changes in modules recursively (it
273 deep_reload module which reloads changes in modules recursively (it
274 replaces the reload() function, so you don't need to change anything to
274 replaces the reload() function, so you don't need to change anything to
275 use it). deep_reload() forces a full reload of modules whose code may
275 use it). deep_reload() forces a full reload of modules whose code may
276 have changed, which the default reload() function does not. When
276 have changed, which the default reload() function does not. When
277 deep_reload is off, IPython will use the normal reload(), but
277 deep_reload is off, IPython will use the normal reload(), but
278 deep_reload will still be available as dreload().
278 deep_reload will still be available as dreload().
279 """
279 """
280 )
280 )
281 disable_failing_post_execute = CBool(False, config=True,
281 disable_failing_post_execute = CBool(False, config=True,
282 help="Don't call post-execute functions that have failed in the past."
282 help="Don't call post-execute functions that have failed in the past."
283 )
283 )
284 display_formatter = Instance(DisplayFormatter)
284 display_formatter = Instance(DisplayFormatter)
285 displayhook_class = Type(DisplayHook)
285 displayhook_class = Type(DisplayHook)
286 display_pub_class = Type(DisplayPublisher)
286 display_pub_class = Type(DisplayPublisher)
287
287
288 exit_now = CBool(False)
288 exit_now = CBool(False)
289 exiter = Instance(ExitAutocall)
289 exiter = Instance(ExitAutocall)
290 def _exiter_default(self):
290 def _exiter_default(self):
291 return ExitAutocall(self)
291 return ExitAutocall(self)
292 # Monotonically increasing execution counter
292 # Monotonically increasing execution counter
293 execution_count = Integer(1)
293 execution_count = Integer(1)
294 filename = Unicode("<ipython console>")
294 filename = Unicode("<ipython console>")
295 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
295 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
296
296
297 # Input splitter, to split entire cells of input into either individual
297 # Input splitter, to split entire cells of input into either individual
298 # interactive statements or whole blocks.
298 # interactive statements or whole blocks.
299 input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
299 input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
300 (), {})
300 (), {})
301 logstart = CBool(False, config=True, help=
301 logstart = CBool(False, config=True, help=
302 """
302 """
303 Start logging to the default log file.
303 Start logging to the default log file.
304 """
304 """
305 )
305 )
306 logfile = Unicode('', config=True, help=
306 logfile = Unicode('', config=True, help=
307 """
307 """
308 The name of the logfile to use.
308 The name of the logfile to use.
309 """
309 """
310 )
310 )
311 logappend = Unicode('', config=True, help=
311 logappend = Unicode('', config=True, help=
312 """
312 """
313 Start logging to the given file in append mode.
313 Start logging to the given file in append mode.
314 """
314 """
315 )
315 )
316 object_info_string_level = Enum((0,1,2), default_value=0,
316 object_info_string_level = Enum((0,1,2), default_value=0,
317 config=True)
317 config=True)
318 pdb = CBool(False, config=True, help=
318 pdb = CBool(False, config=True, help=
319 """
319 """
320 Automatically call the pdb debugger after every exception.
320 Automatically call the pdb debugger after every exception.
321 """
321 """
322 )
322 )
323 multiline_history = CBool(sys.platform != 'win32', config=True,
323 multiline_history = CBool(sys.platform != 'win32', config=True,
324 help="Save multi-line entries as one entry in readline history"
324 help="Save multi-line entries as one entry in readline history"
325 )
325 )
326
326
327 # deprecated prompt traits:
327 # deprecated prompt traits:
328
328
329 prompt_in1 = Unicode('In [\\#]: ', config=True,
329 prompt_in1 = Unicode('In [\\#]: ', config=True,
330 help="Deprecated, use PromptManager.in_template")
330 help="Deprecated, use PromptManager.in_template")
331 prompt_in2 = Unicode(' .\\D.: ', config=True,
331 prompt_in2 = Unicode(' .\\D.: ', config=True,
332 help="Deprecated, use PromptManager.in2_template")
332 help="Deprecated, use PromptManager.in2_template")
333 prompt_out = Unicode('Out[\\#]: ', config=True,
333 prompt_out = Unicode('Out[\\#]: ', config=True,
334 help="Deprecated, use PromptManager.out_template")
334 help="Deprecated, use PromptManager.out_template")
335 prompts_pad_left = CBool(True, config=True,
335 prompts_pad_left = CBool(True, config=True,
336 help="Deprecated, use PromptManager.justify")
336 help="Deprecated, use PromptManager.justify")
337
337
338 def _prompt_trait_changed(self, name, old, new):
338 def _prompt_trait_changed(self, name, old, new):
339 table = {
339 table = {
340 'prompt_in1' : 'in_template',
340 'prompt_in1' : 'in_template',
341 'prompt_in2' : 'in2_template',
341 'prompt_in2' : 'in2_template',
342 'prompt_out' : 'out_template',
342 'prompt_out' : 'out_template',
343 'prompts_pad_left' : 'justify',
343 'prompts_pad_left' : 'justify',
344 }
344 }
345 warn("InteractiveShell.{name} is deprecated, use PromptManager.{newname}\n".format(
345 warn("InteractiveShell.{name} is deprecated, use PromptManager.{newname}\n".format(
346 name=name, newname=table[name])
346 name=name, newname=table[name])
347 )
347 )
348 # protect against weird cases where self.config may not exist:
348 # protect against weird cases where self.config may not exist:
349 if self.config is not None:
349 if self.config is not None:
350 # propagate to corresponding PromptManager trait
350 # propagate to corresponding PromptManager trait
351 setattr(self.config.PromptManager, table[name], new)
351 setattr(self.config.PromptManager, table[name], new)
352
352
353 _prompt_in1_changed = _prompt_trait_changed
353 _prompt_in1_changed = _prompt_trait_changed
354 _prompt_in2_changed = _prompt_trait_changed
354 _prompt_in2_changed = _prompt_trait_changed
355 _prompt_out_changed = _prompt_trait_changed
355 _prompt_out_changed = _prompt_trait_changed
356 _prompt_pad_left_changed = _prompt_trait_changed
356 _prompt_pad_left_changed = _prompt_trait_changed
357
357
358 show_rewritten_input = CBool(True, config=True,
358 show_rewritten_input = CBool(True, config=True,
359 help="Show rewritten input, e.g. for autocall."
359 help="Show rewritten input, e.g. for autocall."
360 )
360 )
361
361
362 quiet = CBool(False, config=True)
362 quiet = CBool(False, config=True)
363
363
364 history_length = Integer(10000, config=True)
364 history_length = Integer(10000, config=True)
365
365
366 # The readline stuff will eventually be moved to the terminal subclass
366 # The readline stuff will eventually be moved to the terminal subclass
367 # but for now, we can't do that as readline is welded in everywhere.
367 # but for now, we can't do that as readline is welded in everywhere.
368 readline_use = CBool(True, config=True)
368 readline_use = CBool(True, config=True)
369 readline_remove_delims = Unicode('-/~', config=True)
369 readline_remove_delims = Unicode('-/~', config=True)
370 # don't use \M- bindings by default, because they
370 # don't use \M- bindings by default, because they
371 # conflict with 8-bit encodings. See gh-58,gh-88
371 # conflict with 8-bit encodings. See gh-58,gh-88
372 readline_parse_and_bind = List([
372 readline_parse_and_bind = List([
373 'tab: complete',
373 'tab: complete',
374 '"\C-l": clear-screen',
374 '"\C-l": clear-screen',
375 'set show-all-if-ambiguous on',
375 'set show-all-if-ambiguous on',
376 '"\C-o": tab-insert',
376 '"\C-o": tab-insert',
377 '"\C-r": reverse-search-history',
377 '"\C-r": reverse-search-history',
378 '"\C-s": forward-search-history',
378 '"\C-s": forward-search-history',
379 '"\C-p": history-search-backward',
379 '"\C-p": history-search-backward',
380 '"\C-n": history-search-forward',
380 '"\C-n": history-search-forward',
381 '"\e[A": history-search-backward',
381 '"\e[A": history-search-backward',
382 '"\e[B": history-search-forward',
382 '"\e[B": history-search-forward',
383 '"\C-k": kill-line',
383 '"\C-k": kill-line',
384 '"\C-u": unix-line-discard',
384 '"\C-u": unix-line-discard',
385 ], allow_none=False, config=True)
385 ], allow_none=False, config=True)
386
386
387 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none'],
387 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none'],
388 default_value='last_expr', config=True,
388 default_value='last_expr', config=True,
389 help="""
389 help="""
390 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
390 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
391 run interactively (displaying output from expressions).""")
391 run interactively (displaying output from expressions).""")
392
392
393 # TODO: this part of prompt management should be moved to the frontends.
393 # TODO: this part of prompt management should be moved to the frontends.
394 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
394 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
395 separate_in = SeparateUnicode('\n', config=True)
395 separate_in = SeparateUnicode('\n', config=True)
396 separate_out = SeparateUnicode('', config=True)
396 separate_out = SeparateUnicode('', config=True)
397 separate_out2 = SeparateUnicode('', config=True)
397 separate_out2 = SeparateUnicode('', config=True)
398 wildcards_case_sensitive = CBool(True, config=True)
398 wildcards_case_sensitive = CBool(True, config=True)
399 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
399 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
400 default_value='Context', config=True)
400 default_value='Context', config=True)
401
401
402 # Subcomponents of InteractiveShell
402 # Subcomponents of InteractiveShell
403 alias_manager = Instance('IPython.core.alias.AliasManager')
403 alias_manager = Instance('IPython.core.alias.AliasManager')
404 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
404 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
405 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap')
405 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap')
406 display_trap = Instance('IPython.core.display_trap.DisplayTrap')
406 display_trap = Instance('IPython.core.display_trap.DisplayTrap')
407 extension_manager = Instance('IPython.core.extensions.ExtensionManager')
407 extension_manager = Instance('IPython.core.extensions.ExtensionManager')
408 plugin_manager = Instance('IPython.core.plugin.PluginManager')
408 plugin_manager = Instance('IPython.core.plugin.PluginManager')
409 payload_manager = Instance('IPython.core.payload.PayloadManager')
409 payload_manager = Instance('IPython.core.payload.PayloadManager')
410 history_manager = Instance('IPython.core.history.HistoryManager')
410 history_manager = Instance('IPython.core.history.HistoryManager')
411 magics_manager = Instance('IPython.core.magic.MagicsManager')
411 magics_manager = Instance('IPython.core.magic.MagicsManager')
412
412
413 profile_dir = Instance('IPython.core.application.ProfileDir')
413 profile_dir = Instance('IPython.core.application.ProfileDir')
414 @property
414 @property
415 def profile(self):
415 def profile(self):
416 if self.profile_dir is not None:
416 if self.profile_dir is not None:
417 name = os.path.basename(self.profile_dir.location)
417 name = os.path.basename(self.profile_dir.location)
418 return name.replace('profile_','')
418 return name.replace('profile_','')
419
419
420
420
421 # Private interface
421 # Private interface
422 _post_execute = Instance(dict)
422 _post_execute = Instance(dict)
423
423
424 def __init__(self, config=None, ipython_dir=None, profile_dir=None,
424 def __init__(self, config=None, ipython_dir=None, profile_dir=None,
425 user_module=None, user_ns=None,
425 user_module=None, user_ns=None,
426 custom_exceptions=((), None)):
426 custom_exceptions=((), None)):
427
427
428 # This is where traits with a config_key argument are updated
428 # This is where traits with a config_key argument are updated
429 # from the values on config.
429 # from the values on config.
430 super(InteractiveShell, self).__init__(config=config)
430 super(InteractiveShell, self).__init__(config=config)
431 self.configurables = [self]
431 self.configurables = [self]
432
432
433 # These are relatively independent and stateless
433 # These are relatively independent and stateless
434 self.init_ipython_dir(ipython_dir)
434 self.init_ipython_dir(ipython_dir)
435 self.init_profile_dir(profile_dir)
435 self.init_profile_dir(profile_dir)
436 self.init_instance_attrs()
436 self.init_instance_attrs()
437 self.init_environment()
437 self.init_environment()
438
438
439 # Check if we're in a virtualenv, and set up sys.path.
439 # Check if we're in a virtualenv, and set up sys.path.
440 self.init_virtualenv()
440 self.init_virtualenv()
441
441
442 # Create namespaces (user_ns, user_global_ns, etc.)
442 # Create namespaces (user_ns, user_global_ns, etc.)
443 self.init_create_namespaces(user_module, user_ns)
443 self.init_create_namespaces(user_module, user_ns)
444 # This has to be done after init_create_namespaces because it uses
444 # This has to be done after init_create_namespaces because it uses
445 # something in self.user_ns, but before init_sys_modules, which
445 # something in self.user_ns, but before init_sys_modules, which
446 # is the first thing to modify sys.
446 # is the first thing to modify sys.
447 # TODO: When we override sys.stdout and sys.stderr before this class
447 # TODO: When we override sys.stdout and sys.stderr before this class
448 # is created, we are saving the overridden ones here. Not sure if this
448 # is created, we are saving the overridden ones here. Not sure if this
449 # is what we want to do.
449 # is what we want to do.
450 self.save_sys_module_state()
450 self.save_sys_module_state()
451 self.init_sys_modules()
451 self.init_sys_modules()
452
452
453 # While we're trying to have each part of the code directly access what
453 # While we're trying to have each part of the code directly access what
454 # it needs without keeping redundant references to objects, we have too
454 # it needs without keeping redundant references to objects, we have too
455 # much legacy code that expects ip.db to exist.
455 # much legacy code that expects ip.db to exist.
456 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
456 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
457
457
458 self.init_history()
458 self.init_history()
459 self.init_encoding()
459 self.init_encoding()
460 self.init_prefilter()
460 self.init_prefilter()
461
461
462 self.init_syntax_highlighting()
462 self.init_syntax_highlighting()
463 self.init_hooks()
463 self.init_hooks()
464 self.init_pushd_popd_magic()
464 self.init_pushd_popd_magic()
465 # self.init_traceback_handlers use to be here, but we moved it below
465 # self.init_traceback_handlers use to be here, but we moved it below
466 # because it and init_io have to come after init_readline.
466 # because it and init_io have to come after init_readline.
467 self.init_user_ns()
467 self.init_user_ns()
468 self.init_logger()
468 self.init_logger()
469 self.init_alias()
469 self.init_alias()
470 self.init_builtins()
470 self.init_builtins()
471
471
472 # pre_config_initialization
472 # pre_config_initialization
473
473
474 # The next section should contain everything that was in ipmaker.
474 # The next section should contain everything that was in ipmaker.
475 self.init_logstart()
475 self.init_logstart()
476
476
477 # The following was in post_config_initialization
477 # The following was in post_config_initialization
478 self.init_inspector()
478 self.init_inspector()
479 # init_readline() must come before init_io(), because init_io uses
479 # init_readline() must come before init_io(), because init_io uses
480 # readline related things.
480 # readline related things.
481 self.init_readline()
481 self.init_readline()
482 # We save this here in case user code replaces raw_input, but it needs
482 # We save this here in case user code replaces raw_input, but it needs
483 # to be after init_readline(), because PyPy's readline works by replacing
483 # to be after init_readline(), because PyPy's readline works by replacing
484 # raw_input.
484 # raw_input.
485 if py3compat.PY3:
485 if py3compat.PY3:
486 self.raw_input_original = input
486 self.raw_input_original = input
487 else:
487 else:
488 self.raw_input_original = raw_input
488 self.raw_input_original = raw_input
489 # init_completer must come after init_readline, because it needs to
489 # init_completer must come after init_readline, because it needs to
490 # know whether readline is present or not system-wide to configure the
490 # know whether readline is present or not system-wide to configure the
491 # completers, since the completion machinery can now operate
491 # completers, since the completion machinery can now operate
492 # independently of readline (e.g. over the network)
492 # independently of readline (e.g. over the network)
493 self.init_completer()
493 self.init_completer()
494 # TODO: init_io() needs to happen before init_traceback handlers
494 # TODO: init_io() needs to happen before init_traceback handlers
495 # because the traceback handlers hardcode the stdout/stderr streams.
495 # because the traceback handlers hardcode the stdout/stderr streams.
496 # This logic in in debugger.Pdb and should eventually be changed.
496 # This logic in in debugger.Pdb and should eventually be changed.
497 self.init_io()
497 self.init_io()
498 self.init_traceback_handlers(custom_exceptions)
498 self.init_traceback_handlers(custom_exceptions)
499 self.init_prompts()
499 self.init_prompts()
500 self.init_display_formatter()
500 self.init_display_formatter()
501 self.init_display_pub()
501 self.init_display_pub()
502 self.init_displayhook()
502 self.init_displayhook()
503 self.init_reload_doctest()
503 self.init_reload_doctest()
504 self.init_magics()
504 self.init_magics()
505 self.init_pdb()
505 self.init_pdb()
506 self.init_extension_manager()
506 self.init_extension_manager()
507 self.init_plugin_manager()
507 self.init_plugin_manager()
508 self.init_payload()
508 self.init_payload()
509 self.hooks.late_startup_hook()
509 self.hooks.late_startup_hook()
510 atexit.register(self.atexit_operations)
510 atexit.register(self.atexit_operations)
511
511
512 def get_ipython(self):
512 def get_ipython(self):
513 """Return the currently running IPython instance."""
513 """Return the currently running IPython instance."""
514 return self
514 return self
515
515
516 #-------------------------------------------------------------------------
516 #-------------------------------------------------------------------------
517 # Trait changed handlers
517 # Trait changed handlers
518 #-------------------------------------------------------------------------
518 #-------------------------------------------------------------------------
519
519
520 def _ipython_dir_changed(self, name, new):
520 def _ipython_dir_changed(self, name, new):
521 if not os.path.isdir(new):
521 if not os.path.isdir(new):
522 os.makedirs(new, mode = 0777)
522 os.makedirs(new, mode = 0777)
523
523
524 def set_autoindent(self,value=None):
524 def set_autoindent(self,value=None):
525 """Set the autoindent flag, checking for readline support.
525 """Set the autoindent flag, checking for readline support.
526
526
527 If called with no arguments, it acts as a toggle."""
527 If called with no arguments, it acts as a toggle."""
528
528
529 if value != 0 and not self.has_readline:
529 if value != 0 and not self.has_readline:
530 if os.name == 'posix':
530 if os.name == 'posix':
531 warn("The auto-indent feature requires the readline library")
531 warn("The auto-indent feature requires the readline library")
532 self.autoindent = 0
532 self.autoindent = 0
533 return
533 return
534 if value is None:
534 if value is None:
535 self.autoindent = not self.autoindent
535 self.autoindent = not self.autoindent
536 else:
536 else:
537 self.autoindent = value
537 self.autoindent = value
538
538
539 #-------------------------------------------------------------------------
539 #-------------------------------------------------------------------------
540 # init_* methods called by __init__
540 # init_* methods called by __init__
541 #-------------------------------------------------------------------------
541 #-------------------------------------------------------------------------
542
542
543 def init_ipython_dir(self, ipython_dir):
543 def init_ipython_dir(self, ipython_dir):
544 if ipython_dir is not None:
544 if ipython_dir is not None:
545 self.ipython_dir = ipython_dir
545 self.ipython_dir = ipython_dir
546 return
546 return
547
547
548 self.ipython_dir = get_ipython_dir()
548 self.ipython_dir = get_ipython_dir()
549
549
550 def init_profile_dir(self, profile_dir):
550 def init_profile_dir(self, profile_dir):
551 if profile_dir is not None:
551 if profile_dir is not None:
552 self.profile_dir = profile_dir
552 self.profile_dir = profile_dir
553 return
553 return
554 self.profile_dir =\
554 self.profile_dir =\
555 ProfileDir.create_profile_dir_by_name(self.ipython_dir, 'default')
555 ProfileDir.create_profile_dir_by_name(self.ipython_dir, 'default')
556
556
557 def init_instance_attrs(self):
557 def init_instance_attrs(self):
558 self.more = False
558 self.more = False
559
559
560 # command compiler
560 # command compiler
561 self.compile = CachingCompiler()
561 self.compile = CachingCompiler()
562
562
563 # Make an empty namespace, which extension writers can rely on both
563 # Make an empty namespace, which extension writers can rely on both
564 # existing and NEVER being used by ipython itself. This gives them a
564 # existing and NEVER being used by ipython itself. This gives them a
565 # convenient location for storing additional information and state
565 # convenient location for storing additional information and state
566 # their extensions may require, without fear of collisions with other
566 # their extensions may require, without fear of collisions with other
567 # ipython names that may develop later.
567 # ipython names that may develop later.
568 self.meta = Struct()
568 self.meta = Struct()
569
569
570 # Temporary files used for various purposes. Deleted at exit.
570 # Temporary files used for various purposes. Deleted at exit.
571 self.tempfiles = []
571 self.tempfiles = []
572
572
573 # Keep track of readline usage (later set by init_readline)
573 # Keep track of readline usage (later set by init_readline)
574 self.has_readline = False
574 self.has_readline = False
575
575
576 # keep track of where we started running (mainly for crash post-mortem)
576 # keep track of where we started running (mainly for crash post-mortem)
577 # This is not being used anywhere currently.
577 # This is not being used anywhere currently.
578 self.starting_dir = os.getcwdu()
578 self.starting_dir = os.getcwdu()
579
579
580 # Indentation management
580 # Indentation management
581 self.indent_current_nsp = 0
581 self.indent_current_nsp = 0
582
582
583 # Dict to track post-execution functions that have been registered
583 # Dict to track post-execution functions that have been registered
584 self._post_execute = {}
584 self._post_execute = {}
585
585
586 def init_environment(self):
586 def init_environment(self):
587 """Any changes we need to make to the user's environment."""
587 """Any changes we need to make to the user's environment."""
588 pass
588 pass
589
589
590 def init_encoding(self):
590 def init_encoding(self):
591 # Get system encoding at startup time. Certain terminals (like Emacs
591 # Get system encoding at startup time. Certain terminals (like Emacs
592 # under Win32 have it set to None, and we need to have a known valid
592 # under Win32 have it set to None, and we need to have a known valid
593 # encoding to use in the raw_input() method
593 # encoding to use in the raw_input() method
594 try:
594 try:
595 self.stdin_encoding = sys.stdin.encoding or 'ascii'
595 self.stdin_encoding = sys.stdin.encoding or 'ascii'
596 except AttributeError:
596 except AttributeError:
597 self.stdin_encoding = 'ascii'
597 self.stdin_encoding = 'ascii'
598
598
599 def init_syntax_highlighting(self):
599 def init_syntax_highlighting(self):
600 # Python source parser/formatter for syntax highlighting
600 # Python source parser/formatter for syntax highlighting
601 pyformat = PyColorize.Parser().format
601 pyformat = PyColorize.Parser().format
602 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
602 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
603
603
604 def init_pushd_popd_magic(self):
604 def init_pushd_popd_magic(self):
605 # for pushd/popd management
605 # for pushd/popd management
606 self.home_dir = get_home_dir()
606 self.home_dir = get_home_dir()
607
607
608 self.dir_stack = []
608 self.dir_stack = []
609
609
610 def init_logger(self):
610 def init_logger(self):
611 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
611 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
612 logmode='rotate')
612 logmode='rotate')
613
613
614 def init_logstart(self):
614 def init_logstart(self):
615 """Initialize logging in case it was requested at the command line.
615 """Initialize logging in case it was requested at the command line.
616 """
616 """
617 if self.logappend:
617 if self.logappend:
618 self.magic('logstart %s append' % self.logappend)
618 self.magic('logstart %s append' % self.logappend)
619 elif self.logfile:
619 elif self.logfile:
620 self.magic('logstart %' % self.logfile)
620 self.magic('logstart %' % self.logfile)
621 elif self.logstart:
621 elif self.logstart:
622 self.magic('logstart')
622 self.magic('logstart')
623
623
624 def init_builtins(self):
624 def init_builtins(self):
625 # A single, static flag that we set to True. Its presence indicates
625 # A single, static flag that we set to True. Its presence indicates
626 # that an IPython shell has been created, and we make no attempts at
626 # that an IPython shell has been created, and we make no attempts at
627 # removing on exit or representing the existence of more than one
627 # removing on exit or representing the existence of more than one
628 # IPython at a time.
628 # IPython at a time.
629 builtin_mod.__dict__['__IPYTHON__'] = True
629 builtin_mod.__dict__['__IPYTHON__'] = True
630
630
631 # In 0.11 we introduced '__IPYTHON__active' as an integer we'd try to
631 # In 0.11 we introduced '__IPYTHON__active' as an integer we'd try to
632 # manage on enter/exit, but with all our shells it's virtually
632 # manage on enter/exit, but with all our shells it's virtually
633 # impossible to get all the cases right. We're leaving the name in for
633 # impossible to get all the cases right. We're leaving the name in for
634 # those who adapted their codes to check for this flag, but will
634 # those who adapted their codes to check for this flag, but will
635 # eventually remove it after a few more releases.
635 # eventually remove it after a few more releases.
636 builtin_mod.__dict__['__IPYTHON__active'] = \
636 builtin_mod.__dict__['__IPYTHON__active'] = \
637 'Deprecated, check for __IPYTHON__'
637 'Deprecated, check for __IPYTHON__'
638
638
639 self.builtin_trap = BuiltinTrap(shell=self)
639 self.builtin_trap = BuiltinTrap(shell=self)
640
640
641 def init_inspector(self):
641 def init_inspector(self):
642 # Object inspector
642 # Object inspector
643 self.inspector = oinspect.Inspector(oinspect.InspectColors,
643 self.inspector = oinspect.Inspector(oinspect.InspectColors,
644 PyColorize.ANSICodeColors,
644 PyColorize.ANSICodeColors,
645 'NoColor',
645 'NoColor',
646 self.object_info_string_level)
646 self.object_info_string_level)
647
647
648 def init_io(self):
648 def init_io(self):
649 # This will just use sys.stdout and sys.stderr. If you want to
649 # This will just use sys.stdout and sys.stderr. If you want to
650 # override sys.stdout and sys.stderr themselves, you need to do that
650 # override sys.stdout and sys.stderr themselves, you need to do that
651 # *before* instantiating this class, because io holds onto
651 # *before* instantiating this class, because io holds onto
652 # references to the underlying streams.
652 # references to the underlying streams.
653 if sys.platform == 'win32' and self.has_readline:
653 if sys.platform == 'win32' and self.has_readline:
654 io.stdout = io.stderr = io.IOStream(self.readline._outputfile)
654 io.stdout = io.stderr = io.IOStream(self.readline._outputfile)
655 else:
655 else:
656 io.stdout = io.IOStream(sys.stdout)
656 io.stdout = io.IOStream(sys.stdout)
657 io.stderr = io.IOStream(sys.stderr)
657 io.stderr = io.IOStream(sys.stderr)
658
658
659 def init_prompts(self):
659 def init_prompts(self):
660 self.prompt_manager = PromptManager(shell=self, config=self.config)
660 self.prompt_manager = PromptManager(shell=self, config=self.config)
661 self.configurables.append(self.prompt_manager)
661 self.configurables.append(self.prompt_manager)
662 # Set system prompts, so that scripts can decide if they are running
662 # Set system prompts, so that scripts can decide if they are running
663 # interactively.
663 # interactively.
664 sys.ps1 = 'In : '
664 sys.ps1 = 'In : '
665 sys.ps2 = '...: '
665 sys.ps2 = '...: '
666 sys.ps3 = 'Out: '
666 sys.ps3 = 'Out: '
667
667
668 def init_display_formatter(self):
668 def init_display_formatter(self):
669 self.display_formatter = DisplayFormatter(config=self.config)
669 self.display_formatter = DisplayFormatter(config=self.config)
670 self.configurables.append(self.display_formatter)
670 self.configurables.append(self.display_formatter)
671
671
672 def init_display_pub(self):
672 def init_display_pub(self):
673 self.display_pub = self.display_pub_class(config=self.config)
673 self.display_pub = self.display_pub_class(config=self.config)
674 self.configurables.append(self.display_pub)
674 self.configurables.append(self.display_pub)
675
675
676 def init_displayhook(self):
676 def init_displayhook(self):
677 # Initialize displayhook, set in/out prompts and printing system
677 # Initialize displayhook, set in/out prompts and printing system
678 self.displayhook = self.displayhook_class(
678 self.displayhook = self.displayhook_class(
679 config=self.config,
679 config=self.config,
680 shell=self,
680 shell=self,
681 cache_size=self.cache_size,
681 cache_size=self.cache_size,
682 )
682 )
683 self.configurables.append(self.displayhook)
683 self.configurables.append(self.displayhook)
684 # This is a context manager that installs/revmoes the displayhook at
684 # This is a context manager that installs/revmoes the displayhook at
685 # the appropriate time.
685 # the appropriate time.
686 self.display_trap = DisplayTrap(hook=self.displayhook)
686 self.display_trap = DisplayTrap(hook=self.displayhook)
687
687
688 def init_reload_doctest(self):
688 def init_reload_doctest(self):
689 # Do a proper resetting of doctest, including the necessary displayhook
689 # Do a proper resetting of doctest, including the necessary displayhook
690 # monkeypatching
690 # monkeypatching
691 try:
691 try:
692 doctest_reload()
692 doctest_reload()
693 except ImportError:
693 except ImportError:
694 warn("doctest module does not exist.")
694 warn("doctest module does not exist.")
695
695
696 def init_virtualenv(self):
696 def init_virtualenv(self):
697 """Add a virtualenv to sys.path so the user can import modules from it.
697 """Add a virtualenv to sys.path so the user can import modules from it.
698 This isn't perfect: it doesn't use the Python interpreter with which the
698 This isn't perfect: it doesn't use the Python interpreter with which the
699 virtualenv was built, and it ignores the --no-site-packages option. A
699 virtualenv was built, and it ignores the --no-site-packages option. A
700 warning will appear suggesting the user installs IPython in the
700 warning will appear suggesting the user installs IPython in the
701 virtualenv, but for many cases, it probably works well enough.
701 virtualenv, but for many cases, it probably works well enough.
702
702
703 Adapted from code snippets online.
703 Adapted from code snippets online.
704
704
705 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
705 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
706 """
706 """
707 if 'VIRTUAL_ENV' not in os.environ:
707 if 'VIRTUAL_ENV' not in os.environ:
708 # Not in a virtualenv
708 # Not in a virtualenv
709 return
709 return
710
710
711 if sys.executable.startswith(os.environ['VIRTUAL_ENV']):
711 if sys.executable.startswith(os.environ['VIRTUAL_ENV']):
712 # Running properly in the virtualenv, don't need to do anything
712 # Running properly in the virtualenv, don't need to do anything
713 return
713 return
714
714
715 warn("Attempting to work in a virtualenv. If you encounter problems, please "
715 warn("Attempting to work in a virtualenv. If you encounter problems, please "
716 "install IPython inside the virtualenv.\n")
716 "install IPython inside the virtualenv.\n")
717 if sys.platform == "win32":
717 if sys.platform == "win32":
718 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'Lib', 'site-packages')
718 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'Lib', 'site-packages')
719 else:
719 else:
720 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'lib',
720 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'lib',
721 'python%d.%d' % sys.version_info[:2], 'site-packages')
721 'python%d.%d' % sys.version_info[:2], 'site-packages')
722
722
723 import site
723 import site
724 sys.path.insert(0, virtual_env)
724 sys.path.insert(0, virtual_env)
725 site.addsitedir(virtual_env)
725 site.addsitedir(virtual_env)
726
726
727 #-------------------------------------------------------------------------
727 #-------------------------------------------------------------------------
728 # Things related to injections into the sys module
728 # Things related to injections into the sys module
729 #-------------------------------------------------------------------------
729 #-------------------------------------------------------------------------
730
730
731 def save_sys_module_state(self):
731 def save_sys_module_state(self):
732 """Save the state of hooks in the sys module.
732 """Save the state of hooks in the sys module.
733
733
734 This has to be called after self.user_module is created.
734 This has to be called after self.user_module is created.
735 """
735 """
736 self._orig_sys_module_state = {}
736 self._orig_sys_module_state = {}
737 self._orig_sys_module_state['stdin'] = sys.stdin
737 self._orig_sys_module_state['stdin'] = sys.stdin
738 self._orig_sys_module_state['stdout'] = sys.stdout
738 self._orig_sys_module_state['stdout'] = sys.stdout
739 self._orig_sys_module_state['stderr'] = sys.stderr
739 self._orig_sys_module_state['stderr'] = sys.stderr
740 self._orig_sys_module_state['excepthook'] = sys.excepthook
740 self._orig_sys_module_state['excepthook'] = sys.excepthook
741 self._orig_sys_modules_main_name = self.user_module.__name__
741 self._orig_sys_modules_main_name = self.user_module.__name__
742 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
742 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
743
743
744 def restore_sys_module_state(self):
744 def restore_sys_module_state(self):
745 """Restore the state of the sys module."""
745 """Restore the state of the sys module."""
746 try:
746 try:
747 for k, v in self._orig_sys_module_state.iteritems():
747 for k, v in self._orig_sys_module_state.iteritems():
748 setattr(sys, k, v)
748 setattr(sys, k, v)
749 except AttributeError:
749 except AttributeError:
750 pass
750 pass
751 # Reset what what done in self.init_sys_modules
751 # Reset what what done in self.init_sys_modules
752 if self._orig_sys_modules_main_mod is not None:
752 if self._orig_sys_modules_main_mod is not None:
753 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
753 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
754
754
755 #-------------------------------------------------------------------------
755 #-------------------------------------------------------------------------
756 # Things related to hooks
756 # Things related to hooks
757 #-------------------------------------------------------------------------
757 #-------------------------------------------------------------------------
758
758
759 def init_hooks(self):
759 def init_hooks(self):
760 # hooks holds pointers used for user-side customizations
760 # hooks holds pointers used for user-side customizations
761 self.hooks = Struct()
761 self.hooks = Struct()
762
762
763 self.strdispatchers = {}
763 self.strdispatchers = {}
764
764
765 # Set all default hooks, defined in the IPython.hooks module.
765 # Set all default hooks, defined in the IPython.hooks module.
766 hooks = IPython.core.hooks
766 hooks = IPython.core.hooks
767 for hook_name in hooks.__all__:
767 for hook_name in hooks.__all__:
768 # default hooks have priority 100, i.e. low; user hooks should have
768 # default hooks have priority 100, i.e. low; user hooks should have
769 # 0-100 priority
769 # 0-100 priority
770 self.set_hook(hook_name,getattr(hooks,hook_name), 100)
770 self.set_hook(hook_name,getattr(hooks,hook_name), 100)
771
771
772 def set_hook(self,name,hook, priority = 50, str_key = None, re_key = None):
772 def set_hook(self,name,hook, priority = 50, str_key = None, re_key = None):
773 """set_hook(name,hook) -> sets an internal IPython hook.
773 """set_hook(name,hook) -> sets an internal IPython hook.
774
774
775 IPython exposes some of its internal API as user-modifiable hooks. By
775 IPython exposes some of its internal API as user-modifiable hooks. By
776 adding your function to one of these hooks, you can modify IPython's
776 adding your function to one of these hooks, you can modify IPython's
777 behavior to call at runtime your own routines."""
777 behavior to call at runtime your own routines."""
778
778
779 # At some point in the future, this should validate the hook before it
779 # At some point in the future, this should validate the hook before it
780 # accepts it. Probably at least check that the hook takes the number
780 # accepts it. Probably at least check that the hook takes the number
781 # of args it's supposed to.
781 # of args it's supposed to.
782
782
783 f = types.MethodType(hook,self)
783 f = types.MethodType(hook,self)
784
784
785 # check if the hook is for strdispatcher first
785 # check if the hook is for strdispatcher first
786 if str_key is not None:
786 if str_key is not None:
787 sdp = self.strdispatchers.get(name, StrDispatch())
787 sdp = self.strdispatchers.get(name, StrDispatch())
788 sdp.add_s(str_key, f, priority )
788 sdp.add_s(str_key, f, priority )
789 self.strdispatchers[name] = sdp
789 self.strdispatchers[name] = sdp
790 return
790 return
791 if re_key is not None:
791 if re_key is not None:
792 sdp = self.strdispatchers.get(name, StrDispatch())
792 sdp = self.strdispatchers.get(name, StrDispatch())
793 sdp.add_re(re.compile(re_key), f, priority )
793 sdp.add_re(re.compile(re_key), f, priority )
794 self.strdispatchers[name] = sdp
794 self.strdispatchers[name] = sdp
795 return
795 return
796
796
797 dp = getattr(self.hooks, name, None)
797 dp = getattr(self.hooks, name, None)
798 if name not in IPython.core.hooks.__all__:
798 if name not in IPython.core.hooks.__all__:
799 print "Warning! Hook '%s' is not one of %s" % \
799 print "Warning! Hook '%s' is not one of %s" % \
800 (name, IPython.core.hooks.__all__ )
800 (name, IPython.core.hooks.__all__ )
801 if not dp:
801 if not dp:
802 dp = IPython.core.hooks.CommandChainDispatcher()
802 dp = IPython.core.hooks.CommandChainDispatcher()
803
803
804 try:
804 try:
805 dp.add(f,priority)
805 dp.add(f,priority)
806 except AttributeError:
806 except AttributeError:
807 # it was not commandchain, plain old func - replace
807 # it was not commandchain, plain old func - replace
808 dp = f
808 dp = f
809
809
810 setattr(self.hooks,name, dp)
810 setattr(self.hooks,name, dp)
811
811
812 def register_post_execute(self, func):
812 def register_post_execute(self, func):
813 """Register a function for calling after code execution.
813 """Register a function for calling after code execution.
814 """
814 """
815 if not callable(func):
815 if not callable(func):
816 raise ValueError('argument %s must be callable' % func)
816 raise ValueError('argument %s must be callable' % func)
817 self._post_execute[func] = True
817 self._post_execute[func] = True
818
818
819 #-------------------------------------------------------------------------
819 #-------------------------------------------------------------------------
820 # Things related to the "main" module
820 # Things related to the "main" module
821 #-------------------------------------------------------------------------
821 #-------------------------------------------------------------------------
822
822
823 def new_main_mod(self,ns=None):
823 def new_main_mod(self,ns=None):
824 """Return a new 'main' module object for user code execution.
824 """Return a new 'main' module object for user code execution.
825 """
825 """
826 main_mod = self._user_main_module
826 main_mod = self._user_main_module
827 init_fakemod_dict(main_mod,ns)
827 init_fakemod_dict(main_mod,ns)
828 return main_mod
828 return main_mod
829
829
830 def cache_main_mod(self,ns,fname):
830 def cache_main_mod(self,ns,fname):
831 """Cache a main module's namespace.
831 """Cache a main module's namespace.
832
832
833 When scripts are executed via %run, we must keep a reference to the
833 When scripts are executed via %run, we must keep a reference to the
834 namespace of their __main__ module (a FakeModule instance) around so
834 namespace of their __main__ module (a FakeModule instance) around so
835 that Python doesn't clear it, rendering objects defined therein
835 that Python doesn't clear it, rendering objects defined therein
836 useless.
836 useless.
837
837
838 This method keeps said reference in a private dict, keyed by the
838 This method keeps said reference in a private dict, keyed by the
839 absolute path of the module object (which corresponds to the script
839 absolute path of the module object (which corresponds to the script
840 path). This way, for multiple executions of the same script we only
840 path). This way, for multiple executions of the same script we only
841 keep one copy of the namespace (the last one), thus preventing memory
841 keep one copy of the namespace (the last one), thus preventing memory
842 leaks from old references while allowing the objects from the last
842 leaks from old references while allowing the objects from the last
843 execution to be accessible.
843 execution to be accessible.
844
844
845 Note: we can not allow the actual FakeModule instances to be deleted,
845 Note: we can not allow the actual FakeModule instances to be deleted,
846 because of how Python tears down modules (it hard-sets all their
846 because of how Python tears down modules (it hard-sets all their
847 references to None without regard for reference counts). This method
847 references to None without regard for reference counts). This method
848 must therefore make a *copy* of the given namespace, to allow the
848 must therefore make a *copy* of the given namespace, to allow the
849 original module's __dict__ to be cleared and reused.
849 original module's __dict__ to be cleared and reused.
850
850
851
851
852 Parameters
852 Parameters
853 ----------
853 ----------
854 ns : a namespace (a dict, typically)
854 ns : a namespace (a dict, typically)
855
855
856 fname : str
856 fname : str
857 Filename associated with the namespace.
857 Filename associated with the namespace.
858
858
859 Examples
859 Examples
860 --------
860 --------
861
861
862 In [10]: import IPython
862 In [10]: import IPython
863
863
864 In [11]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
864 In [11]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
865
865
866 In [12]: IPython.__file__ in _ip._main_ns_cache
866 In [12]: IPython.__file__ in _ip._main_ns_cache
867 Out[12]: True
867 Out[12]: True
868 """
868 """
869 self._main_ns_cache[os.path.abspath(fname)] = ns.copy()
869 self._main_ns_cache[os.path.abspath(fname)] = ns.copy()
870
870
871 def clear_main_mod_cache(self):
871 def clear_main_mod_cache(self):
872 """Clear the cache of main modules.
872 """Clear the cache of main modules.
873
873
874 Mainly for use by utilities like %reset.
874 Mainly for use by utilities like %reset.
875
875
876 Examples
876 Examples
877 --------
877 --------
878
878
879 In [15]: import IPython
879 In [15]: import IPython
880
880
881 In [16]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
881 In [16]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
882
882
883 In [17]: len(_ip._main_ns_cache) > 0
883 In [17]: len(_ip._main_ns_cache) > 0
884 Out[17]: True
884 Out[17]: True
885
885
886 In [18]: _ip.clear_main_mod_cache()
886 In [18]: _ip.clear_main_mod_cache()
887
887
888 In [19]: len(_ip._main_ns_cache) == 0
888 In [19]: len(_ip._main_ns_cache) == 0
889 Out[19]: True
889 Out[19]: True
890 """
890 """
891 self._main_ns_cache.clear()
891 self._main_ns_cache.clear()
892
892
893 #-------------------------------------------------------------------------
893 #-------------------------------------------------------------------------
894 # Things related to debugging
894 # Things related to debugging
895 #-------------------------------------------------------------------------
895 #-------------------------------------------------------------------------
896
896
897 def init_pdb(self):
897 def init_pdb(self):
898 # Set calling of pdb on exceptions
898 # Set calling of pdb on exceptions
899 # self.call_pdb is a property
899 # self.call_pdb is a property
900 self.call_pdb = self.pdb
900 self.call_pdb = self.pdb
901
901
902 def _get_call_pdb(self):
902 def _get_call_pdb(self):
903 return self._call_pdb
903 return self._call_pdb
904
904
905 def _set_call_pdb(self,val):
905 def _set_call_pdb(self,val):
906
906
907 if val not in (0,1,False,True):
907 if val not in (0,1,False,True):
908 raise ValueError,'new call_pdb value must be boolean'
908 raise ValueError,'new call_pdb value must be boolean'
909
909
910 # store value in instance
910 # store value in instance
911 self._call_pdb = val
911 self._call_pdb = val
912
912
913 # notify the actual exception handlers
913 # notify the actual exception handlers
914 self.InteractiveTB.call_pdb = val
914 self.InteractiveTB.call_pdb = val
915
915
916 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
916 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
917 'Control auto-activation of pdb at exceptions')
917 'Control auto-activation of pdb at exceptions')
918
918
919 def debugger(self,force=False):
919 def debugger(self,force=False):
920 """Call the pydb/pdb debugger.
920 """Call the pydb/pdb debugger.
921
921
922 Keywords:
922 Keywords:
923
923
924 - force(False): by default, this routine checks the instance call_pdb
924 - force(False): by default, this routine checks the instance call_pdb
925 flag and does not actually invoke the debugger if the flag is false.
925 flag and does not actually invoke the debugger if the flag is false.
926 The 'force' option forces the debugger to activate even if the flag
926 The 'force' option forces the debugger to activate even if the flag
927 is false.
927 is false.
928 """
928 """
929
929
930 if not (force or self.call_pdb):
930 if not (force or self.call_pdb):
931 return
931 return
932
932
933 if not hasattr(sys,'last_traceback'):
933 if not hasattr(sys,'last_traceback'):
934 error('No traceback has been produced, nothing to debug.')
934 error('No traceback has been produced, nothing to debug.')
935 return
935 return
936
936
937 # use pydb if available
937 # use pydb if available
938 if debugger.has_pydb:
938 if debugger.has_pydb:
939 from pydb import pm
939 from pydb import pm
940 else:
940 else:
941 # fallback to our internal debugger
941 # fallback to our internal debugger
942 pm = lambda : self.InteractiveTB.debugger(force=True)
942 pm = lambda : self.InteractiveTB.debugger(force=True)
943
943
944 with self.readline_no_record:
944 with self.readline_no_record:
945 pm()
945 pm()
946
946
947 #-------------------------------------------------------------------------
947 #-------------------------------------------------------------------------
948 # Things related to IPython's various namespaces
948 # Things related to IPython's various namespaces
949 #-------------------------------------------------------------------------
949 #-------------------------------------------------------------------------
950 default_user_namespaces = True
950 default_user_namespaces = True
951
951
952 def init_create_namespaces(self, user_module=None, user_ns=None):
952 def init_create_namespaces(self, user_module=None, user_ns=None):
953 # Create the namespace where the user will operate. user_ns is
953 # Create the namespace where the user will operate. user_ns is
954 # normally the only one used, and it is passed to the exec calls as
954 # normally the only one used, and it is passed to the exec calls as
955 # the locals argument. But we do carry a user_global_ns namespace
955 # the locals argument. But we do carry a user_global_ns namespace
956 # given as the exec 'globals' argument, This is useful in embedding
956 # given as the exec 'globals' argument, This is useful in embedding
957 # situations where the ipython shell opens in a context where the
957 # situations where the ipython shell opens in a context where the
958 # distinction between locals and globals is meaningful. For
958 # distinction between locals and globals is meaningful. For
959 # non-embedded contexts, it is just the same object as the user_ns dict.
959 # non-embedded contexts, it is just the same object as the user_ns dict.
960
960
961 # FIXME. For some strange reason, __builtins__ is showing up at user
961 # FIXME. For some strange reason, __builtins__ is showing up at user
962 # level as a dict instead of a module. This is a manual fix, but I
962 # level as a dict instead of a module. This is a manual fix, but I
963 # should really track down where the problem is coming from. Alex
963 # should really track down where the problem is coming from. Alex
964 # Schmolck reported this problem first.
964 # Schmolck reported this problem first.
965
965
966 # A useful post by Alex Martelli on this topic:
966 # A useful post by Alex Martelli on this topic:
967 # Re: inconsistent value from __builtins__
967 # Re: inconsistent value from __builtins__
968 # Von: Alex Martelli <aleaxit@yahoo.com>
968 # Von: Alex Martelli <aleaxit@yahoo.com>
969 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
969 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
970 # Gruppen: comp.lang.python
970 # Gruppen: comp.lang.python
971
971
972 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
972 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
973 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
973 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
974 # > <type 'dict'>
974 # > <type 'dict'>
975 # > >>> print type(__builtins__)
975 # > >>> print type(__builtins__)
976 # > <type 'module'>
976 # > <type 'module'>
977 # > Is this difference in return value intentional?
977 # > Is this difference in return value intentional?
978
978
979 # Well, it's documented that '__builtins__' can be either a dictionary
979 # Well, it's documented that '__builtins__' can be either a dictionary
980 # or a module, and it's been that way for a long time. Whether it's
980 # or a module, and it's been that way for a long time. Whether it's
981 # intentional (or sensible), I don't know. In any case, the idea is
981 # intentional (or sensible), I don't know. In any case, the idea is
982 # that if you need to access the built-in namespace directly, you
982 # that if you need to access the built-in namespace directly, you
983 # should start with "import __builtin__" (note, no 's') which will
983 # should start with "import __builtin__" (note, no 's') which will
984 # definitely give you a module. Yeah, it's somewhat confusing:-(.
984 # definitely give you a module. Yeah, it's somewhat confusing:-(.
985
985
986 # These routines return a properly built module and dict as needed by
986 # These routines return a properly built module and dict as needed by
987 # the rest of the code, and can also be used by extension writers to
987 # the rest of the code, and can also be used by extension writers to
988 # generate properly initialized namespaces.
988 # generate properly initialized namespaces.
989 if (user_ns is not None) or (user_module is not None):
989 if (user_ns is not None) or (user_module is not None):
990 self.default_user_namespaces = False
990 self.default_user_namespaces = False
991 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
991 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
992
992
993 # A record of hidden variables we have added to the user namespace, so
993 # A record of hidden variables we have added to the user namespace, so
994 # we can list later only variables defined in actual interactive use.
994 # we can list later only variables defined in actual interactive use.
995 self.user_ns_hidden = set()
995 self.user_ns_hidden = set()
996
996
997 # Now that FakeModule produces a real module, we've run into a nasty
997 # Now that FakeModule produces a real module, we've run into a nasty
998 # problem: after script execution (via %run), the module where the user
998 # problem: after script execution (via %run), the module where the user
999 # code ran is deleted. Now that this object is a true module (needed
999 # code ran is deleted. Now that this object is a true module (needed
1000 # so docetst and other tools work correctly), the Python module
1000 # so docetst and other tools work correctly), the Python module
1001 # teardown mechanism runs over it, and sets to None every variable
1001 # teardown mechanism runs over it, and sets to None every variable
1002 # present in that module. Top-level references to objects from the
1002 # present in that module. Top-level references to objects from the
1003 # script survive, because the user_ns is updated with them. However,
1003 # script survive, because the user_ns is updated with them. However,
1004 # calling functions defined in the script that use other things from
1004 # calling functions defined in the script that use other things from
1005 # the script will fail, because the function's closure had references
1005 # the script will fail, because the function's closure had references
1006 # to the original objects, which are now all None. So we must protect
1006 # to the original objects, which are now all None. So we must protect
1007 # these modules from deletion by keeping a cache.
1007 # these modules from deletion by keeping a cache.
1008 #
1008 #
1009 # To avoid keeping stale modules around (we only need the one from the
1009 # To avoid keeping stale modules around (we only need the one from the
1010 # last run), we use a dict keyed with the full path to the script, so
1010 # last run), we use a dict keyed with the full path to the script, so
1011 # only the last version of the module is held in the cache. Note,
1011 # only the last version of the module is held in the cache. Note,
1012 # however, that we must cache the module *namespace contents* (their
1012 # however, that we must cache the module *namespace contents* (their
1013 # __dict__). Because if we try to cache the actual modules, old ones
1013 # __dict__). Because if we try to cache the actual modules, old ones
1014 # (uncached) could be destroyed while still holding references (such as
1014 # (uncached) could be destroyed while still holding references (such as
1015 # those held by GUI objects that tend to be long-lived)>
1015 # those held by GUI objects that tend to be long-lived)>
1016 #
1016 #
1017 # The %reset command will flush this cache. See the cache_main_mod()
1017 # The %reset command will flush this cache. See the cache_main_mod()
1018 # and clear_main_mod_cache() methods for details on use.
1018 # and clear_main_mod_cache() methods for details on use.
1019
1019
1020 # This is the cache used for 'main' namespaces
1020 # This is the cache used for 'main' namespaces
1021 self._main_ns_cache = {}
1021 self._main_ns_cache = {}
1022 # And this is the single instance of FakeModule whose __dict__ we keep
1022 # And this is the single instance of FakeModule whose __dict__ we keep
1023 # copying and clearing for reuse on each %run
1023 # copying and clearing for reuse on each %run
1024 self._user_main_module = FakeModule()
1024 self._user_main_module = FakeModule()
1025
1025
1026 # A table holding all the namespaces IPython deals with, so that
1026 # A table holding all the namespaces IPython deals with, so that
1027 # introspection facilities can search easily.
1027 # introspection facilities can search easily.
1028 self.ns_table = {'user_global':self.user_module.__dict__,
1028 self.ns_table = {'user_global':self.user_module.__dict__,
1029 'user_local':self.user_ns,
1029 'user_local':self.user_ns,
1030 'builtin':builtin_mod.__dict__
1030 'builtin':builtin_mod.__dict__
1031 }
1031 }
1032
1032
1033 @property
1033 @property
1034 def user_global_ns(self):
1034 def user_global_ns(self):
1035 return self.user_module.__dict__
1035 return self.user_module.__dict__
1036
1036
1037 def prepare_user_module(self, user_module=None, user_ns=None):
1037 def prepare_user_module(self, user_module=None, user_ns=None):
1038 """Prepare the module and namespace in which user code will be run.
1038 """Prepare the module and namespace in which user code will be run.
1039
1039
1040 When IPython is started normally, both parameters are None: a new module
1040 When IPython is started normally, both parameters are None: a new module
1041 is created automatically, and its __dict__ used as the namespace.
1041 is created automatically, and its __dict__ used as the namespace.
1042
1042
1043 If only user_module is provided, its __dict__ is used as the namespace.
1043 If only user_module is provided, its __dict__ is used as the namespace.
1044 If only user_ns is provided, a dummy module is created, and user_ns
1044 If only user_ns is provided, a dummy module is created, and user_ns
1045 becomes the global namespace. If both are provided (as they may be
1045 becomes the global namespace. If both are provided (as they may be
1046 when embedding), user_ns is the local namespace, and user_module
1046 when embedding), user_ns is the local namespace, and user_module
1047 provides the global namespace.
1047 provides the global namespace.
1048
1048
1049 Parameters
1049 Parameters
1050 ----------
1050 ----------
1051 user_module : module, optional
1051 user_module : module, optional
1052 The current user module in which IPython is being run. If None,
1052 The current user module in which IPython is being run. If None,
1053 a clean module will be created.
1053 a clean module will be created.
1054 user_ns : dict, optional
1054 user_ns : dict, optional
1055 A namespace in which to run interactive commands.
1055 A namespace in which to run interactive commands.
1056
1056
1057 Returns
1057 Returns
1058 -------
1058 -------
1059 A tuple of user_module and user_ns, each properly initialised.
1059 A tuple of user_module and user_ns, each properly initialised.
1060 """
1060 """
1061 if user_module is None and user_ns is not None:
1061 if user_module is None and user_ns is not None:
1062 user_ns.setdefault("__name__", "__main__")
1062 user_ns.setdefault("__name__", "__main__")
1063 class DummyMod(object):
1063 class DummyMod(object):
1064 "A dummy module used for IPython's interactive namespace."
1064 "A dummy module used for IPython's interactive namespace."
1065 pass
1065 pass
1066 user_module = DummyMod()
1066 user_module = DummyMod()
1067 user_module.__dict__ = user_ns
1067 user_module.__dict__ = user_ns
1068
1068
1069 if user_module is None:
1069 if user_module is None:
1070 user_module = types.ModuleType("__main__",
1070 user_module = types.ModuleType("__main__",
1071 doc="Automatically created module for IPython interactive environment")
1071 doc="Automatically created module for IPython interactive environment")
1072
1072
1073 # We must ensure that __builtin__ (without the final 's') is always
1073 # We must ensure that __builtin__ (without the final 's') is always
1074 # available and pointing to the __builtin__ *module*. For more details:
1074 # available and pointing to the __builtin__ *module*. For more details:
1075 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1075 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1076 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1076 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1077 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1077 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1078
1078
1079 if user_ns is None:
1079 if user_ns is None:
1080 user_ns = user_module.__dict__
1080 user_ns = user_module.__dict__
1081
1081
1082 return user_module, user_ns
1082 return user_module, user_ns
1083
1083
1084 def init_sys_modules(self):
1084 def init_sys_modules(self):
1085 # We need to insert into sys.modules something that looks like a
1085 # We need to insert into sys.modules something that looks like a
1086 # module but which accesses the IPython namespace, for shelve and
1086 # module but which accesses the IPython namespace, for shelve and
1087 # pickle to work interactively. Normally they rely on getting
1087 # pickle to work interactively. Normally they rely on getting
1088 # everything out of __main__, but for embedding purposes each IPython
1088 # everything out of __main__, but for embedding purposes each IPython
1089 # instance has its own private namespace, so we can't go shoving
1089 # instance has its own private namespace, so we can't go shoving
1090 # everything into __main__.
1090 # everything into __main__.
1091
1091
1092 # note, however, that we should only do this for non-embedded
1092 # note, however, that we should only do this for non-embedded
1093 # ipythons, which really mimic the __main__.__dict__ with their own
1093 # ipythons, which really mimic the __main__.__dict__ with their own
1094 # namespace. Embedded instances, on the other hand, should not do
1094 # namespace. Embedded instances, on the other hand, should not do
1095 # this because they need to manage the user local/global namespaces
1095 # this because they need to manage the user local/global namespaces
1096 # only, but they live within a 'normal' __main__ (meaning, they
1096 # only, but they live within a 'normal' __main__ (meaning, they
1097 # shouldn't overtake the execution environment of the script they're
1097 # shouldn't overtake the execution environment of the script they're
1098 # embedded in).
1098 # embedded in).
1099
1099
1100 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1100 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1101 main_name = self.user_module.__name__
1101 main_name = self.user_module.__name__
1102 sys.modules[main_name] = self.user_module
1102 sys.modules[main_name] = self.user_module
1103
1103
1104 def init_user_ns(self):
1104 def init_user_ns(self):
1105 """Initialize all user-visible namespaces to their minimum defaults.
1105 """Initialize all user-visible namespaces to their minimum defaults.
1106
1106
1107 Certain history lists are also initialized here, as they effectively
1107 Certain history lists are also initialized here, as they effectively
1108 act as user namespaces.
1108 act as user namespaces.
1109
1109
1110 Notes
1110 Notes
1111 -----
1111 -----
1112 All data structures here are only filled in, they are NOT reset by this
1112 All data structures here are only filled in, they are NOT reset by this
1113 method. If they were not empty before, data will simply be added to
1113 method. If they were not empty before, data will simply be added to
1114 therm.
1114 therm.
1115 """
1115 """
1116 # This function works in two parts: first we put a few things in
1116 # This function works in two parts: first we put a few things in
1117 # user_ns, and we sync that contents into user_ns_hidden so that these
1117 # user_ns, and we sync that contents into user_ns_hidden so that these
1118 # initial variables aren't shown by %who. After the sync, we add the
1118 # initial variables aren't shown by %who. After the sync, we add the
1119 # rest of what we *do* want the user to see with %who even on a new
1119 # rest of what we *do* want the user to see with %who even on a new
1120 # session (probably nothing, so theye really only see their own stuff)
1120 # session (probably nothing, so theye really only see their own stuff)
1121
1121
1122 # The user dict must *always* have a __builtin__ reference to the
1122 # The user dict must *always* have a __builtin__ reference to the
1123 # Python standard __builtin__ namespace, which must be imported.
1123 # Python standard __builtin__ namespace, which must be imported.
1124 # This is so that certain operations in prompt evaluation can be
1124 # This is so that certain operations in prompt evaluation can be
1125 # reliably executed with builtins. Note that we can NOT use
1125 # reliably executed with builtins. Note that we can NOT use
1126 # __builtins__ (note the 's'), because that can either be a dict or a
1126 # __builtins__ (note the 's'), because that can either be a dict or a
1127 # module, and can even mutate at runtime, depending on the context
1127 # module, and can even mutate at runtime, depending on the context
1128 # (Python makes no guarantees on it). In contrast, __builtin__ is
1128 # (Python makes no guarantees on it). In contrast, __builtin__ is
1129 # always a module object, though it must be explicitly imported.
1129 # always a module object, though it must be explicitly imported.
1130
1130
1131 # For more details:
1131 # For more details:
1132 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1132 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1133 ns = dict()
1133 ns = dict()
1134
1134
1135 # Put 'help' in the user namespace
1135 # Put 'help' in the user namespace
1136 try:
1136 try:
1137 from site import _Helper
1137 from site import _Helper
1138 ns['help'] = _Helper()
1138 ns['help'] = _Helper()
1139 except ImportError:
1139 except ImportError:
1140 warn('help() not available - check site.py')
1140 warn('help() not available - check site.py')
1141
1141
1142 # make global variables for user access to the histories
1142 # make global variables for user access to the histories
1143 ns['_ih'] = self.history_manager.input_hist_parsed
1143 ns['_ih'] = self.history_manager.input_hist_parsed
1144 ns['_oh'] = self.history_manager.output_hist
1144 ns['_oh'] = self.history_manager.output_hist
1145 ns['_dh'] = self.history_manager.dir_hist
1145 ns['_dh'] = self.history_manager.dir_hist
1146
1146
1147 ns['_sh'] = shadowns
1147 ns['_sh'] = shadowns
1148
1148
1149 # user aliases to input and output histories. These shouldn't show up
1149 # user aliases to input and output histories. These shouldn't show up
1150 # in %who, as they can have very large reprs.
1150 # in %who, as they can have very large reprs.
1151 ns['In'] = self.history_manager.input_hist_parsed
1151 ns['In'] = self.history_manager.input_hist_parsed
1152 ns['Out'] = self.history_manager.output_hist
1152 ns['Out'] = self.history_manager.output_hist
1153
1153
1154 # Store myself as the public api!!!
1154 # Store myself as the public api!!!
1155 ns['get_ipython'] = self.get_ipython
1155 ns['get_ipython'] = self.get_ipython
1156
1156
1157 ns['exit'] = self.exiter
1157 ns['exit'] = self.exiter
1158 ns['quit'] = self.exiter
1158 ns['quit'] = self.exiter
1159
1159
1160 # Sync what we've added so far to user_ns_hidden so these aren't seen
1160 # Sync what we've added so far to user_ns_hidden so these aren't seen
1161 # by %who
1161 # by %who
1162 self.user_ns_hidden.update(ns)
1162 self.user_ns_hidden.update(ns)
1163
1163
1164 # Anything put into ns now would show up in %who. Think twice before
1164 # Anything put into ns now would show up in %who. Think twice before
1165 # putting anything here, as we really want %who to show the user their
1165 # putting anything here, as we really want %who to show the user their
1166 # stuff, not our variables.
1166 # stuff, not our variables.
1167
1167
1168 # Finally, update the real user's namespace
1168 # Finally, update the real user's namespace
1169 self.user_ns.update(ns)
1169 self.user_ns.update(ns)
1170
1170
1171 @property
1171 @property
1172 def all_ns_refs(self):
1172 def all_ns_refs(self):
1173 """Get a list of references to all the namespace dictionaries in which
1173 """Get a list of references to all the namespace dictionaries in which
1174 IPython might store a user-created object.
1174 IPython might store a user-created object.
1175
1175
1176 Note that this does not include the displayhook, which also caches
1176 Note that this does not include the displayhook, which also caches
1177 objects from the output."""
1177 objects from the output."""
1178 return [self.user_ns, self.user_global_ns,
1178 return [self.user_ns, self.user_global_ns,
1179 self._user_main_module.__dict__] + self._main_ns_cache.values()
1179 self._user_main_module.__dict__] + self._main_ns_cache.values()
1180
1180
1181 def reset(self, new_session=True):
1181 def reset(self, new_session=True):
1182 """Clear all internal namespaces, and attempt to release references to
1182 """Clear all internal namespaces, and attempt to release references to
1183 user objects.
1183 user objects.
1184
1184
1185 If new_session is True, a new history session will be opened.
1185 If new_session is True, a new history session will be opened.
1186 """
1186 """
1187 # Clear histories
1187 # Clear histories
1188 self.history_manager.reset(new_session)
1188 self.history_manager.reset(new_session)
1189 # Reset counter used to index all histories
1189 # Reset counter used to index all histories
1190 if new_session:
1190 if new_session:
1191 self.execution_count = 1
1191 self.execution_count = 1
1192
1192
1193 # Flush cached output items
1193 # Flush cached output items
1194 if self.displayhook.do_full_cache:
1194 if self.displayhook.do_full_cache:
1195 self.displayhook.flush()
1195 self.displayhook.flush()
1196
1196
1197 # The main execution namespaces must be cleared very carefully,
1197 # The main execution namespaces must be cleared very carefully,
1198 # skipping the deletion of the builtin-related keys, because doing so
1198 # skipping the deletion of the builtin-related keys, because doing so
1199 # would cause errors in many object's __del__ methods.
1199 # would cause errors in many object's __del__ methods.
1200 if self.user_ns is not self.user_global_ns:
1200 if self.user_ns is not self.user_global_ns:
1201 self.user_ns.clear()
1201 self.user_ns.clear()
1202 ns = self.user_global_ns
1202 ns = self.user_global_ns
1203 drop_keys = set(ns.keys())
1203 drop_keys = set(ns.keys())
1204 drop_keys.discard('__builtin__')
1204 drop_keys.discard('__builtin__')
1205 drop_keys.discard('__builtins__')
1205 drop_keys.discard('__builtins__')
1206 drop_keys.discard('__name__')
1206 drop_keys.discard('__name__')
1207 for k in drop_keys:
1207 for k in drop_keys:
1208 del ns[k]
1208 del ns[k]
1209
1209
1210 self.user_ns_hidden.clear()
1210 self.user_ns_hidden.clear()
1211
1211
1212 # Restore the user namespaces to minimal usability
1212 # Restore the user namespaces to minimal usability
1213 self.init_user_ns()
1213 self.init_user_ns()
1214
1214
1215 # Restore the default and user aliases
1215 # Restore the default and user aliases
1216 self.alias_manager.clear_aliases()
1216 self.alias_manager.clear_aliases()
1217 self.alias_manager.init_aliases()
1217 self.alias_manager.init_aliases()
1218
1218
1219 # Flush the private list of module references kept for script
1219 # Flush the private list of module references kept for script
1220 # execution protection
1220 # execution protection
1221 self.clear_main_mod_cache()
1221 self.clear_main_mod_cache()
1222
1222
1223 # Clear out the namespace from the last %run
1223 # Clear out the namespace from the last %run
1224 self.new_main_mod()
1224 self.new_main_mod()
1225
1225
1226 def del_var(self, varname, by_name=False):
1226 def del_var(self, varname, by_name=False):
1227 """Delete a variable from the various namespaces, so that, as
1227 """Delete a variable from the various namespaces, so that, as
1228 far as possible, we're not keeping any hidden references to it.
1228 far as possible, we're not keeping any hidden references to it.
1229
1229
1230 Parameters
1230 Parameters
1231 ----------
1231 ----------
1232 varname : str
1232 varname : str
1233 The name of the variable to delete.
1233 The name of the variable to delete.
1234 by_name : bool
1234 by_name : bool
1235 If True, delete variables with the given name in each
1235 If True, delete variables with the given name in each
1236 namespace. If False (default), find the variable in the user
1236 namespace. If False (default), find the variable in the user
1237 namespace, and delete references to it.
1237 namespace, and delete references to it.
1238 """
1238 """
1239 if varname in ('__builtin__', '__builtins__'):
1239 if varname in ('__builtin__', '__builtins__'):
1240 raise ValueError("Refusing to delete %s" % varname)
1240 raise ValueError("Refusing to delete %s" % varname)
1241
1241
1242 ns_refs = self.all_ns_refs
1242 ns_refs = self.all_ns_refs
1243
1243
1244 if by_name: # Delete by name
1244 if by_name: # Delete by name
1245 for ns in ns_refs:
1245 for ns in ns_refs:
1246 try:
1246 try:
1247 del ns[varname]
1247 del ns[varname]
1248 except KeyError:
1248 except KeyError:
1249 pass
1249 pass
1250 else: # Delete by object
1250 else: # Delete by object
1251 try:
1251 try:
1252 obj = self.user_ns[varname]
1252 obj = self.user_ns[varname]
1253 except KeyError:
1253 except KeyError:
1254 raise NameError("name '%s' is not defined" % varname)
1254 raise NameError("name '%s' is not defined" % varname)
1255 # Also check in output history
1255 # Also check in output history
1256 ns_refs.append(self.history_manager.output_hist)
1256 ns_refs.append(self.history_manager.output_hist)
1257 for ns in ns_refs:
1257 for ns in ns_refs:
1258 to_delete = [n for n, o in ns.iteritems() if o is obj]
1258 to_delete = [n for n, o in ns.iteritems() if o is obj]
1259 for name in to_delete:
1259 for name in to_delete:
1260 del ns[name]
1260 del ns[name]
1261
1261
1262 # displayhook keeps extra references, but not in a dictionary
1262 # displayhook keeps extra references, but not in a dictionary
1263 for name in ('_', '__', '___'):
1263 for name in ('_', '__', '___'):
1264 if getattr(self.displayhook, name) is obj:
1264 if getattr(self.displayhook, name) is obj:
1265 setattr(self.displayhook, name, None)
1265 setattr(self.displayhook, name, None)
1266
1266
1267 def reset_selective(self, regex=None):
1267 def reset_selective(self, regex=None):
1268 """Clear selective variables from internal namespaces based on a
1268 """Clear selective variables from internal namespaces based on a
1269 specified regular expression.
1269 specified regular expression.
1270
1270
1271 Parameters
1271 Parameters
1272 ----------
1272 ----------
1273 regex : string or compiled pattern, optional
1273 regex : string or compiled pattern, optional
1274 A regular expression pattern that will be used in searching
1274 A regular expression pattern that will be used in searching
1275 variable names in the users namespaces.
1275 variable names in the users namespaces.
1276 """
1276 """
1277 if regex is not None:
1277 if regex is not None:
1278 try:
1278 try:
1279 m = re.compile(regex)
1279 m = re.compile(regex)
1280 except TypeError:
1280 except TypeError:
1281 raise TypeError('regex must be a string or compiled pattern')
1281 raise TypeError('regex must be a string or compiled pattern')
1282 # Search for keys in each namespace that match the given regex
1282 # Search for keys in each namespace that match the given regex
1283 # If a match is found, delete the key/value pair.
1283 # If a match is found, delete the key/value pair.
1284 for ns in self.all_ns_refs:
1284 for ns in self.all_ns_refs:
1285 for var in ns:
1285 for var in ns:
1286 if m.search(var):
1286 if m.search(var):
1287 del ns[var]
1287 del ns[var]
1288
1288
1289 def push(self, variables, interactive=True):
1289 def push(self, variables, interactive=True):
1290 """Inject a group of variables into the IPython user namespace.
1290 """Inject a group of variables into the IPython user namespace.
1291
1291
1292 Parameters
1292 Parameters
1293 ----------
1293 ----------
1294 variables : dict, str or list/tuple of str
1294 variables : dict, str or list/tuple of str
1295 The variables to inject into the user's namespace. If a dict, a
1295 The variables to inject into the user's namespace. If a dict, a
1296 simple update is done. If a str, the string is assumed to have
1296 simple update is done. If a str, the string is assumed to have
1297 variable names separated by spaces. A list/tuple of str can also
1297 variable names separated by spaces. A list/tuple of str can also
1298 be used to give the variable names. If just the variable names are
1298 be used to give the variable names. If just the variable names are
1299 give (list/tuple/str) then the variable values looked up in the
1299 give (list/tuple/str) then the variable values looked up in the
1300 callers frame.
1300 callers frame.
1301 interactive : bool
1301 interactive : bool
1302 If True (default), the variables will be listed with the ``who``
1302 If True (default), the variables will be listed with the ``who``
1303 magic.
1303 magic.
1304 """
1304 """
1305 vdict = None
1305 vdict = None
1306
1306
1307 # We need a dict of name/value pairs to do namespace updates.
1307 # We need a dict of name/value pairs to do namespace updates.
1308 if isinstance(variables, dict):
1308 if isinstance(variables, dict):
1309 vdict = variables
1309 vdict = variables
1310 elif isinstance(variables, (basestring, list, tuple)):
1310 elif isinstance(variables, (basestring, list, tuple)):
1311 if isinstance(variables, basestring):
1311 if isinstance(variables, basestring):
1312 vlist = variables.split()
1312 vlist = variables.split()
1313 else:
1313 else:
1314 vlist = variables
1314 vlist = variables
1315 vdict = {}
1315 vdict = {}
1316 cf = sys._getframe(1)
1316 cf = sys._getframe(1)
1317 for name in vlist:
1317 for name in vlist:
1318 try:
1318 try:
1319 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1319 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1320 except:
1320 except:
1321 print ('Could not get variable %s from %s' %
1321 print ('Could not get variable %s from %s' %
1322 (name,cf.f_code.co_name))
1322 (name,cf.f_code.co_name))
1323 else:
1323 else:
1324 raise ValueError('variables must be a dict/str/list/tuple')
1324 raise ValueError('variables must be a dict/str/list/tuple')
1325
1325
1326 # Propagate variables to user namespace
1326 # Propagate variables to user namespace
1327 self.user_ns.update(vdict)
1327 self.user_ns.update(vdict)
1328
1328
1329 # And configure interactive visibility
1329 # And configure interactive visibility
1330 user_ns_hidden = self.user_ns_hidden
1330 user_ns_hidden = self.user_ns_hidden
1331 if interactive:
1331 if interactive:
1332 user_ns_hidden.difference_update(vdict)
1332 user_ns_hidden.difference_update(vdict)
1333 else:
1333 else:
1334 user_ns_hidden.update(vdict)
1334 user_ns_hidden.update(vdict)
1335
1335
1336 def drop_by_id(self, variables):
1336 def drop_by_id(self, variables):
1337 """Remove a dict of variables from the user namespace, if they are the
1337 """Remove a dict of variables from the user namespace, if they are the
1338 same as the values in the dictionary.
1338 same as the values in the dictionary.
1339
1339
1340 This is intended for use by extensions: variables that they've added can
1340 This is intended for use by extensions: variables that they've added can
1341 be taken back out if they are unloaded, without removing any that the
1341 be taken back out if they are unloaded, without removing any that the
1342 user has overwritten.
1342 user has overwritten.
1343
1343
1344 Parameters
1344 Parameters
1345 ----------
1345 ----------
1346 variables : dict
1346 variables : dict
1347 A dictionary mapping object names (as strings) to the objects.
1347 A dictionary mapping object names (as strings) to the objects.
1348 """
1348 """
1349 for name, obj in variables.iteritems():
1349 for name, obj in variables.iteritems():
1350 if name in self.user_ns and self.user_ns[name] is obj:
1350 if name in self.user_ns and self.user_ns[name] is obj:
1351 del self.user_ns[name]
1351 del self.user_ns[name]
1352 self.user_ns_hidden.discard(name)
1352 self.user_ns_hidden.discard(name)
1353
1353
1354 #-------------------------------------------------------------------------
1354 #-------------------------------------------------------------------------
1355 # Things related to object introspection
1355 # Things related to object introspection
1356 #-------------------------------------------------------------------------
1356 #-------------------------------------------------------------------------
1357
1357
1358 def _ofind(self, oname, namespaces=None):
1358 def _ofind(self, oname, namespaces=None):
1359 """Find an object in the available namespaces.
1359 """Find an object in the available namespaces.
1360
1360
1361 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1361 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1362
1362
1363 Has special code to detect magic functions.
1363 Has special code to detect magic functions.
1364 """
1364 """
1365 oname = oname.strip()
1365 oname = oname.strip()
1366 #print '1- oname: <%r>' % oname # dbg
1366 #print '1- oname: <%r>' % oname # dbg
1367 if not oname.startswith(ESC_MAGIC) and \
1367 if not oname.startswith(ESC_MAGIC) and \
1368 not oname.startswith(ESC_MAGIC2) and \
1368 not oname.startswith(ESC_MAGIC2) and \
1369 not py3compat.isidentifier(oname, dotted=True):
1369 not py3compat.isidentifier(oname, dotted=True):
1370 return dict(found=False)
1370 return dict(found=False)
1371
1371
1372 alias_ns = None
1372 alias_ns = None
1373 if namespaces is None:
1373 if namespaces is None:
1374 # Namespaces to search in:
1374 # Namespaces to search in:
1375 # Put them in a list. The order is important so that we
1375 # Put them in a list. The order is important so that we
1376 # find things in the same order that Python finds them.
1376 # find things in the same order that Python finds them.
1377 namespaces = [ ('Interactive', self.user_ns),
1377 namespaces = [ ('Interactive', self.user_ns),
1378 ('Interactive (global)', self.user_global_ns),
1378 ('Interactive (global)', self.user_global_ns),
1379 ('Python builtin', builtin_mod.__dict__),
1379 ('Python builtin', builtin_mod.__dict__),
1380 ('Alias', self.alias_manager.alias_table),
1380 ('Alias', self.alias_manager.alias_table),
1381 ]
1381 ]
1382 alias_ns = self.alias_manager.alias_table
1382 alias_ns = self.alias_manager.alias_table
1383
1383
1384 # initialize results to 'null'
1384 # initialize results to 'null'
1385 found = False; obj = None; ospace = None; ds = None;
1385 found = False; obj = None; ospace = None; ds = None;
1386 ismagic = False; isalias = False; parent = None
1386 ismagic = False; isalias = False; parent = None
1387
1387
1388 # We need to special-case 'print', which as of python2.6 registers as a
1388 # We need to special-case 'print', which as of python2.6 registers as a
1389 # function but should only be treated as one if print_function was
1389 # function but should only be treated as one if print_function was
1390 # loaded with a future import. In this case, just bail.
1390 # loaded with a future import. In this case, just bail.
1391 if (oname == 'print' and not py3compat.PY3 and not \
1391 if (oname == 'print' and not py3compat.PY3 and not \
1392 (self.compile.compiler_flags & __future__.CO_FUTURE_PRINT_FUNCTION)):
1392 (self.compile.compiler_flags & __future__.CO_FUTURE_PRINT_FUNCTION)):
1393 return {'found':found, 'obj':obj, 'namespace':ospace,
1393 return {'found':found, 'obj':obj, 'namespace':ospace,
1394 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1394 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1395
1395
1396 # Look for the given name by splitting it in parts. If the head is
1396 # Look for the given name by splitting it in parts. If the head is
1397 # found, then we look for all the remaining parts as members, and only
1397 # found, then we look for all the remaining parts as members, and only
1398 # declare success if we can find them all.
1398 # declare success if we can find them all.
1399 oname_parts = oname.split('.')
1399 oname_parts = oname.split('.')
1400 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1400 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1401 for nsname,ns in namespaces:
1401 for nsname,ns in namespaces:
1402 try:
1402 try:
1403 obj = ns[oname_head]
1403 obj = ns[oname_head]
1404 except KeyError:
1404 except KeyError:
1405 continue
1405 continue
1406 else:
1406 else:
1407 #print 'oname_rest:', oname_rest # dbg
1407 #print 'oname_rest:', oname_rest # dbg
1408 for part in oname_rest:
1408 for part in oname_rest:
1409 try:
1409 try:
1410 parent = obj
1410 parent = obj
1411 obj = getattr(obj,part)
1411 obj = getattr(obj,part)
1412 except:
1412 except:
1413 # Blanket except b/c some badly implemented objects
1413 # Blanket except b/c some badly implemented objects
1414 # allow __getattr__ to raise exceptions other than
1414 # allow __getattr__ to raise exceptions other than
1415 # AttributeError, which then crashes IPython.
1415 # AttributeError, which then crashes IPython.
1416 break
1416 break
1417 else:
1417 else:
1418 # If we finish the for loop (no break), we got all members
1418 # If we finish the for loop (no break), we got all members
1419 found = True
1419 found = True
1420 ospace = nsname
1420 ospace = nsname
1421 if ns == alias_ns:
1421 if ns == alias_ns:
1422 isalias = True
1422 isalias = True
1423 break # namespace loop
1423 break # namespace loop
1424
1424
1425 # Try to see if it's magic
1425 # Try to see if it's magic
1426 if not found:
1426 if not found:
1427 obj = None
1427 obj = None
1428 if oname.startswith(ESC_MAGIC2):
1428 if oname.startswith(ESC_MAGIC2):
1429 oname = oname.lstrip(ESC_MAGIC2)
1429 oname = oname.lstrip(ESC_MAGIC2)
1430 obj = self.find_cell_magic(oname)
1430 obj = self.find_cell_magic(oname)
1431 elif oname.startswith(ESC_MAGIC):
1431 elif oname.startswith(ESC_MAGIC):
1432 oname = oname.lstrip(ESC_MAGIC)
1432 oname = oname.lstrip(ESC_MAGIC)
1433 obj = self.find_line_magic(oname)
1433 obj = self.find_line_magic(oname)
1434 else:
1434 else:
1435 # search without prefix, so run? will find %run?
1435 # search without prefix, so run? will find %run?
1436 obj = self.find_line_magic(oname)
1436 obj = self.find_line_magic(oname)
1437 if obj is None:
1437 if obj is None:
1438 obj = self.find_cell_magic(oname)
1438 obj = self.find_cell_magic(oname)
1439 if obj is not None:
1439 if obj is not None:
1440 found = True
1440 found = True
1441 ospace = 'IPython internal'
1441 ospace = 'IPython internal'
1442 ismagic = True
1442 ismagic = True
1443
1443
1444 # Last try: special-case some literals like '', [], {}, etc:
1444 # Last try: special-case some literals like '', [], {}, etc:
1445 if not found and oname_head in ["''",'""','[]','{}','()']:
1445 if not found and oname_head in ["''",'""','[]','{}','()']:
1446 obj = eval(oname_head)
1446 obj = eval(oname_head)
1447 found = True
1447 found = True
1448 ospace = 'Interactive'
1448 ospace = 'Interactive'
1449
1449
1450 return {'found':found, 'obj':obj, 'namespace':ospace,
1450 return {'found':found, 'obj':obj, 'namespace':ospace,
1451 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1451 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1452
1452
1453 def _ofind_property(self, oname, info):
1453 def _ofind_property(self, oname, info):
1454 """Second part of object finding, to look for property details."""
1454 """Second part of object finding, to look for property details."""
1455 if info.found:
1455 if info.found:
1456 # Get the docstring of the class property if it exists.
1456 # Get the docstring of the class property if it exists.
1457 path = oname.split('.')
1457 path = oname.split('.')
1458 root = '.'.join(path[:-1])
1458 root = '.'.join(path[:-1])
1459 if info.parent is not None:
1459 if info.parent is not None:
1460 try:
1460 try:
1461 target = getattr(info.parent, '__class__')
1461 target = getattr(info.parent, '__class__')
1462 # The object belongs to a class instance.
1462 # The object belongs to a class instance.
1463 try:
1463 try:
1464 target = getattr(target, path[-1])
1464 target = getattr(target, path[-1])
1465 # The class defines the object.
1465 # The class defines the object.
1466 if isinstance(target, property):
1466 if isinstance(target, property):
1467 oname = root + '.__class__.' + path[-1]
1467 oname = root + '.__class__.' + path[-1]
1468 info = Struct(self._ofind(oname))
1468 info = Struct(self._ofind(oname))
1469 except AttributeError: pass
1469 except AttributeError: pass
1470 except AttributeError: pass
1470 except AttributeError: pass
1471
1471
1472 # We return either the new info or the unmodified input if the object
1472 # We return either the new info or the unmodified input if the object
1473 # hadn't been found
1473 # hadn't been found
1474 return info
1474 return info
1475
1475
1476 def _object_find(self, oname, namespaces=None):
1476 def _object_find(self, oname, namespaces=None):
1477 """Find an object and return a struct with info about it."""
1477 """Find an object and return a struct with info about it."""
1478 inf = Struct(self._ofind(oname, namespaces))
1478 inf = Struct(self._ofind(oname, namespaces))
1479 return Struct(self._ofind_property(oname, inf))
1479 return Struct(self._ofind_property(oname, inf))
1480
1480
1481 def _inspect(self, meth, oname, namespaces=None, **kw):
1481 def _inspect(self, meth, oname, namespaces=None, **kw):
1482 """Generic interface to the inspector system.
1482 """Generic interface to the inspector system.
1483
1483
1484 This function is meant to be called by pdef, pdoc & friends."""
1484 This function is meant to be called by pdef, pdoc & friends."""
1485 info = self._object_find(oname)
1485 info = self._object_find(oname)
1486 if info.found:
1486 if info.found:
1487 pmethod = getattr(self.inspector, meth)
1487 pmethod = getattr(self.inspector, meth)
1488 formatter = format_screen if info.ismagic else None
1488 formatter = format_screen if info.ismagic else None
1489 if meth == 'pdoc':
1489 if meth == 'pdoc':
1490 pmethod(info.obj, oname, formatter)
1490 pmethod(info.obj, oname, formatter)
1491 elif meth == 'pinfo':
1491 elif meth == 'pinfo':
1492 pmethod(info.obj, oname, formatter, info, **kw)
1492 pmethod(info.obj, oname, formatter, info, **kw)
1493 else:
1493 else:
1494 pmethod(info.obj, oname)
1494 pmethod(info.obj, oname)
1495 else:
1495 else:
1496 print 'Object `%s` not found.' % oname
1496 print 'Object `%s` not found.' % oname
1497 return 'not found' # so callers can take other action
1497 return 'not found' # so callers can take other action
1498
1498
1499 def object_inspect(self, oname, detail_level=0):
1499 def object_inspect(self, oname, detail_level=0):
1500 with self.builtin_trap:
1500 with self.builtin_trap:
1501 info = self._object_find(oname)
1501 info = self._object_find(oname)
1502 if info.found:
1502 if info.found:
1503 return self.inspector.info(info.obj, oname, info=info,
1503 return self.inspector.info(info.obj, oname, info=info,
1504 detail_level=detail_level
1504 detail_level=detail_level
1505 )
1505 )
1506 else:
1506 else:
1507 return oinspect.object_info(name=oname, found=False)
1507 return oinspect.object_info(name=oname, found=False)
1508
1508
1509 #-------------------------------------------------------------------------
1509 #-------------------------------------------------------------------------
1510 # Things related to history management
1510 # Things related to history management
1511 #-------------------------------------------------------------------------
1511 #-------------------------------------------------------------------------
1512
1512
1513 def init_history(self):
1513 def init_history(self):
1514 """Sets up the command history, and starts regular autosaves."""
1514 """Sets up the command history, and starts regular autosaves."""
1515 self.history_manager = HistoryManager(shell=self, config=self.config)
1515 self.history_manager = HistoryManager(shell=self, config=self.config)
1516 self.configurables.append(self.history_manager)
1516 self.configurables.append(self.history_manager)
1517
1517
1518 #-------------------------------------------------------------------------
1518 #-------------------------------------------------------------------------
1519 # Things related to exception handling and tracebacks (not debugging)
1519 # Things related to exception handling and tracebacks (not debugging)
1520 #-------------------------------------------------------------------------
1520 #-------------------------------------------------------------------------
1521
1521
1522 def init_traceback_handlers(self, custom_exceptions):
1522 def init_traceback_handlers(self, custom_exceptions):
1523 # Syntax error handler.
1523 # Syntax error handler.
1524 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor')
1524 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor')
1525
1525
1526 # The interactive one is initialized with an offset, meaning we always
1526 # The interactive one is initialized with an offset, meaning we always
1527 # want to remove the topmost item in the traceback, which is our own
1527 # want to remove the topmost item in the traceback, which is our own
1528 # internal code. Valid modes: ['Plain','Context','Verbose']
1528 # internal code. Valid modes: ['Plain','Context','Verbose']
1529 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1529 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1530 color_scheme='NoColor',
1530 color_scheme='NoColor',
1531 tb_offset = 1,
1531 tb_offset = 1,
1532 check_cache=self.compile.check_cache)
1532 check_cache=self.compile.check_cache)
1533
1533
1534 # The instance will store a pointer to the system-wide exception hook,
1534 # The instance will store a pointer to the system-wide exception hook,
1535 # so that runtime code (such as magics) can access it. This is because
1535 # so that runtime code (such as magics) can access it. This is because
1536 # during the read-eval loop, it may get temporarily overwritten.
1536 # during the read-eval loop, it may get temporarily overwritten.
1537 self.sys_excepthook = sys.excepthook
1537 self.sys_excepthook = sys.excepthook
1538
1538
1539 # and add any custom exception handlers the user may have specified
1539 # and add any custom exception handlers the user may have specified
1540 self.set_custom_exc(*custom_exceptions)
1540 self.set_custom_exc(*custom_exceptions)
1541
1541
1542 # Set the exception mode
1542 # Set the exception mode
1543 self.InteractiveTB.set_mode(mode=self.xmode)
1543 self.InteractiveTB.set_mode(mode=self.xmode)
1544
1544
1545 def set_custom_exc(self, exc_tuple, handler):
1545 def set_custom_exc(self, exc_tuple, handler):
1546 """set_custom_exc(exc_tuple,handler)
1546 """set_custom_exc(exc_tuple,handler)
1547
1547
1548 Set a custom exception handler, which will be called if any of the
1548 Set a custom exception handler, which will be called if any of the
1549 exceptions in exc_tuple occur in the mainloop (specifically, in the
1549 exceptions in exc_tuple occur in the mainloop (specifically, in the
1550 run_code() method).
1550 run_code() method).
1551
1551
1552 Parameters
1552 Parameters
1553 ----------
1553 ----------
1554
1554
1555 exc_tuple : tuple of exception classes
1555 exc_tuple : tuple of exception classes
1556 A *tuple* of exception classes, for which to call the defined
1556 A *tuple* of exception classes, for which to call the defined
1557 handler. It is very important that you use a tuple, and NOT A
1557 handler. It is very important that you use a tuple, and NOT A
1558 LIST here, because of the way Python's except statement works. If
1558 LIST here, because of the way Python's except statement works. If
1559 you only want to trap a single exception, use a singleton tuple::
1559 you only want to trap a single exception, use a singleton tuple::
1560
1560
1561 exc_tuple == (MyCustomException,)
1561 exc_tuple == (MyCustomException,)
1562
1562
1563 handler : callable
1563 handler : callable
1564 handler must have the following signature::
1564 handler must have the following signature::
1565
1565
1566 def my_handler(self, etype, value, tb, tb_offset=None):
1566 def my_handler(self, etype, value, tb, tb_offset=None):
1567 ...
1567 ...
1568 return structured_traceback
1568 return structured_traceback
1569
1569
1570 Your handler must return a structured traceback (a list of strings),
1570 Your handler must return a structured traceback (a list of strings),
1571 or None.
1571 or None.
1572
1572
1573 This will be made into an instance method (via types.MethodType)
1573 This will be made into an instance method (via types.MethodType)
1574 of IPython itself, and it will be called if any of the exceptions
1574 of IPython itself, and it will be called if any of the exceptions
1575 listed in the exc_tuple are caught. If the handler is None, an
1575 listed in the exc_tuple are caught. If the handler is None, an
1576 internal basic one is used, which just prints basic info.
1576 internal basic one is used, which just prints basic info.
1577
1577
1578 To protect IPython from crashes, if your handler ever raises an
1578 To protect IPython from crashes, if your handler ever raises an
1579 exception or returns an invalid result, it will be immediately
1579 exception or returns an invalid result, it will be immediately
1580 disabled.
1580 disabled.
1581
1581
1582 WARNING: by putting in your own exception handler into IPython's main
1582 WARNING: by putting in your own exception handler into IPython's main
1583 execution loop, you run a very good chance of nasty crashes. This
1583 execution loop, you run a very good chance of nasty crashes. This
1584 facility should only be used if you really know what you are doing."""
1584 facility should only be used if you really know what you are doing."""
1585
1585
1586 assert type(exc_tuple)==type(()) , \
1586 assert type(exc_tuple)==type(()) , \
1587 "The custom exceptions must be given AS A TUPLE."
1587 "The custom exceptions must be given AS A TUPLE."
1588
1588
1589 def dummy_handler(self,etype,value,tb,tb_offset=None):
1589 def dummy_handler(self,etype,value,tb,tb_offset=None):
1590 print '*** Simple custom exception handler ***'
1590 print '*** Simple custom exception handler ***'
1591 print 'Exception type :',etype
1591 print 'Exception type :',etype
1592 print 'Exception value:',value
1592 print 'Exception value:',value
1593 print 'Traceback :',tb
1593 print 'Traceback :',tb
1594 #print 'Source code :','\n'.join(self.buffer)
1594 #print 'Source code :','\n'.join(self.buffer)
1595
1595
1596 def validate_stb(stb):
1596 def validate_stb(stb):
1597 """validate structured traceback return type
1597 """validate structured traceback return type
1598
1598
1599 return type of CustomTB *should* be a list of strings, but allow
1599 return type of CustomTB *should* be a list of strings, but allow
1600 single strings or None, which are harmless.
1600 single strings or None, which are harmless.
1601
1601
1602 This function will *always* return a list of strings,
1602 This function will *always* return a list of strings,
1603 and will raise a TypeError if stb is inappropriate.
1603 and will raise a TypeError if stb is inappropriate.
1604 """
1604 """
1605 msg = "CustomTB must return list of strings, not %r" % stb
1605 msg = "CustomTB must return list of strings, not %r" % stb
1606 if stb is None:
1606 if stb is None:
1607 return []
1607 return []
1608 elif isinstance(stb, basestring):
1608 elif isinstance(stb, basestring):
1609 return [stb]
1609 return [stb]
1610 elif not isinstance(stb, list):
1610 elif not isinstance(stb, list):
1611 raise TypeError(msg)
1611 raise TypeError(msg)
1612 # it's a list
1612 # it's a list
1613 for line in stb:
1613 for line in stb:
1614 # check every element
1614 # check every element
1615 if not isinstance(line, basestring):
1615 if not isinstance(line, basestring):
1616 raise TypeError(msg)
1616 raise TypeError(msg)
1617 return stb
1617 return stb
1618
1618
1619 if handler is None:
1619 if handler is None:
1620 wrapped = dummy_handler
1620 wrapped = dummy_handler
1621 else:
1621 else:
1622 def wrapped(self,etype,value,tb,tb_offset=None):
1622 def wrapped(self,etype,value,tb,tb_offset=None):
1623 """wrap CustomTB handler, to protect IPython from user code
1623 """wrap CustomTB handler, to protect IPython from user code
1624
1624
1625 This makes it harder (but not impossible) for custom exception
1625 This makes it harder (but not impossible) for custom exception
1626 handlers to crash IPython.
1626 handlers to crash IPython.
1627 """
1627 """
1628 try:
1628 try:
1629 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1629 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1630 return validate_stb(stb)
1630 return validate_stb(stb)
1631 except:
1631 except:
1632 # clear custom handler immediately
1632 # clear custom handler immediately
1633 self.set_custom_exc((), None)
1633 self.set_custom_exc((), None)
1634 print >> io.stderr, "Custom TB Handler failed, unregistering"
1634 print >> io.stderr, "Custom TB Handler failed, unregistering"
1635 # show the exception in handler first
1635 # show the exception in handler first
1636 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1636 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1637 print >> io.stdout, self.InteractiveTB.stb2text(stb)
1637 print >> io.stdout, self.InteractiveTB.stb2text(stb)
1638 print >> io.stdout, "The original exception:"
1638 print >> io.stdout, "The original exception:"
1639 stb = self.InteractiveTB.structured_traceback(
1639 stb = self.InteractiveTB.structured_traceback(
1640 (etype,value,tb), tb_offset=tb_offset
1640 (etype,value,tb), tb_offset=tb_offset
1641 )
1641 )
1642 return stb
1642 return stb
1643
1643
1644 self.CustomTB = types.MethodType(wrapped,self)
1644 self.CustomTB = types.MethodType(wrapped,self)
1645 self.custom_exceptions = exc_tuple
1645 self.custom_exceptions = exc_tuple
1646
1646
1647 def excepthook(self, etype, value, tb):
1647 def excepthook(self, etype, value, tb):
1648 """One more defense for GUI apps that call sys.excepthook.
1648 """One more defense for GUI apps that call sys.excepthook.
1649
1649
1650 GUI frameworks like wxPython trap exceptions and call
1650 GUI frameworks like wxPython trap exceptions and call
1651 sys.excepthook themselves. I guess this is a feature that
1651 sys.excepthook themselves. I guess this is a feature that
1652 enables them to keep running after exceptions that would
1652 enables them to keep running after exceptions that would
1653 otherwise kill their mainloop. This is a bother for IPython
1653 otherwise kill their mainloop. This is a bother for IPython
1654 which excepts to catch all of the program exceptions with a try:
1654 which excepts to catch all of the program exceptions with a try:
1655 except: statement.
1655 except: statement.
1656
1656
1657 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1657 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1658 any app directly invokes sys.excepthook, it will look to the user like
1658 any app directly invokes sys.excepthook, it will look to the user like
1659 IPython crashed. In order to work around this, we can disable the
1659 IPython crashed. In order to work around this, we can disable the
1660 CrashHandler and replace it with this excepthook instead, which prints a
1660 CrashHandler and replace it with this excepthook instead, which prints a
1661 regular traceback using our InteractiveTB. In this fashion, apps which
1661 regular traceback using our InteractiveTB. In this fashion, apps which
1662 call sys.excepthook will generate a regular-looking exception from
1662 call sys.excepthook will generate a regular-looking exception from
1663 IPython, and the CrashHandler will only be triggered by real IPython
1663 IPython, and the CrashHandler will only be triggered by real IPython
1664 crashes.
1664 crashes.
1665
1665
1666 This hook should be used sparingly, only in places which are not likely
1666 This hook should be used sparingly, only in places which are not likely
1667 to be true IPython errors.
1667 to be true IPython errors.
1668 """
1668 """
1669 self.showtraceback((etype,value,tb),tb_offset=0)
1669 self.showtraceback((etype,value,tb),tb_offset=0)
1670
1670
1671 def _get_exc_info(self, exc_tuple=None):
1671 def _get_exc_info(self, exc_tuple=None):
1672 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1672 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1673
1673
1674 Ensures sys.last_type,value,traceback hold the exc_info we found,
1674 Ensures sys.last_type,value,traceback hold the exc_info we found,
1675 from whichever source.
1675 from whichever source.
1676
1676
1677 raises ValueError if none of these contain any information
1677 raises ValueError if none of these contain any information
1678 """
1678 """
1679 if exc_tuple is None:
1679 if exc_tuple is None:
1680 etype, value, tb = sys.exc_info()
1680 etype, value, tb = sys.exc_info()
1681 else:
1681 else:
1682 etype, value, tb = exc_tuple
1682 etype, value, tb = exc_tuple
1683
1683
1684 if etype is None:
1684 if etype is None:
1685 if hasattr(sys, 'last_type'):
1685 if hasattr(sys, 'last_type'):
1686 etype, value, tb = sys.last_type, sys.last_value, \
1686 etype, value, tb = sys.last_type, sys.last_value, \
1687 sys.last_traceback
1687 sys.last_traceback
1688
1688
1689 if etype is None:
1689 if etype is None:
1690 raise ValueError("No exception to find")
1690 raise ValueError("No exception to find")
1691
1691
1692 # Now store the exception info in sys.last_type etc.
1692 # Now store the exception info in sys.last_type etc.
1693 # WARNING: these variables are somewhat deprecated and not
1693 # WARNING: these variables are somewhat deprecated and not
1694 # necessarily safe to use in a threaded environment, but tools
1694 # necessarily safe to use in a threaded environment, but tools
1695 # like pdb depend on their existence, so let's set them. If we
1695 # like pdb depend on their existence, so let's set them. If we
1696 # find problems in the field, we'll need to revisit their use.
1696 # find problems in the field, we'll need to revisit their use.
1697 sys.last_type = etype
1697 sys.last_type = etype
1698 sys.last_value = value
1698 sys.last_value = value
1699 sys.last_traceback = tb
1699 sys.last_traceback = tb
1700
1700
1701 return etype, value, tb
1701 return etype, value, tb
1702
1702
1703
1703
1704 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None,
1704 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None,
1705 exception_only=False):
1705 exception_only=False):
1706 """Display the exception that just occurred.
1706 """Display the exception that just occurred.
1707
1707
1708 If nothing is known about the exception, this is the method which
1708 If nothing is known about the exception, this is the method which
1709 should be used throughout the code for presenting user tracebacks,
1709 should be used throughout the code for presenting user tracebacks,
1710 rather than directly invoking the InteractiveTB object.
1710 rather than directly invoking the InteractiveTB object.
1711
1711
1712 A specific showsyntaxerror() also exists, but this method can take
1712 A specific showsyntaxerror() also exists, but this method can take
1713 care of calling it if needed, so unless you are explicitly catching a
1713 care of calling it if needed, so unless you are explicitly catching a
1714 SyntaxError exception, don't try to analyze the stack manually and
1714 SyntaxError exception, don't try to analyze the stack manually and
1715 simply call this method."""
1715 simply call this method."""
1716
1716
1717 try:
1717 try:
1718 try:
1718 try:
1719 etype, value, tb = self._get_exc_info(exc_tuple)
1719 etype, value, tb = self._get_exc_info(exc_tuple)
1720 except ValueError:
1720 except ValueError:
1721 self.write_err('No traceback available to show.\n')
1721 self.write_err('No traceback available to show.\n')
1722 return
1722 return
1723
1723
1724 if etype is SyntaxError:
1724 if etype is SyntaxError:
1725 # Though this won't be called by syntax errors in the input
1725 # Though this won't be called by syntax errors in the input
1726 # line, there may be SyntaxError cases with imported code.
1726 # line, there may be SyntaxError cases with imported code.
1727 self.showsyntaxerror(filename)
1727 self.showsyntaxerror(filename)
1728 elif etype is UsageError:
1728 elif etype is UsageError:
1729 self.write_err("UsageError: %s" % value)
1729 self.write_err("UsageError: %s" % value)
1730 elif issubclass(etype, RemoteError):
1730 elif issubclass(etype, RemoteError):
1731 # IPython.parallel remote exceptions.
1731 # IPython.parallel remote exceptions.
1732 # Draw the remote traceback, not the local one.
1732 # Draw the remote traceback, not the local one.
1733 self._showtraceback(etype, value, value.render_traceback())
1733 self._showtraceback(etype, value, value.render_traceback())
1734 else:
1734 else:
1735 if exception_only:
1735 if exception_only:
1736 stb = ['An exception has occurred, use %tb to see '
1736 stb = ['An exception has occurred, use %tb to see '
1737 'the full traceback.\n']
1737 'the full traceback.\n']
1738 stb.extend(self.InteractiveTB.get_exception_only(etype,
1738 stb.extend(self.InteractiveTB.get_exception_only(etype,
1739 value))
1739 value))
1740 else:
1740 else:
1741 stb = self.InteractiveTB.structured_traceback(etype,
1741 stb = self.InteractiveTB.structured_traceback(etype,
1742 value, tb, tb_offset=tb_offset)
1742 value, tb, tb_offset=tb_offset)
1743
1743
1744 self._showtraceback(etype, value, stb)
1744 self._showtraceback(etype, value, stb)
1745 if self.call_pdb:
1745 if self.call_pdb:
1746 # drop into debugger
1746 # drop into debugger
1747 self.debugger(force=True)
1747 self.debugger(force=True)
1748 return
1748 return
1749
1749
1750 # Actually show the traceback
1750 # Actually show the traceback
1751 self._showtraceback(etype, value, stb)
1751 self._showtraceback(etype, value, stb)
1752
1752
1753 except KeyboardInterrupt:
1753 except KeyboardInterrupt:
1754 self.write_err("\nKeyboardInterrupt\n")
1754 self.write_err("\nKeyboardInterrupt\n")
1755
1755
1756 def _showtraceback(self, etype, evalue, stb):
1756 def _showtraceback(self, etype, evalue, stb):
1757 """Actually show a traceback.
1757 """Actually show a traceback.
1758
1758
1759 Subclasses may override this method to put the traceback on a different
1759 Subclasses may override this method to put the traceback on a different
1760 place, like a side channel.
1760 place, like a side channel.
1761 """
1761 """
1762 print >> io.stdout, self.InteractiveTB.stb2text(stb)
1762 print >> io.stdout, self.InteractiveTB.stb2text(stb)
1763
1763
1764 def showsyntaxerror(self, filename=None):
1764 def showsyntaxerror(self, filename=None):
1765 """Display the syntax error that just occurred.
1765 """Display the syntax error that just occurred.
1766
1766
1767 This doesn't display a stack trace because there isn't one.
1767 This doesn't display a stack trace because there isn't one.
1768
1768
1769 If a filename is given, it is stuffed in the exception instead
1769 If a filename is given, it is stuffed in the exception instead
1770 of what was there before (because Python's parser always uses
1770 of what was there before (because Python's parser always uses
1771 "<string>" when reading from a string).
1771 "<string>" when reading from a string).
1772 """
1772 """
1773 etype, value, last_traceback = self._get_exc_info()
1773 etype, value, last_traceback = self._get_exc_info()
1774
1774
1775 if filename and etype is SyntaxError:
1775 if filename and etype is SyntaxError:
1776 try:
1776 try:
1777 value.filename = filename
1777 value.filename = filename
1778 except:
1778 except:
1779 # Not the format we expect; leave it alone
1779 # Not the format we expect; leave it alone
1780 pass
1780 pass
1781
1781
1782 stb = self.SyntaxTB.structured_traceback(etype, value, [])
1782 stb = self.SyntaxTB.structured_traceback(etype, value, [])
1783 self._showtraceback(etype, value, stb)
1783 self._showtraceback(etype, value, stb)
1784
1784
1785 # This is overridden in TerminalInteractiveShell to show a message about
1785 # This is overridden in TerminalInteractiveShell to show a message about
1786 # the %paste magic.
1786 # the %paste magic.
1787 def showindentationerror(self):
1787 def showindentationerror(self):
1788 """Called by run_cell when there's an IndentationError in code entered
1788 """Called by run_cell when there's an IndentationError in code entered
1789 at the prompt.
1789 at the prompt.
1790
1790
1791 This is overridden in TerminalInteractiveShell to show a message about
1791 This is overridden in TerminalInteractiveShell to show a message about
1792 the %paste magic."""
1792 the %paste magic."""
1793 self.showsyntaxerror()
1793 self.showsyntaxerror()
1794
1794
1795 #-------------------------------------------------------------------------
1795 #-------------------------------------------------------------------------
1796 # Things related to readline
1796 # Things related to readline
1797 #-------------------------------------------------------------------------
1797 #-------------------------------------------------------------------------
1798
1798
1799 def init_readline(self):
1799 def init_readline(self):
1800 """Command history completion/saving/reloading."""
1800 """Command history completion/saving/reloading."""
1801
1801
1802 if self.readline_use:
1802 if self.readline_use:
1803 import IPython.utils.rlineimpl as readline
1803 import IPython.utils.rlineimpl as readline
1804
1804
1805 self.rl_next_input = None
1805 self.rl_next_input = None
1806 self.rl_do_indent = False
1806 self.rl_do_indent = False
1807
1807
1808 if not self.readline_use or not readline.have_readline:
1808 if not self.readline_use or not readline.have_readline:
1809 self.has_readline = False
1809 self.has_readline = False
1810 self.readline = None
1810 self.readline = None
1811 # Set a number of methods that depend on readline to be no-op
1811 # Set a number of methods that depend on readline to be no-op
1812 self.readline_no_record = no_op_context
1812 self.readline_no_record = no_op_context
1813 self.set_readline_completer = no_op
1813 self.set_readline_completer = no_op
1814 self.set_custom_completer = no_op
1814 self.set_custom_completer = no_op
1815 self.set_completer_frame = no_op
1815 self.set_completer_frame = no_op
1816 if self.readline_use:
1816 if self.readline_use:
1817 warn('Readline services not available or not loaded.')
1817 warn('Readline services not available or not loaded.')
1818 else:
1818 else:
1819 self.has_readline = True
1819 self.has_readline = True
1820 self.readline = readline
1820 self.readline = readline
1821 sys.modules['readline'] = readline
1821 sys.modules['readline'] = readline
1822
1822
1823 # Platform-specific configuration
1823 # Platform-specific configuration
1824 if os.name == 'nt':
1824 if os.name == 'nt':
1825 # FIXME - check with Frederick to see if we can harmonize
1825 # FIXME - check with Frederick to see if we can harmonize
1826 # naming conventions with pyreadline to avoid this
1826 # naming conventions with pyreadline to avoid this
1827 # platform-dependent check
1827 # platform-dependent check
1828 self.readline_startup_hook = readline.set_pre_input_hook
1828 self.readline_startup_hook = readline.set_pre_input_hook
1829 else:
1829 else:
1830 self.readline_startup_hook = readline.set_startup_hook
1830 self.readline_startup_hook = readline.set_startup_hook
1831
1831
1832 # Load user's initrc file (readline config)
1832 # Load user's initrc file (readline config)
1833 # Or if libedit is used, load editrc.
1833 # Or if libedit is used, load editrc.
1834 inputrc_name = os.environ.get('INPUTRC')
1834 inputrc_name = os.environ.get('INPUTRC')
1835 if inputrc_name is None:
1835 if inputrc_name is None:
1836 inputrc_name = '.inputrc'
1836 inputrc_name = '.inputrc'
1837 if readline.uses_libedit:
1837 if readline.uses_libedit:
1838 inputrc_name = '.editrc'
1838 inputrc_name = '.editrc'
1839 inputrc_name = os.path.join(self.home_dir, inputrc_name)
1839 inputrc_name = os.path.join(self.home_dir, inputrc_name)
1840 if os.path.isfile(inputrc_name):
1840 if os.path.isfile(inputrc_name):
1841 try:
1841 try:
1842 readline.read_init_file(inputrc_name)
1842 readline.read_init_file(inputrc_name)
1843 except:
1843 except:
1844 warn('Problems reading readline initialization file <%s>'
1844 warn('Problems reading readline initialization file <%s>'
1845 % inputrc_name)
1845 % inputrc_name)
1846
1846
1847 # Configure readline according to user's prefs
1847 # Configure readline according to user's prefs
1848 # This is only done if GNU readline is being used. If libedit
1848 # This is only done if GNU readline is being used. If libedit
1849 # is being used (as on Leopard) the readline config is
1849 # is being used (as on Leopard) the readline config is
1850 # not run as the syntax for libedit is different.
1850 # not run as the syntax for libedit is different.
1851 if not readline.uses_libedit:
1851 if not readline.uses_libedit:
1852 for rlcommand in self.readline_parse_and_bind:
1852 for rlcommand in self.readline_parse_and_bind:
1853 #print "loading rl:",rlcommand # dbg
1853 #print "loading rl:",rlcommand # dbg
1854 readline.parse_and_bind(rlcommand)
1854 readline.parse_and_bind(rlcommand)
1855
1855
1856 # Remove some chars from the delimiters list. If we encounter
1856 # Remove some chars from the delimiters list. If we encounter
1857 # unicode chars, discard them.
1857 # unicode chars, discard them.
1858 delims = readline.get_completer_delims()
1858 delims = readline.get_completer_delims()
1859 if not py3compat.PY3:
1859 if not py3compat.PY3:
1860 delims = delims.encode("ascii", "ignore")
1860 delims = delims.encode("ascii", "ignore")
1861 for d in self.readline_remove_delims:
1861 for d in self.readline_remove_delims:
1862 delims = delims.replace(d, "")
1862 delims = delims.replace(d, "")
1863 delims = delims.replace(ESC_MAGIC, '')
1863 delims = delims.replace(ESC_MAGIC, '')
1864 readline.set_completer_delims(delims)
1864 readline.set_completer_delims(delims)
1865 # otherwise we end up with a monster history after a while:
1865 # otherwise we end up with a monster history after a while:
1866 readline.set_history_length(self.history_length)
1866 readline.set_history_length(self.history_length)
1867
1867
1868 self.refill_readline_hist()
1868 self.refill_readline_hist()
1869 self.readline_no_record = ReadlineNoRecord(self)
1869 self.readline_no_record = ReadlineNoRecord(self)
1870
1870
1871 # Configure auto-indent for all platforms
1871 # Configure auto-indent for all platforms
1872 self.set_autoindent(self.autoindent)
1872 self.set_autoindent(self.autoindent)
1873
1873
1874 def refill_readline_hist(self):
1874 def refill_readline_hist(self):
1875 # Load the last 1000 lines from history
1875 # Load the last 1000 lines from history
1876 self.readline.clear_history()
1876 self.readline.clear_history()
1877 stdin_encoding = sys.stdin.encoding or "utf-8"
1877 stdin_encoding = sys.stdin.encoding or "utf-8"
1878 last_cell = u""
1878 last_cell = u""
1879 for _, _, cell in self.history_manager.get_tail(1000,
1879 for _, _, cell in self.history_manager.get_tail(1000,
1880 include_latest=True):
1880 include_latest=True):
1881 # Ignore blank lines and consecutive duplicates
1881 # Ignore blank lines and consecutive duplicates
1882 cell = cell.rstrip()
1882 cell = cell.rstrip()
1883 if cell and (cell != last_cell):
1883 if cell and (cell != last_cell):
1884 if self.multiline_history:
1884 if self.multiline_history:
1885 self.readline.add_history(py3compat.unicode_to_str(cell,
1885 self.readline.add_history(py3compat.unicode_to_str(cell,
1886 stdin_encoding))
1886 stdin_encoding))
1887 else:
1887 else:
1888 for line in cell.splitlines():
1888 for line in cell.splitlines():
1889 self.readline.add_history(py3compat.unicode_to_str(line,
1889 self.readline.add_history(py3compat.unicode_to_str(line,
1890 stdin_encoding))
1890 stdin_encoding))
1891 last_cell = cell
1891 last_cell = cell
1892
1892
1893 def set_next_input(self, s):
1893 def set_next_input(self, s):
1894 """ Sets the 'default' input string for the next command line.
1894 """ Sets the 'default' input string for the next command line.
1895
1895
1896 Requires readline.
1896 Requires readline.
1897
1897
1898 Example:
1898 Example:
1899
1899
1900 [D:\ipython]|1> _ip.set_next_input("Hello Word")
1900 [D:\ipython]|1> _ip.set_next_input("Hello Word")
1901 [D:\ipython]|2> Hello Word_ # cursor is here
1901 [D:\ipython]|2> Hello Word_ # cursor is here
1902 """
1902 """
1903 self.rl_next_input = py3compat.cast_bytes_py2(s)
1903 self.rl_next_input = py3compat.cast_bytes_py2(s)
1904
1904
1905 # Maybe move this to the terminal subclass?
1905 # Maybe move this to the terminal subclass?
1906 def pre_readline(self):
1906 def pre_readline(self):
1907 """readline hook to be used at the start of each line.
1907 """readline hook to be used at the start of each line.
1908
1908
1909 Currently it handles auto-indent only."""
1909 Currently it handles auto-indent only."""
1910
1910
1911 if self.rl_do_indent:
1911 if self.rl_do_indent:
1912 self.readline.insert_text(self._indent_current_str())
1912 self.readline.insert_text(self._indent_current_str())
1913 if self.rl_next_input is not None:
1913 if self.rl_next_input is not None:
1914 self.readline.insert_text(self.rl_next_input)
1914 self.readline.insert_text(self.rl_next_input)
1915 self.rl_next_input = None
1915 self.rl_next_input = None
1916
1916
1917 def _indent_current_str(self):
1917 def _indent_current_str(self):
1918 """return the current level of indentation as a string"""
1918 """return the current level of indentation as a string"""
1919 return self.input_splitter.indent_spaces * ' '
1919 return self.input_splitter.indent_spaces * ' '
1920
1920
1921 #-------------------------------------------------------------------------
1921 #-------------------------------------------------------------------------
1922 # Things related to text completion
1922 # Things related to text completion
1923 #-------------------------------------------------------------------------
1923 #-------------------------------------------------------------------------
1924
1924
1925 def init_completer(self):
1925 def init_completer(self):
1926 """Initialize the completion machinery.
1926 """Initialize the completion machinery.
1927
1927
1928 This creates completion machinery that can be used by client code,
1928 This creates completion machinery that can be used by client code,
1929 either interactively in-process (typically triggered by the readline
1929 either interactively in-process (typically triggered by the readline
1930 library), programatically (such as in test suites) or out-of-prcess
1930 library), programatically (such as in test suites) or out-of-prcess
1931 (typically over the network by remote frontends).
1931 (typically over the network by remote frontends).
1932 """
1932 """
1933 from IPython.core.completer import IPCompleter
1933 from IPython.core.completer import IPCompleter
1934 from IPython.core.completerlib import (module_completer,
1934 from IPython.core.completerlib import (module_completer,
1935 magic_run_completer, cd_completer, reset_completer)
1935 magic_run_completer, cd_completer, reset_completer)
1936
1936
1937 self.Completer = IPCompleter(shell=self,
1937 self.Completer = IPCompleter(shell=self,
1938 namespace=self.user_ns,
1938 namespace=self.user_ns,
1939 global_namespace=self.user_global_ns,
1939 global_namespace=self.user_global_ns,
1940 alias_table=self.alias_manager.alias_table,
1940 alias_table=self.alias_manager.alias_table,
1941 use_readline=self.has_readline,
1941 use_readline=self.has_readline,
1942 config=self.config,
1942 config=self.config,
1943 )
1943 )
1944 self.configurables.append(self.Completer)
1944 self.configurables.append(self.Completer)
1945
1945
1946 # Add custom completers to the basic ones built into IPCompleter
1946 # Add custom completers to the basic ones built into IPCompleter
1947 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1947 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1948 self.strdispatchers['complete_command'] = sdisp
1948 self.strdispatchers['complete_command'] = sdisp
1949 self.Completer.custom_completers = sdisp
1949 self.Completer.custom_completers = sdisp
1950
1950
1951 self.set_hook('complete_command', module_completer, str_key = 'import')
1951 self.set_hook('complete_command', module_completer, str_key = 'import')
1952 self.set_hook('complete_command', module_completer, str_key = 'from')
1952 self.set_hook('complete_command', module_completer, str_key = 'from')
1953 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
1953 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
1954 self.set_hook('complete_command', cd_completer, str_key = '%cd')
1954 self.set_hook('complete_command', cd_completer, str_key = '%cd')
1955 self.set_hook('complete_command', reset_completer, str_key = '%reset')
1955 self.set_hook('complete_command', reset_completer, str_key = '%reset')
1956
1956
1957 # Only configure readline if we truly are using readline. IPython can
1957 # Only configure readline if we truly are using readline. IPython can
1958 # do tab-completion over the network, in GUIs, etc, where readline
1958 # do tab-completion over the network, in GUIs, etc, where readline
1959 # itself may be absent
1959 # itself may be absent
1960 if self.has_readline:
1960 if self.has_readline:
1961 self.set_readline_completer()
1961 self.set_readline_completer()
1962
1962
1963 def complete(self, text, line=None, cursor_pos=None):
1963 def complete(self, text, line=None, cursor_pos=None):
1964 """Return the completed text and a list of completions.
1964 """Return the completed text and a list of completions.
1965
1965
1966 Parameters
1966 Parameters
1967 ----------
1967 ----------
1968
1968
1969 text : string
1969 text : string
1970 A string of text to be completed on. It can be given as empty and
1970 A string of text to be completed on. It can be given as empty and
1971 instead a line/position pair are given. In this case, the
1971 instead a line/position pair are given. In this case, the
1972 completer itself will split the line like readline does.
1972 completer itself will split the line like readline does.
1973
1973
1974 line : string, optional
1974 line : string, optional
1975 The complete line that text is part of.
1975 The complete line that text is part of.
1976
1976
1977 cursor_pos : int, optional
1977 cursor_pos : int, optional
1978 The position of the cursor on the input line.
1978 The position of the cursor on the input line.
1979
1979
1980 Returns
1980 Returns
1981 -------
1981 -------
1982 text : string
1982 text : string
1983 The actual text that was completed.
1983 The actual text that was completed.
1984
1984
1985 matches : list
1985 matches : list
1986 A sorted list with all possible completions.
1986 A sorted list with all possible completions.
1987
1987
1988 The optional arguments allow the completion to take more context into
1988 The optional arguments allow the completion to take more context into
1989 account, and are part of the low-level completion API.
1989 account, and are part of the low-level completion API.
1990
1990
1991 This is a wrapper around the completion mechanism, similar to what
1991 This is a wrapper around the completion mechanism, similar to what
1992 readline does at the command line when the TAB key is hit. By
1992 readline does at the command line when the TAB key is hit. By
1993 exposing it as a method, it can be used by other non-readline
1993 exposing it as a method, it can be used by other non-readline
1994 environments (such as GUIs) for text completion.
1994 environments (such as GUIs) for text completion.
1995
1995
1996 Simple usage example:
1996 Simple usage example:
1997
1997
1998 In [1]: x = 'hello'
1998 In [1]: x = 'hello'
1999
1999
2000 In [2]: _ip.complete('x.l')
2000 In [2]: _ip.complete('x.l')
2001 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2001 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2002 """
2002 """
2003
2003
2004 # Inject names into __builtin__ so we can complete on the added names.
2004 # Inject names into __builtin__ so we can complete on the added names.
2005 with self.builtin_trap:
2005 with self.builtin_trap:
2006 return self.Completer.complete(text, line, cursor_pos)
2006 return self.Completer.complete(text, line, cursor_pos)
2007
2007
2008 def set_custom_completer(self, completer, pos=0):
2008 def set_custom_completer(self, completer, pos=0):
2009 """Adds a new custom completer function.
2009 """Adds a new custom completer function.
2010
2010
2011 The position argument (defaults to 0) is the index in the completers
2011 The position argument (defaults to 0) is the index in the completers
2012 list where you want the completer to be inserted."""
2012 list where you want the completer to be inserted."""
2013
2013
2014 newcomp = types.MethodType(completer,self.Completer)
2014 newcomp = types.MethodType(completer,self.Completer)
2015 self.Completer.matchers.insert(pos,newcomp)
2015 self.Completer.matchers.insert(pos,newcomp)
2016
2016
2017 def set_readline_completer(self):
2017 def set_readline_completer(self):
2018 """Reset readline's completer to be our own."""
2018 """Reset readline's completer to be our own."""
2019 self.readline.set_completer(self.Completer.rlcomplete)
2019 self.readline.set_completer(self.Completer.rlcomplete)
2020
2020
2021 def set_completer_frame(self, frame=None):
2021 def set_completer_frame(self, frame=None):
2022 """Set the frame of the completer."""
2022 """Set the frame of the completer."""
2023 if frame:
2023 if frame:
2024 self.Completer.namespace = frame.f_locals
2024 self.Completer.namespace = frame.f_locals
2025 self.Completer.global_namespace = frame.f_globals
2025 self.Completer.global_namespace = frame.f_globals
2026 else:
2026 else:
2027 self.Completer.namespace = self.user_ns
2027 self.Completer.namespace = self.user_ns
2028 self.Completer.global_namespace = self.user_global_ns
2028 self.Completer.global_namespace = self.user_global_ns
2029
2029
2030 #-------------------------------------------------------------------------
2030 #-------------------------------------------------------------------------
2031 # Things related to magics
2031 # Things related to magics
2032 #-------------------------------------------------------------------------
2032 #-------------------------------------------------------------------------
2033
2033
2034 def init_magics(self):
2034 def init_magics(self):
2035 from IPython.core import magics as m
2035 from IPython.core import magics as m
2036 self.magics_manager = magic.MagicsManager(shell=self,
2036 self.magics_manager = magic.MagicsManager(shell=self,
2037 confg=self.config,
2037 confg=self.config,
2038 user_magics=m.UserMagics(self))
2038 user_magics=m.UserMagics(self))
2039 self.configurables.append(self.magics_manager)
2039 self.configurables.append(self.magics_manager)
2040
2040
2041 # Expose as public API from the magics manager
2041 # Expose as public API from the magics manager
2042 self.register_magics = self.magics_manager.register
2042 self.register_magics = self.magics_manager.register
2043 self.register_magic_function = self.magics_manager.register_function
2043 self.register_magic_function = self.magics_manager.register_function
2044 self.define_magic = self.magics_manager.define_magic
2044 self.define_magic = self.magics_manager.define_magic
2045
2045
2046 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2046 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2047 m.ConfigMagics, m.DeprecatedMagics, m.ExecutionMagics,
2047 m.ConfigMagics, m.DeprecatedMagics, m.ExecutionMagics,
2048 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2048 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2049 m.NamespaceMagics, m.OSMagics, m.PylabMagics, m.ScriptMagics,
2049 m.NamespaceMagics, m.OSMagics, m.PylabMagics, m.ScriptMagics,
2050 )
2050 )
2051
2051
2052 # FIXME: Move the color initialization to the DisplayHook, which
2052 # FIXME: Move the color initialization to the DisplayHook, which
2053 # should be split into a prompt manager and displayhook. We probably
2053 # should be split into a prompt manager and displayhook. We probably
2054 # even need a centralize colors management object.
2054 # even need a centralize colors management object.
2055 self.magic('colors %s' % self.colors)
2055 self.magic('colors %s' % self.colors)
2056
2056
2057 def run_line_magic(self, magic_name, line):
2057 def run_line_magic(self, magic_name, line):
2058 """Execute the given line magic.
2058 """Execute the given line magic.
2059
2059
2060 Parameters
2060 Parameters
2061 ----------
2061 ----------
2062 magic_name : str
2062 magic_name : str
2063 Name of the desired magic function, without '%' prefix.
2063 Name of the desired magic function, without '%' prefix.
2064
2064
2065 line : str
2065 line : str
2066 The rest of the input line as a single string.
2066 The rest of the input line as a single string.
2067 """
2067 """
2068 fn = self.find_line_magic(magic_name)
2068 fn = self.find_line_magic(magic_name)
2069 if fn is None:
2069 if fn is None:
2070 cm = self.find_cell_magic(magic_name)
2070 cm = self.find_cell_magic(magic_name)
2071 etpl = "Line magic function `%%%s` not found%s."
2071 etpl = "Line magic function `%%%s` not found%s."
2072 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2072 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2073 'did you mean that instead?)' % magic_name )
2073 'did you mean that instead?)' % magic_name )
2074 error(etpl % (magic_name, extra))
2074 error(etpl % (magic_name, extra))
2075 else:
2075 else:
2076 # Note: this is the distance in the stack to the user's frame.
2076 # Note: this is the distance in the stack to the user's frame.
2077 # This will need to be updated if the internal calling logic gets
2077 # This will need to be updated if the internal calling logic gets
2078 # refactored, or else we'll be expanding the wrong variables.
2078 # refactored, or else we'll be expanding the wrong variables.
2079 stack_depth = 2
2079 stack_depth = 2
2080 magic_arg_s = self.var_expand(line, stack_depth)
2080 magic_arg_s = self.var_expand(line, stack_depth)
2081 # Put magic args in a list so we can call with f(*a) syntax
2081 # Put magic args in a list so we can call with f(*a) syntax
2082 args = [magic_arg_s]
2082 args = [magic_arg_s]
2083 # Grab local namespace if we need it:
2083 # Grab local namespace if we need it:
2084 if getattr(fn, "needs_local_scope", False):
2084 if getattr(fn, "needs_local_scope", False):
2085 args.append(sys._getframe(stack_depth).f_locals)
2085 args.append(sys._getframe(stack_depth).f_locals)
2086 with self.builtin_trap:
2086 with self.builtin_trap:
2087 result = fn(*args)
2087 result = fn(*args)
2088 return result
2088 return result
2089
2089
2090 def run_cell_magic(self, magic_name, line, cell):
2090 def run_cell_magic(self, magic_name, line, cell):
2091 """Execute the given cell magic.
2091 """Execute the given cell magic.
2092
2092
2093 Parameters
2093 Parameters
2094 ----------
2094 ----------
2095 magic_name : str
2095 magic_name : str
2096 Name of the desired magic function, without '%' prefix.
2096 Name of the desired magic function, without '%' prefix.
2097
2097
2098 line : str
2098 line : str
2099 The rest of the first input line as a single string.
2099 The rest of the first input line as a single string.
2100
2100
2101 cell : str
2101 cell : str
2102 The body of the cell as a (possibly multiline) string.
2102 The body of the cell as a (possibly multiline) string.
2103 """
2103 """
2104 fn = self.find_cell_magic(magic_name)
2104 fn = self.find_cell_magic(magic_name)
2105 if fn is None:
2105 if fn is None:
2106 lm = self.find_line_magic(magic_name)
2106 lm = self.find_line_magic(magic_name)
2107 etpl = "Cell magic function `%%%%%s` not found%s."
2107 etpl = "Cell magic function `%%%%%s` not found%s."
2108 extra = '' if lm is None else (' (But line magic `%%%s` exists, '
2108 extra = '' if lm is None else (' (But line magic `%%%s` exists, '
2109 'did you mean that instead?)' % magic_name )
2109 'did you mean that instead?)' % magic_name )
2110 error(etpl % (magic_name, extra))
2110 error(etpl % (magic_name, extra))
2111 else:
2111 else:
2112 # Note: this is the distance in the stack to the user's frame.
2112 # Note: this is the distance in the stack to the user's frame.
2113 # This will need to be updated if the internal calling logic gets
2113 # This will need to be updated if the internal calling logic gets
2114 # refactored, or else we'll be expanding the wrong variables.
2114 # refactored, or else we'll be expanding the wrong variables.
2115 stack_depth = 2
2115 stack_depth = 2
2116 magic_arg_s = self.var_expand(line, stack_depth)
2116 magic_arg_s = self.var_expand(line, stack_depth)
2117 with self.builtin_trap:
2117 with self.builtin_trap:
2118 result = fn(line, cell)
2118 result = fn(line, cell)
2119 return result
2119 return result
2120
2120
2121 def find_line_magic(self, magic_name):
2121 def find_line_magic(self, magic_name):
2122 """Find and return a line magic by name.
2122 """Find and return a line magic by name.
2123
2123
2124 Returns None if the magic isn't found."""
2124 Returns None if the magic isn't found."""
2125 return self.magics_manager.magics['line'].get(magic_name)
2125 return self.magics_manager.magics['line'].get(magic_name)
2126
2126
2127 def find_cell_magic(self, magic_name):
2127 def find_cell_magic(self, magic_name):
2128 """Find and return a cell magic by name.
2128 """Find and return a cell magic by name.
2129
2129
2130 Returns None if the magic isn't found."""
2130 Returns None if the magic isn't found."""
2131 return self.magics_manager.magics['cell'].get(magic_name)
2131 return self.magics_manager.magics['cell'].get(magic_name)
2132
2132
2133 def find_magic(self, magic_name, magic_kind='line'):
2133 def find_magic(self, magic_name, magic_kind='line'):
2134 """Find and return a magic of the given type by name.
2134 """Find and return a magic of the given type by name.
2135
2135
2136 Returns None if the magic isn't found."""
2136 Returns None if the magic isn't found."""
2137 return self.magics_manager.magics[magic_kind].get(magic_name)
2137 return self.magics_manager.magics[magic_kind].get(magic_name)
2138
2138
2139 def magic(self, arg_s):
2139 def magic(self, arg_s):
2140 """DEPRECATED. Use run_line_magic() instead.
2140 """DEPRECATED. Use run_line_magic() instead.
2141
2141
2142 Call a magic function by name.
2142 Call a magic function by name.
2143
2143
2144 Input: a string containing the name of the magic function to call and
2144 Input: a string containing the name of the magic function to call and
2145 any additional arguments to be passed to the magic.
2145 any additional arguments to be passed to the magic.
2146
2146
2147 magic('name -opt foo bar') is equivalent to typing at the ipython
2147 magic('name -opt foo bar') is equivalent to typing at the ipython
2148 prompt:
2148 prompt:
2149
2149
2150 In[1]: %name -opt foo bar
2150 In[1]: %name -opt foo bar
2151
2151
2152 To call a magic without arguments, simply use magic('name').
2152 To call a magic without arguments, simply use magic('name').
2153
2153
2154 This provides a proper Python function to call IPython's magics in any
2154 This provides a proper Python function to call IPython's magics in any
2155 valid Python code you can type at the interpreter, including loops and
2155 valid Python code you can type at the interpreter, including loops and
2156 compound statements.
2156 compound statements.
2157 """
2157 """
2158 # TODO: should we issue a loud deprecation warning here?
2158 # TODO: should we issue a loud deprecation warning here?
2159 magic_name, _, magic_arg_s = arg_s.partition(' ')
2159 magic_name, _, magic_arg_s = arg_s.partition(' ')
2160 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2160 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2161 return self.run_line_magic(magic_name, magic_arg_s)
2161 return self.run_line_magic(magic_name, magic_arg_s)
2162
2162
2163 #-------------------------------------------------------------------------
2163 #-------------------------------------------------------------------------
2164 # Things related to macros
2164 # Things related to macros
2165 #-------------------------------------------------------------------------
2165 #-------------------------------------------------------------------------
2166
2166
2167 def define_macro(self, name, themacro):
2167 def define_macro(self, name, themacro):
2168 """Define a new macro
2168 """Define a new macro
2169
2169
2170 Parameters
2170 Parameters
2171 ----------
2171 ----------
2172 name : str
2172 name : str
2173 The name of the macro.
2173 The name of the macro.
2174 themacro : str or Macro
2174 themacro : str or Macro
2175 The action to do upon invoking the macro. If a string, a new
2175 The action to do upon invoking the macro. If a string, a new
2176 Macro object is created by passing the string to it.
2176 Macro object is created by passing the string to it.
2177 """
2177 """
2178
2178
2179 from IPython.core import macro
2179 from IPython.core import macro
2180
2180
2181 if isinstance(themacro, basestring):
2181 if isinstance(themacro, basestring):
2182 themacro = macro.Macro(themacro)
2182 themacro = macro.Macro(themacro)
2183 if not isinstance(themacro, macro.Macro):
2183 if not isinstance(themacro, macro.Macro):
2184 raise ValueError('A macro must be a string or a Macro instance.')
2184 raise ValueError('A macro must be a string or a Macro instance.')
2185 self.user_ns[name] = themacro
2185 self.user_ns[name] = themacro
2186
2186
2187 #-------------------------------------------------------------------------
2187 #-------------------------------------------------------------------------
2188 # Things related to the running of system commands
2188 # Things related to the running of system commands
2189 #-------------------------------------------------------------------------
2189 #-------------------------------------------------------------------------
2190
2190
2191 def system_piped(self, cmd):
2191 def system_piped(self, cmd):
2192 """Call the given cmd in a subprocess, piping stdout/err
2192 """Call the given cmd in a subprocess, piping stdout/err
2193
2193
2194 Parameters
2194 Parameters
2195 ----------
2195 ----------
2196 cmd : str
2196 cmd : str
2197 Command to execute (can not end in '&', as background processes are
2197 Command to execute (can not end in '&', as background processes are
2198 not supported. Should not be a command that expects input
2198 not supported. Should not be a command that expects input
2199 other than simple text.
2199 other than simple text.
2200 """
2200 """
2201 if cmd.rstrip().endswith('&'):
2201 if cmd.rstrip().endswith('&'):
2202 # this is *far* from a rigorous test
2202 # this is *far* from a rigorous test
2203 # We do not support backgrounding processes because we either use
2203 # We do not support backgrounding processes because we either use
2204 # pexpect or pipes to read from. Users can always just call
2204 # pexpect or pipes to read from. Users can always just call
2205 # os.system() or use ip.system=ip.system_raw
2205 # os.system() or use ip.system=ip.system_raw
2206 # if they really want a background process.
2206 # if they really want a background process.
2207 raise OSError("Background processes not supported.")
2207 raise OSError("Background processes not supported.")
2208
2208
2209 # we explicitly do NOT return the subprocess status code, because
2209 # we explicitly do NOT return the subprocess status code, because
2210 # a non-None value would trigger :func:`sys.displayhook` calls.
2210 # a non-None value would trigger :func:`sys.displayhook` calls.
2211 # Instead, we store the exit_code in user_ns.
2211 # Instead, we store the exit_code in user_ns.
2212 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2212 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2213
2213
2214 def system_raw(self, cmd):
2214 def system_raw(self, cmd):
2215 """Call the given cmd in a subprocess using os.system
2215 """Call the given cmd in a subprocess using os.system
2216
2216
2217 Parameters
2217 Parameters
2218 ----------
2218 ----------
2219 cmd : str
2219 cmd : str
2220 Command to execute.
2220 Command to execute.
2221 """
2221 """
2222 cmd = self.var_expand(cmd, depth=1)
2222 cmd = self.var_expand(cmd, depth=1)
2223 # protect os.system from UNC paths on Windows, which it can't handle:
2223 # protect os.system from UNC paths on Windows, which it can't handle:
2224 if sys.platform == 'win32':
2224 if sys.platform == 'win32':
2225 from IPython.utils._process_win32 import AvoidUNCPath
2225 from IPython.utils._process_win32 import AvoidUNCPath
2226 with AvoidUNCPath() as path:
2226 with AvoidUNCPath() as path:
2227 if path is not None:
2227 if path is not None:
2228 cmd = '"pushd %s &&"%s' % (path, cmd)
2228 cmd = '"pushd %s &&"%s' % (path, cmd)
2229 cmd = py3compat.unicode_to_str(cmd)
2229 cmd = py3compat.unicode_to_str(cmd)
2230 ec = os.system(cmd)
2230 ec = os.system(cmd)
2231 else:
2231 else:
2232 cmd = py3compat.unicode_to_str(cmd)
2232 cmd = py3compat.unicode_to_str(cmd)
2233 ec = os.system(cmd)
2233 ec = os.system(cmd)
2234
2234
2235 # We explicitly do NOT return the subprocess status code, because
2235 # We explicitly do NOT return the subprocess status code, because
2236 # a non-None value would trigger :func:`sys.displayhook` calls.
2236 # a non-None value would trigger :func:`sys.displayhook` calls.
2237 # Instead, we store the exit_code in user_ns.
2237 # Instead, we store the exit_code in user_ns.
2238 self.user_ns['_exit_code'] = ec
2238 self.user_ns['_exit_code'] = ec
2239
2239
2240 # use piped system by default, because it is better behaved
2240 # use piped system by default, because it is better behaved
2241 system = system_piped
2241 system = system_piped
2242
2242
2243 def getoutput(self, cmd, split=True, depth=0):
2243 def getoutput(self, cmd, split=True, depth=0):
2244 """Get output (possibly including stderr) from a subprocess.
2244 """Get output (possibly including stderr) from a subprocess.
2245
2245
2246 Parameters
2246 Parameters
2247 ----------
2247 ----------
2248 cmd : str
2248 cmd : str
2249 Command to execute (can not end in '&', as background processes are
2249 Command to execute (can not end in '&', as background processes are
2250 not supported.
2250 not supported.
2251 split : bool, optional
2251 split : bool, optional
2252 If True, split the output into an IPython SList. Otherwise, an
2252 If True, split the output into an IPython SList. Otherwise, an
2253 IPython LSString is returned. These are objects similar to normal
2253 IPython LSString is returned. These are objects similar to normal
2254 lists and strings, with a few convenience attributes for easier
2254 lists and strings, with a few convenience attributes for easier
2255 manipulation of line-based output. You can use '?' on them for
2255 manipulation of line-based output. You can use '?' on them for
2256 details.
2256 details.
2257 depth : int, optional
2257 depth : int, optional
2258 How many frames above the caller are the local variables which should
2258 How many frames above the caller are the local variables which should
2259 be expanded in the command string? The default (0) assumes that the
2259 be expanded in the command string? The default (0) assumes that the
2260 expansion variables are in the stack frame calling this function.
2260 expansion variables are in the stack frame calling this function.
2261 """
2261 """
2262 if cmd.rstrip().endswith('&'):
2262 if cmd.rstrip().endswith('&'):
2263 # this is *far* from a rigorous test
2263 # this is *far* from a rigorous test
2264 raise OSError("Background processes not supported.")
2264 raise OSError("Background processes not supported.")
2265 out = getoutput(self.var_expand(cmd, depth=depth+1))
2265 out = getoutput(self.var_expand(cmd, depth=depth+1))
2266 if split:
2266 if split:
2267 out = SList(out.splitlines())
2267 out = SList(out.splitlines())
2268 else:
2268 else:
2269 out = LSString(out)
2269 out = LSString(out)
2270 return out
2270 return out
2271
2271
2272 #-------------------------------------------------------------------------
2272 #-------------------------------------------------------------------------
2273 # Things related to aliases
2273 # Things related to aliases
2274 #-------------------------------------------------------------------------
2274 #-------------------------------------------------------------------------
2275
2275
2276 def init_alias(self):
2276 def init_alias(self):
2277 self.alias_manager = AliasManager(shell=self, config=self.config)
2277 self.alias_manager = AliasManager(shell=self, config=self.config)
2278 self.configurables.append(self.alias_manager)
2278 self.configurables.append(self.alias_manager)
2279 self.ns_table['alias'] = self.alias_manager.alias_table,
2279 self.ns_table['alias'] = self.alias_manager.alias_table,
2280
2280
2281 #-------------------------------------------------------------------------
2281 #-------------------------------------------------------------------------
2282 # Things related to extensions and plugins
2282 # Things related to extensions and plugins
2283 #-------------------------------------------------------------------------
2283 #-------------------------------------------------------------------------
2284
2284
2285 def init_extension_manager(self):
2285 def init_extension_manager(self):
2286 self.extension_manager = ExtensionManager(shell=self, config=self.config)
2286 self.extension_manager = ExtensionManager(shell=self, config=self.config)
2287 self.configurables.append(self.extension_manager)
2287 self.configurables.append(self.extension_manager)
2288
2288
2289 def init_plugin_manager(self):
2289 def init_plugin_manager(self):
2290 self.plugin_manager = PluginManager(config=self.config)
2290 self.plugin_manager = PluginManager(config=self.config)
2291 self.configurables.append(self.plugin_manager)
2291 self.configurables.append(self.plugin_manager)
2292
2292
2293
2293
2294 #-------------------------------------------------------------------------
2294 #-------------------------------------------------------------------------
2295 # Things related to payloads
2295 # Things related to payloads
2296 #-------------------------------------------------------------------------
2296 #-------------------------------------------------------------------------
2297
2297
2298 def init_payload(self):
2298 def init_payload(self):
2299 self.payload_manager = PayloadManager(config=self.config)
2299 self.payload_manager = PayloadManager(config=self.config)
2300 self.configurables.append(self.payload_manager)
2300 self.configurables.append(self.payload_manager)
2301
2301
2302 #-------------------------------------------------------------------------
2302 #-------------------------------------------------------------------------
2303 # Things related to the prefilter
2303 # Things related to the prefilter
2304 #-------------------------------------------------------------------------
2304 #-------------------------------------------------------------------------
2305
2305
2306 def init_prefilter(self):
2306 def init_prefilter(self):
2307 self.prefilter_manager = PrefilterManager(shell=self, config=self.config)
2307 self.prefilter_manager = PrefilterManager(shell=self, config=self.config)
2308 self.configurables.append(self.prefilter_manager)
2308 self.configurables.append(self.prefilter_manager)
2309 # Ultimately this will be refactored in the new interpreter code, but
2309 # Ultimately this will be refactored in the new interpreter code, but
2310 # for now, we should expose the main prefilter method (there's legacy
2310 # for now, we should expose the main prefilter method (there's legacy
2311 # code out there that may rely on this).
2311 # code out there that may rely on this).
2312 self.prefilter = self.prefilter_manager.prefilter_lines
2312 self.prefilter = self.prefilter_manager.prefilter_lines
2313
2313
2314 def auto_rewrite_input(self, cmd):
2314 def auto_rewrite_input(self, cmd):
2315 """Print to the screen the rewritten form of the user's command.
2315 """Print to the screen the rewritten form of the user's command.
2316
2316
2317 This shows visual feedback by rewriting input lines that cause
2317 This shows visual feedback by rewriting input lines that cause
2318 automatic calling to kick in, like::
2318 automatic calling to kick in, like::
2319
2319
2320 /f x
2320 /f x
2321
2321
2322 into::
2322 into::
2323
2323
2324 ------> f(x)
2324 ------> f(x)
2325
2325
2326 after the user's input prompt. This helps the user understand that the
2326 after the user's input prompt. This helps the user understand that the
2327 input line was transformed automatically by IPython.
2327 input line was transformed automatically by IPython.
2328 """
2328 """
2329 if not self.show_rewritten_input:
2329 if not self.show_rewritten_input:
2330 return
2330 return
2331
2331
2332 rw = self.prompt_manager.render('rewrite') + cmd
2332 rw = self.prompt_manager.render('rewrite') + cmd
2333
2333
2334 try:
2334 try:
2335 # plain ascii works better w/ pyreadline, on some machines, so
2335 # plain ascii works better w/ pyreadline, on some machines, so
2336 # we use it and only print uncolored rewrite if we have unicode
2336 # we use it and only print uncolored rewrite if we have unicode
2337 rw = str(rw)
2337 rw = str(rw)
2338 print >> io.stdout, rw
2338 print >> io.stdout, rw
2339 except UnicodeEncodeError:
2339 except UnicodeEncodeError:
2340 print "------> " + cmd
2340 print "------> " + cmd
2341
2341
2342 #-------------------------------------------------------------------------
2342 #-------------------------------------------------------------------------
2343 # Things related to extracting values/expressions from kernel and user_ns
2343 # Things related to extracting values/expressions from kernel and user_ns
2344 #-------------------------------------------------------------------------
2344 #-------------------------------------------------------------------------
2345
2345
2346 def _simple_error(self):
2346 def _simple_error(self):
2347 etype, value = sys.exc_info()[:2]
2347 etype, value = sys.exc_info()[:2]
2348 return u'[ERROR] {e.__name__}: {v}'.format(e=etype, v=value)
2348 return u'[ERROR] {e.__name__}: {v}'.format(e=etype, v=value)
2349
2349
2350 def user_variables(self, names):
2350 def user_variables(self, names):
2351 """Get a list of variable names from the user's namespace.
2351 """Get a list of variable names from the user's namespace.
2352
2352
2353 Parameters
2353 Parameters
2354 ----------
2354 ----------
2355 names : list of strings
2355 names : list of strings
2356 A list of names of variables to be read from the user namespace.
2356 A list of names of variables to be read from the user namespace.
2357
2357
2358 Returns
2358 Returns
2359 -------
2359 -------
2360 A dict, keyed by the input names and with the repr() of each value.
2360 A dict, keyed by the input names and with the repr() of each value.
2361 """
2361 """
2362 out = {}
2362 out = {}
2363 user_ns = self.user_ns
2363 user_ns = self.user_ns
2364 for varname in names:
2364 for varname in names:
2365 try:
2365 try:
2366 value = repr(user_ns[varname])
2366 value = repr(user_ns[varname])
2367 except:
2367 except:
2368 value = self._simple_error()
2368 value = self._simple_error()
2369 out[varname] = value
2369 out[varname] = value
2370 return out
2370 return out
2371
2371
2372 def user_expressions(self, expressions):
2372 def user_expressions(self, expressions):
2373 """Evaluate a dict of expressions in the user's namespace.
2373 """Evaluate a dict of expressions in the user's namespace.
2374
2374
2375 Parameters
2375 Parameters
2376 ----------
2376 ----------
2377 expressions : dict
2377 expressions : dict
2378 A dict with string keys and string values. The expression values
2378 A dict with string keys and string values. The expression values
2379 should be valid Python expressions, each of which will be evaluated
2379 should be valid Python expressions, each of which will be evaluated
2380 in the user namespace.
2380 in the user namespace.
2381
2381
2382 Returns
2382 Returns
2383 -------
2383 -------
2384 A dict, keyed like the input expressions dict, with the repr() of each
2384 A dict, keyed like the input expressions dict, with the repr() of each
2385 value.
2385 value.
2386 """
2386 """
2387 out = {}
2387 out = {}
2388 user_ns = self.user_ns
2388 user_ns = self.user_ns
2389 global_ns = self.user_global_ns
2389 global_ns = self.user_global_ns
2390 for key, expr in expressions.iteritems():
2390 for key, expr in expressions.iteritems():
2391 try:
2391 try:
2392 value = repr(eval(expr, global_ns, user_ns))
2392 value = repr(eval(expr, global_ns, user_ns))
2393 except:
2393 except:
2394 value = self._simple_error()
2394 value = self._simple_error()
2395 out[key] = value
2395 out[key] = value
2396 return out
2396 return out
2397
2397
2398 #-------------------------------------------------------------------------
2398 #-------------------------------------------------------------------------
2399 # Things related to the running of code
2399 # Things related to the running of code
2400 #-------------------------------------------------------------------------
2400 #-------------------------------------------------------------------------
2401
2401
2402 def ex(self, cmd):
2402 def ex(self, cmd):
2403 """Execute a normal python statement in user namespace."""
2403 """Execute a normal python statement in user namespace."""
2404 with self.builtin_trap:
2404 with self.builtin_trap:
2405 exec cmd in self.user_global_ns, self.user_ns
2405 exec cmd in self.user_global_ns, self.user_ns
2406
2406
2407 def ev(self, expr):
2407 def ev(self, expr):
2408 """Evaluate python expression expr in user namespace.
2408 """Evaluate python expression expr in user namespace.
2409
2409
2410 Returns the result of evaluation
2410 Returns the result of evaluation
2411 """
2411 """
2412 with self.builtin_trap:
2412 with self.builtin_trap:
2413 return eval(expr, self.user_global_ns, self.user_ns)
2413 return eval(expr, self.user_global_ns, self.user_ns)
2414
2414
2415 def safe_execfile(self, fname, *where, **kw):
2415 def safe_execfile(self, fname, *where, **kw):
2416 """A safe version of the builtin execfile().
2416 """A safe version of the builtin execfile().
2417
2417
2418 This version will never throw an exception, but instead print
2418 This version will never throw an exception, but instead print
2419 helpful error messages to the screen. This only works on pure
2419 helpful error messages to the screen. This only works on pure
2420 Python files with the .py extension.
2420 Python files with the .py extension.
2421
2421
2422 Parameters
2422 Parameters
2423 ----------
2423 ----------
2424 fname : string
2424 fname : string
2425 The name of the file to be executed.
2425 The name of the file to be executed.
2426 where : tuple
2426 where : tuple
2427 One or two namespaces, passed to execfile() as (globals,locals).
2427 One or two namespaces, passed to execfile() as (globals,locals).
2428 If only one is given, it is passed as both.
2428 If only one is given, it is passed as both.
2429 exit_ignore : bool (False)
2429 exit_ignore : bool (False)
2430 If True, then silence SystemExit for non-zero status (it is always
2430 If True, then silence SystemExit for non-zero status (it is always
2431 silenced for zero status, as it is so common).
2431 silenced for zero status, as it is so common).
2432 raise_exceptions : bool (False)
2432 raise_exceptions : bool (False)
2433 If True raise exceptions everywhere. Meant for testing.
2433 If True raise exceptions everywhere. Meant for testing.
2434
2434
2435 """
2435 """
2436 kw.setdefault('exit_ignore', False)
2436 kw.setdefault('exit_ignore', False)
2437 kw.setdefault('raise_exceptions', False)
2437 kw.setdefault('raise_exceptions', False)
2438
2438
2439 fname = os.path.abspath(os.path.expanduser(fname))
2439 fname = os.path.abspath(os.path.expanduser(fname))
2440
2440
2441 # Make sure we can open the file
2441 # Make sure we can open the file
2442 try:
2442 try:
2443 with open(fname) as thefile:
2443 with open(fname) as thefile:
2444 pass
2444 pass
2445 except:
2445 except:
2446 warn('Could not open file <%s> for safe execution.' % fname)
2446 warn('Could not open file <%s> for safe execution.' % fname)
2447 return
2447 return
2448
2448
2449 # Find things also in current directory. This is needed to mimic the
2449 # Find things also in current directory. This is needed to mimic the
2450 # behavior of running a script from the system command line, where
2450 # behavior of running a script from the system command line, where
2451 # Python inserts the script's directory into sys.path
2451 # Python inserts the script's directory into sys.path
2452 dname = os.path.dirname(fname)
2452 dname = os.path.dirname(fname)
2453
2453
2454 with prepended_to_syspath(dname):
2454 with prepended_to_syspath(dname):
2455 try:
2455 try:
2456 py3compat.execfile(fname,*where)
2456 py3compat.execfile(fname,*where)
2457 except SystemExit, status:
2457 except SystemExit as status:
2458 # If the call was made with 0 or None exit status (sys.exit(0)
2458 # If the call was made with 0 or None exit status (sys.exit(0)
2459 # or sys.exit() ), don't bother showing a traceback, as both of
2459 # or sys.exit() ), don't bother showing a traceback, as both of
2460 # these are considered normal by the OS:
2460 # these are considered normal by the OS:
2461 # > python -c'import sys;sys.exit(0)'; echo $?
2461 # > python -c'import sys;sys.exit(0)'; echo $?
2462 # 0
2462 # 0
2463 # > python -c'import sys;sys.exit()'; echo $?
2463 # > python -c'import sys;sys.exit()'; echo $?
2464 # 0
2464 # 0
2465 # For other exit status, we show the exception unless
2465 # For other exit status, we show the exception unless
2466 # explicitly silenced, but only in short form.
2466 # explicitly silenced, but only in short form.
2467 if kw['raise_exceptions']:
2467 if kw['raise_exceptions']:
2468 raise
2468 raise
2469 if status.code not in (0, None) and not kw['exit_ignore']:
2469 if status.code not in (0, None) and not kw['exit_ignore']:
2470 self.showtraceback(exception_only=True)
2470 self.showtraceback(exception_only=True)
2471 except:
2471 except:
2472 if kw['raise_exceptions']:
2472 if kw['raise_exceptions']:
2473 raise
2473 raise
2474 self.showtraceback()
2474 self.showtraceback()
2475
2475
2476 def safe_execfile_ipy(self, fname):
2476 def safe_execfile_ipy(self, fname):
2477 """Like safe_execfile, but for .ipy files with IPython syntax.
2477 """Like safe_execfile, but for .ipy files with IPython syntax.
2478
2478
2479 Parameters
2479 Parameters
2480 ----------
2480 ----------
2481 fname : str
2481 fname : str
2482 The name of the file to execute. The filename must have a
2482 The name of the file to execute. The filename must have a
2483 .ipy extension.
2483 .ipy extension.
2484 """
2484 """
2485 fname = os.path.abspath(os.path.expanduser(fname))
2485 fname = os.path.abspath(os.path.expanduser(fname))
2486
2486
2487 # Make sure we can open the file
2487 # Make sure we can open the file
2488 try:
2488 try:
2489 with open(fname) as thefile:
2489 with open(fname) as thefile:
2490 pass
2490 pass
2491 except:
2491 except:
2492 warn('Could not open file <%s> for safe execution.' % fname)
2492 warn('Could not open file <%s> for safe execution.' % fname)
2493 return
2493 return
2494
2494
2495 # Find things also in current directory. This is needed to mimic the
2495 # Find things also in current directory. This is needed to mimic the
2496 # behavior of running a script from the system command line, where
2496 # behavior of running a script from the system command line, where
2497 # Python inserts the script's directory into sys.path
2497 # Python inserts the script's directory into sys.path
2498 dname = os.path.dirname(fname)
2498 dname = os.path.dirname(fname)
2499
2499
2500 with prepended_to_syspath(dname):
2500 with prepended_to_syspath(dname):
2501 try:
2501 try:
2502 with open(fname) as thefile:
2502 with open(fname) as thefile:
2503 # self.run_cell currently captures all exceptions
2503 # self.run_cell currently captures all exceptions
2504 # raised in user code. It would be nice if there were
2504 # raised in user code. It would be nice if there were
2505 # versions of runlines, execfile that did raise, so
2505 # versions of runlines, execfile that did raise, so
2506 # we could catch the errors.
2506 # we could catch the errors.
2507 self.run_cell(thefile.read(), store_history=False)
2507 self.run_cell(thefile.read(), store_history=False)
2508 except:
2508 except:
2509 self.showtraceback()
2509 self.showtraceback()
2510 warn('Unknown failure executing file: <%s>' % fname)
2510 warn('Unknown failure executing file: <%s>' % fname)
2511
2511
2512 def safe_run_module(self, mod_name, where):
2512 def safe_run_module(self, mod_name, where):
2513 """A safe version of runpy.run_module().
2513 """A safe version of runpy.run_module().
2514
2514
2515 This version will never throw an exception, but instead print
2515 This version will never throw an exception, but instead print
2516 helpful error messages to the screen.
2516 helpful error messages to the screen.
2517
2517
2518 Parameters
2518 Parameters
2519 ----------
2519 ----------
2520 mod_name : string
2520 mod_name : string
2521 The name of the module to be executed.
2521 The name of the module to be executed.
2522 where : dict
2522 where : dict
2523 The globals namespace.
2523 The globals namespace.
2524 """
2524 """
2525 try:
2525 try:
2526 where.update(
2526 where.update(
2527 runpy.run_module(str(mod_name), run_name="__main__",
2527 runpy.run_module(str(mod_name), run_name="__main__",
2528 alter_sys=True)
2528 alter_sys=True)
2529 )
2529 )
2530 except:
2530 except:
2531 self.showtraceback()
2531 self.showtraceback()
2532 warn('Unknown failure executing module: <%s>' % mod_name)
2532 warn('Unknown failure executing module: <%s>' % mod_name)
2533
2533
2534 def _run_cached_cell_magic(self, magic_name, line):
2534 def _run_cached_cell_magic(self, magic_name, line):
2535 """Special method to call a cell magic with the data stored in self.
2535 """Special method to call a cell magic with the data stored in self.
2536 """
2536 """
2537 cell = self._current_cell_magic_body
2537 cell = self._current_cell_magic_body
2538 self._current_cell_magic_body = None
2538 self._current_cell_magic_body = None
2539 return self.run_cell_magic(magic_name, line, cell)
2539 return self.run_cell_magic(magic_name, line, cell)
2540
2540
2541 def run_cell(self, raw_cell, store_history=False, silent=False):
2541 def run_cell(self, raw_cell, store_history=False, silent=False):
2542 """Run a complete IPython cell.
2542 """Run a complete IPython cell.
2543
2543
2544 Parameters
2544 Parameters
2545 ----------
2545 ----------
2546 raw_cell : str
2546 raw_cell : str
2547 The code (including IPython code such as %magic functions) to run.
2547 The code (including IPython code such as %magic functions) to run.
2548 store_history : bool
2548 store_history : bool
2549 If True, the raw and translated cell will be stored in IPython's
2549 If True, the raw and translated cell will be stored in IPython's
2550 history. For user code calling back into IPython's machinery, this
2550 history. For user code calling back into IPython's machinery, this
2551 should be set to False.
2551 should be set to False.
2552 silent : bool
2552 silent : bool
2553 If True, avoid side-effets, such as implicit displayhooks, history,
2553 If True, avoid side-effets, such as implicit displayhooks, history,
2554 and logging. silent=True forces store_history=False.
2554 and logging. silent=True forces store_history=False.
2555 """
2555 """
2556 if (not raw_cell) or raw_cell.isspace():
2556 if (not raw_cell) or raw_cell.isspace():
2557 return
2557 return
2558
2558
2559 if silent:
2559 if silent:
2560 store_history = False
2560 store_history = False
2561
2561
2562 self.input_splitter.push(raw_cell)
2562 self.input_splitter.push(raw_cell)
2563
2563
2564 # Check for cell magics, which leave state behind. This interface is
2564 # Check for cell magics, which leave state behind. This interface is
2565 # ugly, we need to do something cleaner later... Now the logic is
2565 # ugly, we need to do something cleaner later... Now the logic is
2566 # simply that the input_splitter remembers if there was a cell magic,
2566 # simply that the input_splitter remembers if there was a cell magic,
2567 # and in that case we grab the cell body.
2567 # and in that case we grab the cell body.
2568 if self.input_splitter.cell_magic_parts:
2568 if self.input_splitter.cell_magic_parts:
2569 self._current_cell_magic_body = \
2569 self._current_cell_magic_body = \
2570 ''.join(self.input_splitter.cell_magic_parts)
2570 ''.join(self.input_splitter.cell_magic_parts)
2571 cell = self.input_splitter.source_reset()
2571 cell = self.input_splitter.source_reset()
2572
2572
2573 with self.builtin_trap:
2573 with self.builtin_trap:
2574 prefilter_failed = False
2574 prefilter_failed = False
2575 if len(cell.splitlines()) == 1:
2575 if len(cell.splitlines()) == 1:
2576 try:
2576 try:
2577 # use prefilter_lines to handle trailing newlines
2577 # use prefilter_lines to handle trailing newlines
2578 # restore trailing newline for ast.parse
2578 # restore trailing newline for ast.parse
2579 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
2579 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
2580 except AliasError as e:
2580 except AliasError as e:
2581 error(e)
2581 error(e)
2582 prefilter_failed = True
2582 prefilter_failed = True
2583 except Exception:
2583 except Exception:
2584 # don't allow prefilter errors to crash IPython
2584 # don't allow prefilter errors to crash IPython
2585 self.showtraceback()
2585 self.showtraceback()
2586 prefilter_failed = True
2586 prefilter_failed = True
2587
2587
2588 # Store raw and processed history
2588 # Store raw and processed history
2589 if store_history:
2589 if store_history:
2590 self.history_manager.store_inputs(self.execution_count,
2590 self.history_manager.store_inputs(self.execution_count,
2591 cell, raw_cell)
2591 cell, raw_cell)
2592 if not silent:
2592 if not silent:
2593 self.logger.log(cell, raw_cell)
2593 self.logger.log(cell, raw_cell)
2594
2594
2595 if not prefilter_failed:
2595 if not prefilter_failed:
2596 # don't run if prefilter failed
2596 # don't run if prefilter failed
2597 cell_name = self.compile.cache(cell, self.execution_count)
2597 cell_name = self.compile.cache(cell, self.execution_count)
2598
2598
2599 with self.display_trap:
2599 with self.display_trap:
2600 try:
2600 try:
2601 code_ast = self.compile.ast_parse(cell,
2601 code_ast = self.compile.ast_parse(cell,
2602 filename=cell_name)
2602 filename=cell_name)
2603 except IndentationError:
2603 except IndentationError:
2604 self.showindentationerror()
2604 self.showindentationerror()
2605 if store_history:
2605 if store_history:
2606 self.execution_count += 1
2606 self.execution_count += 1
2607 return None
2607 return None
2608 except (OverflowError, SyntaxError, ValueError, TypeError,
2608 except (OverflowError, SyntaxError, ValueError, TypeError,
2609 MemoryError):
2609 MemoryError):
2610 self.showsyntaxerror()
2610 self.showsyntaxerror()
2611 if store_history:
2611 if store_history:
2612 self.execution_count += 1
2612 self.execution_count += 1
2613 return None
2613 return None
2614
2614
2615 interactivity = "none" if silent else self.ast_node_interactivity
2615 interactivity = "none" if silent else self.ast_node_interactivity
2616 self.run_ast_nodes(code_ast.body, cell_name,
2616 self.run_ast_nodes(code_ast.body, cell_name,
2617 interactivity=interactivity)
2617 interactivity=interactivity)
2618
2618
2619 # Execute any registered post-execution functions.
2619 # Execute any registered post-execution functions.
2620 # unless we are silent
2620 # unless we are silent
2621 post_exec = [] if silent else self._post_execute.iteritems()
2621 post_exec = [] if silent else self._post_execute.iteritems()
2622
2622
2623 for func, status in post_exec:
2623 for func, status in post_exec:
2624 if self.disable_failing_post_execute and not status:
2624 if self.disable_failing_post_execute and not status:
2625 continue
2625 continue
2626 try:
2626 try:
2627 func()
2627 func()
2628 except KeyboardInterrupt:
2628 except KeyboardInterrupt:
2629 print >> io.stderr, "\nKeyboardInterrupt"
2629 print >> io.stderr, "\nKeyboardInterrupt"
2630 except Exception:
2630 except Exception:
2631 # register as failing:
2631 # register as failing:
2632 self._post_execute[func] = False
2632 self._post_execute[func] = False
2633 self.showtraceback()
2633 self.showtraceback()
2634 print >> io.stderr, '\n'.join([
2634 print >> io.stderr, '\n'.join([
2635 "post-execution function %r produced an error." % func,
2635 "post-execution function %r produced an error." % func,
2636 "If this problem persists, you can disable failing post-exec functions with:",
2636 "If this problem persists, you can disable failing post-exec functions with:",
2637 "",
2637 "",
2638 " get_ipython().disable_failing_post_execute = True"
2638 " get_ipython().disable_failing_post_execute = True"
2639 ])
2639 ])
2640
2640
2641 if store_history:
2641 if store_history:
2642 # Write output to the database. Does nothing unless
2642 # Write output to the database. Does nothing unless
2643 # history output logging is enabled.
2643 # history output logging is enabled.
2644 self.history_manager.store_output(self.execution_count)
2644 self.history_manager.store_output(self.execution_count)
2645 # Each cell is a *single* input, regardless of how many lines it has
2645 # Each cell is a *single* input, regardless of how many lines it has
2646 self.execution_count += 1
2646 self.execution_count += 1
2647
2647
2648 def run_ast_nodes(self, nodelist, cell_name, interactivity='last_expr'):
2648 def run_ast_nodes(self, nodelist, cell_name, interactivity='last_expr'):
2649 """Run a sequence of AST nodes. The execution mode depends on the
2649 """Run a sequence of AST nodes. The execution mode depends on the
2650 interactivity parameter.
2650 interactivity parameter.
2651
2651
2652 Parameters
2652 Parameters
2653 ----------
2653 ----------
2654 nodelist : list
2654 nodelist : list
2655 A sequence of AST nodes to run.
2655 A sequence of AST nodes to run.
2656 cell_name : str
2656 cell_name : str
2657 Will be passed to the compiler as the filename of the cell. Typically
2657 Will be passed to the compiler as the filename of the cell. Typically
2658 the value returned by ip.compile.cache(cell).
2658 the value returned by ip.compile.cache(cell).
2659 interactivity : str
2659 interactivity : str
2660 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
2660 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
2661 run interactively (displaying output from expressions). 'last_expr'
2661 run interactively (displaying output from expressions). 'last_expr'
2662 will run the last node interactively only if it is an expression (i.e.
2662 will run the last node interactively only if it is an expression (i.e.
2663 expressions in loops or other blocks are not displayed. Other values
2663 expressions in loops or other blocks are not displayed. Other values
2664 for this parameter will raise a ValueError.
2664 for this parameter will raise a ValueError.
2665 """
2665 """
2666 if not nodelist:
2666 if not nodelist:
2667 return
2667 return
2668
2668
2669 if interactivity == 'last_expr':
2669 if interactivity == 'last_expr':
2670 if isinstance(nodelist[-1], ast.Expr):
2670 if isinstance(nodelist[-1], ast.Expr):
2671 interactivity = "last"
2671 interactivity = "last"
2672 else:
2672 else:
2673 interactivity = "none"
2673 interactivity = "none"
2674
2674
2675 if interactivity == 'none':
2675 if interactivity == 'none':
2676 to_run_exec, to_run_interactive = nodelist, []
2676 to_run_exec, to_run_interactive = nodelist, []
2677 elif interactivity == 'last':
2677 elif interactivity == 'last':
2678 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
2678 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
2679 elif interactivity == 'all':
2679 elif interactivity == 'all':
2680 to_run_exec, to_run_interactive = [], nodelist
2680 to_run_exec, to_run_interactive = [], nodelist
2681 else:
2681 else:
2682 raise ValueError("Interactivity was %r" % interactivity)
2682 raise ValueError("Interactivity was %r" % interactivity)
2683
2683
2684 exec_count = self.execution_count
2684 exec_count = self.execution_count
2685
2685
2686 try:
2686 try:
2687 for i, node in enumerate(to_run_exec):
2687 for i, node in enumerate(to_run_exec):
2688 mod = ast.Module([node])
2688 mod = ast.Module([node])
2689 code = self.compile(mod, cell_name, "exec")
2689 code = self.compile(mod, cell_name, "exec")
2690 if self.run_code(code):
2690 if self.run_code(code):
2691 return True
2691 return True
2692
2692
2693 for i, node in enumerate(to_run_interactive):
2693 for i, node in enumerate(to_run_interactive):
2694 mod = ast.Interactive([node])
2694 mod = ast.Interactive([node])
2695 code = self.compile(mod, cell_name, "single")
2695 code = self.compile(mod, cell_name, "single")
2696 if self.run_code(code):
2696 if self.run_code(code):
2697 return True
2697 return True
2698
2698
2699 # Flush softspace
2699 # Flush softspace
2700 if softspace(sys.stdout, 0):
2700 if softspace(sys.stdout, 0):
2701 print
2701 print
2702
2702
2703 except:
2703 except:
2704 # It's possible to have exceptions raised here, typically by
2704 # It's possible to have exceptions raised here, typically by
2705 # compilation of odd code (such as a naked 'return' outside a
2705 # compilation of odd code (such as a naked 'return' outside a
2706 # function) that did parse but isn't valid. Typically the exception
2706 # function) that did parse but isn't valid. Typically the exception
2707 # is a SyntaxError, but it's safest just to catch anything and show
2707 # is a SyntaxError, but it's safest just to catch anything and show
2708 # the user a traceback.
2708 # the user a traceback.
2709
2709
2710 # We do only one try/except outside the loop to minimize the impact
2710 # We do only one try/except outside the loop to minimize the impact
2711 # on runtime, and also because if any node in the node list is
2711 # on runtime, and also because if any node in the node list is
2712 # broken, we should stop execution completely.
2712 # broken, we should stop execution completely.
2713 self.showtraceback()
2713 self.showtraceback()
2714
2714
2715 return False
2715 return False
2716
2716
2717 def run_code(self, code_obj):
2717 def run_code(self, code_obj):
2718 """Execute a code object.
2718 """Execute a code object.
2719
2719
2720 When an exception occurs, self.showtraceback() is called to display a
2720 When an exception occurs, self.showtraceback() is called to display a
2721 traceback.
2721 traceback.
2722
2722
2723 Parameters
2723 Parameters
2724 ----------
2724 ----------
2725 code_obj : code object
2725 code_obj : code object
2726 A compiled code object, to be executed
2726 A compiled code object, to be executed
2727
2727
2728 Returns
2728 Returns
2729 -------
2729 -------
2730 False : successful execution.
2730 False : successful execution.
2731 True : an error occurred.
2731 True : an error occurred.
2732 """
2732 """
2733
2733
2734 # Set our own excepthook in case the user code tries to call it
2734 # Set our own excepthook in case the user code tries to call it
2735 # directly, so that the IPython crash handler doesn't get triggered
2735 # directly, so that the IPython crash handler doesn't get triggered
2736 old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
2736 old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
2737
2737
2738 # we save the original sys.excepthook in the instance, in case config
2738 # we save the original sys.excepthook in the instance, in case config
2739 # code (such as magics) needs access to it.
2739 # code (such as magics) needs access to it.
2740 self.sys_excepthook = old_excepthook
2740 self.sys_excepthook = old_excepthook
2741 outflag = 1 # happens in more places, so it's easier as default
2741 outflag = 1 # happens in more places, so it's easier as default
2742 try:
2742 try:
2743 try:
2743 try:
2744 self.hooks.pre_run_code_hook()
2744 self.hooks.pre_run_code_hook()
2745 #rprint('Running code', repr(code_obj)) # dbg
2745 #rprint('Running code', repr(code_obj)) # dbg
2746 exec code_obj in self.user_global_ns, self.user_ns
2746 exec code_obj in self.user_global_ns, self.user_ns
2747 finally:
2747 finally:
2748 # Reset our crash handler in place
2748 # Reset our crash handler in place
2749 sys.excepthook = old_excepthook
2749 sys.excepthook = old_excepthook
2750 except SystemExit:
2750 except SystemExit:
2751 self.showtraceback(exception_only=True)
2751 self.showtraceback(exception_only=True)
2752 warn("To exit: use 'exit', 'quit', or Ctrl-D.", level=1)
2752 warn("To exit: use 'exit', 'quit', or Ctrl-D.", level=1)
2753 except self.custom_exceptions:
2753 except self.custom_exceptions:
2754 etype,value,tb = sys.exc_info()
2754 etype,value,tb = sys.exc_info()
2755 self.CustomTB(etype,value,tb)
2755 self.CustomTB(etype,value,tb)
2756 except:
2756 except:
2757 self.showtraceback()
2757 self.showtraceback()
2758 else:
2758 else:
2759 outflag = 0
2759 outflag = 0
2760 return outflag
2760 return outflag
2761
2761
2762 # For backwards compatibility
2762 # For backwards compatibility
2763 runcode = run_code
2763 runcode = run_code
2764
2764
2765 #-------------------------------------------------------------------------
2765 #-------------------------------------------------------------------------
2766 # Things related to GUI support and pylab
2766 # Things related to GUI support and pylab
2767 #-------------------------------------------------------------------------
2767 #-------------------------------------------------------------------------
2768
2768
2769 def enable_gui(self, gui=None):
2769 def enable_gui(self, gui=None):
2770 raise NotImplementedError('Implement enable_gui in a subclass')
2770 raise NotImplementedError('Implement enable_gui in a subclass')
2771
2771
2772 def enable_pylab(self, gui=None, import_all=True):
2772 def enable_pylab(self, gui=None, import_all=True):
2773 """Activate pylab support at runtime.
2773 """Activate pylab support at runtime.
2774
2774
2775 This turns on support for matplotlib, preloads into the interactive
2775 This turns on support for matplotlib, preloads into the interactive
2776 namespace all of numpy and pylab, and configures IPython to correctly
2776 namespace all of numpy and pylab, and configures IPython to correctly
2777 interact with the GUI event loop. The GUI backend to be used can be
2777 interact with the GUI event loop. The GUI backend to be used can be
2778 optionally selected with the optional :param:`gui` argument.
2778 optionally selected with the optional :param:`gui` argument.
2779
2779
2780 Parameters
2780 Parameters
2781 ----------
2781 ----------
2782 gui : optional, string
2782 gui : optional, string
2783
2783
2784 If given, dictates the choice of matplotlib GUI backend to use
2784 If given, dictates the choice of matplotlib GUI backend to use
2785 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
2785 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
2786 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
2786 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
2787 matplotlib (as dictated by the matplotlib build-time options plus the
2787 matplotlib (as dictated by the matplotlib build-time options plus the
2788 user's matplotlibrc configuration file). Note that not all backends
2788 user's matplotlibrc configuration file). Note that not all backends
2789 make sense in all contexts, for example a terminal ipython can't
2789 make sense in all contexts, for example a terminal ipython can't
2790 display figures inline.
2790 display figures inline.
2791 """
2791 """
2792 from IPython.core.pylabtools import mpl_runner
2792 from IPython.core.pylabtools import mpl_runner
2793 # We want to prevent the loading of pylab to pollute the user's
2793 # We want to prevent the loading of pylab to pollute the user's
2794 # namespace as shown by the %who* magics, so we execute the activation
2794 # namespace as shown by the %who* magics, so we execute the activation
2795 # code in an empty namespace, and we update *both* user_ns and
2795 # code in an empty namespace, and we update *both* user_ns and
2796 # user_ns_hidden with this information.
2796 # user_ns_hidden with this information.
2797 ns = {}
2797 ns = {}
2798 try:
2798 try:
2799 gui = pylab_activate(ns, gui, import_all, self)
2799 gui = pylab_activate(ns, gui, import_all, self)
2800 except KeyError:
2800 except KeyError:
2801 error("Backend %r not supported" % gui)
2801 error("Backend %r not supported" % gui)
2802 return
2802 return
2803 self.user_ns.update(ns)
2803 self.user_ns.update(ns)
2804 self.user_ns_hidden.update(ns)
2804 self.user_ns_hidden.update(ns)
2805 # Now we must activate the gui pylab wants to use, and fix %run to take
2805 # Now we must activate the gui pylab wants to use, and fix %run to take
2806 # plot updates into account
2806 # plot updates into account
2807 self.enable_gui(gui)
2807 self.enable_gui(gui)
2808 self.magics_manager.registry['ExecutionMagics'].default_runner = \
2808 self.magics_manager.registry['ExecutionMagics'].default_runner = \
2809 mpl_runner(self.safe_execfile)
2809 mpl_runner(self.safe_execfile)
2810
2810
2811 #-------------------------------------------------------------------------
2811 #-------------------------------------------------------------------------
2812 # Utilities
2812 # Utilities
2813 #-------------------------------------------------------------------------
2813 #-------------------------------------------------------------------------
2814
2814
2815 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
2815 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
2816 """Expand python variables in a string.
2816 """Expand python variables in a string.
2817
2817
2818 The depth argument indicates how many frames above the caller should
2818 The depth argument indicates how many frames above the caller should
2819 be walked to look for the local namespace where to expand variables.
2819 be walked to look for the local namespace where to expand variables.
2820
2820
2821 The global namespace for expansion is always the user's interactive
2821 The global namespace for expansion is always the user's interactive
2822 namespace.
2822 namespace.
2823 """
2823 """
2824 ns = self.user_ns.copy()
2824 ns = self.user_ns.copy()
2825 ns.update(sys._getframe(depth+1).f_locals)
2825 ns.update(sys._getframe(depth+1).f_locals)
2826 ns.pop('self', None)
2826 ns.pop('self', None)
2827 try:
2827 try:
2828 cmd = formatter.format(cmd, **ns)
2828 cmd = formatter.format(cmd, **ns)
2829 except Exception:
2829 except Exception:
2830 # if formatter couldn't format, just let it go untransformed
2830 # if formatter couldn't format, just let it go untransformed
2831 pass
2831 pass
2832 return cmd
2832 return cmd
2833
2833
2834 def mktempfile(self, data=None, prefix='ipython_edit_'):
2834 def mktempfile(self, data=None, prefix='ipython_edit_'):
2835 """Make a new tempfile and return its filename.
2835 """Make a new tempfile and return its filename.
2836
2836
2837 This makes a call to tempfile.mktemp, but it registers the created
2837 This makes a call to tempfile.mktemp, but it registers the created
2838 filename internally so ipython cleans it up at exit time.
2838 filename internally so ipython cleans it up at exit time.
2839
2839
2840 Optional inputs:
2840 Optional inputs:
2841
2841
2842 - data(None): if data is given, it gets written out to the temp file
2842 - data(None): if data is given, it gets written out to the temp file
2843 immediately, and the file is closed again."""
2843 immediately, and the file is closed again."""
2844
2844
2845 filename = tempfile.mktemp('.py', prefix)
2845 filename = tempfile.mktemp('.py', prefix)
2846 self.tempfiles.append(filename)
2846 self.tempfiles.append(filename)
2847
2847
2848 if data:
2848 if data:
2849 tmp_file = open(filename,'w')
2849 tmp_file = open(filename,'w')
2850 tmp_file.write(data)
2850 tmp_file.write(data)
2851 tmp_file.close()
2851 tmp_file.close()
2852 return filename
2852 return filename
2853
2853
2854 # TODO: This should be removed when Term is refactored.
2854 # TODO: This should be removed when Term is refactored.
2855 def write(self,data):
2855 def write(self,data):
2856 """Write a string to the default output"""
2856 """Write a string to the default output"""
2857 io.stdout.write(data)
2857 io.stdout.write(data)
2858
2858
2859 # TODO: This should be removed when Term is refactored.
2859 # TODO: This should be removed when Term is refactored.
2860 def write_err(self,data):
2860 def write_err(self,data):
2861 """Write a string to the default error output"""
2861 """Write a string to the default error output"""
2862 io.stderr.write(data)
2862 io.stderr.write(data)
2863
2863
2864 def ask_yes_no(self, prompt, default=None):
2864 def ask_yes_no(self, prompt, default=None):
2865 if self.quiet:
2865 if self.quiet:
2866 return True
2866 return True
2867 return ask_yes_no(prompt,default)
2867 return ask_yes_no(prompt,default)
2868
2868
2869 def show_usage(self):
2869 def show_usage(self):
2870 """Show a usage message"""
2870 """Show a usage message"""
2871 page.page(IPython.core.usage.interactive_usage)
2871 page.page(IPython.core.usage.interactive_usage)
2872
2872
2873 def extract_input_lines(self, range_str, raw=False):
2873 def extract_input_lines(self, range_str, raw=False):
2874 """Return as a string a set of input history slices.
2874 """Return as a string a set of input history slices.
2875
2875
2876 Parameters
2876 Parameters
2877 ----------
2877 ----------
2878 range_str : string
2878 range_str : string
2879 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
2879 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
2880 since this function is for use by magic functions which get their
2880 since this function is for use by magic functions which get their
2881 arguments as strings. The number before the / is the session
2881 arguments as strings. The number before the / is the session
2882 number: ~n goes n back from the current session.
2882 number: ~n goes n back from the current session.
2883
2883
2884 Optional Parameters:
2884 Optional Parameters:
2885 - raw(False): by default, the processed input is used. If this is
2885 - raw(False): by default, the processed input is used. If this is
2886 true, the raw input history is used instead.
2886 true, the raw input history is used instead.
2887
2887
2888 Note that slices can be called with two notations:
2888 Note that slices can be called with two notations:
2889
2889
2890 N:M -> standard python form, means including items N...(M-1).
2890 N:M -> standard python form, means including items N...(M-1).
2891
2891
2892 N-M -> include items N..M (closed endpoint)."""
2892 N-M -> include items N..M (closed endpoint)."""
2893 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
2893 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
2894 return "\n".join(x for _, _, x in lines)
2894 return "\n".join(x for _, _, x in lines)
2895
2895
2896 def find_user_code(self, target, raw=True, py_only=False):
2896 def find_user_code(self, target, raw=True, py_only=False):
2897 """Get a code string from history, file, url, or a string or macro.
2897 """Get a code string from history, file, url, or a string or macro.
2898
2898
2899 This is mainly used by magic functions.
2899 This is mainly used by magic functions.
2900
2900
2901 Parameters
2901 Parameters
2902 ----------
2902 ----------
2903
2903
2904 target : str
2904 target : str
2905
2905
2906 A string specifying code to retrieve. This will be tried respectively
2906 A string specifying code to retrieve. This will be tried respectively
2907 as: ranges of input history (see %history for syntax), url,
2907 as: ranges of input history (see %history for syntax), url,
2908 correspnding .py file, filename, or an expression evaluating to a
2908 correspnding .py file, filename, or an expression evaluating to a
2909 string or Macro in the user namespace.
2909 string or Macro in the user namespace.
2910
2910
2911 raw : bool
2911 raw : bool
2912 If true (default), retrieve raw history. Has no effect on the other
2912 If true (default), retrieve raw history. Has no effect on the other
2913 retrieval mechanisms.
2913 retrieval mechanisms.
2914
2914
2915 py_only : bool (default False)
2915 py_only : bool (default False)
2916 Only try to fetch python code, do not try alternative methods to decode file
2916 Only try to fetch python code, do not try alternative methods to decode file
2917 if unicode fails.
2917 if unicode fails.
2918
2918
2919 Returns
2919 Returns
2920 -------
2920 -------
2921 A string of code.
2921 A string of code.
2922
2922
2923 ValueError is raised if nothing is found, and TypeError if it evaluates
2923 ValueError is raised if nothing is found, and TypeError if it evaluates
2924 to an object of another type. In each case, .args[0] is a printable
2924 to an object of another type. In each case, .args[0] is a printable
2925 message.
2925 message.
2926 """
2926 """
2927 code = self.extract_input_lines(target, raw=raw) # Grab history
2927 code = self.extract_input_lines(target, raw=raw) # Grab history
2928 if code:
2928 if code:
2929 return code
2929 return code
2930 utarget = unquote_filename(target)
2930 utarget = unquote_filename(target)
2931 try:
2931 try:
2932 if utarget.startswith(('http://', 'https://')):
2932 if utarget.startswith(('http://', 'https://')):
2933 return openpy.read_py_url(utarget, skip_encoding_cookie=True)
2933 return openpy.read_py_url(utarget, skip_encoding_cookie=True)
2934 except UnicodeDecodeError:
2934 except UnicodeDecodeError:
2935 if not py_only :
2935 if not py_only :
2936 response = urllib.urlopen(target)
2936 response = urllib.urlopen(target)
2937 return response.read().decode('latin1')
2937 return response.read().decode('latin1')
2938 raise ValueError(("'%s' seem to be unreadable.") % utarget)
2938 raise ValueError(("'%s' seem to be unreadable.") % utarget)
2939
2939
2940 potential_target = [target]
2940 potential_target = [target]
2941 try :
2941 try :
2942 potential_target.insert(0,get_py_filename(target))
2942 potential_target.insert(0,get_py_filename(target))
2943 except IOError:
2943 except IOError:
2944 pass
2944 pass
2945
2945
2946 for tgt in potential_target :
2946 for tgt in potential_target :
2947 if os.path.isfile(tgt): # Read file
2947 if os.path.isfile(tgt): # Read file
2948 try :
2948 try :
2949 return openpy.read_py_file(tgt, skip_encoding_cookie=True)
2949 return openpy.read_py_file(tgt, skip_encoding_cookie=True)
2950 except UnicodeDecodeError :
2950 except UnicodeDecodeError :
2951 if not py_only :
2951 if not py_only :
2952 with io_open(tgt,'r', encoding='latin1') as f :
2952 with io_open(tgt,'r', encoding='latin1') as f :
2953 return f.read()
2953 return f.read()
2954 raise ValueError(("'%s' seem to be unreadable.") % target)
2954 raise ValueError(("'%s' seem to be unreadable.") % target)
2955
2955
2956 try: # User namespace
2956 try: # User namespace
2957 codeobj = eval(target, self.user_ns)
2957 codeobj = eval(target, self.user_ns)
2958 except Exception:
2958 except Exception:
2959 raise ValueError(("'%s' was not found in history, as a file, url, "
2959 raise ValueError(("'%s' was not found in history, as a file, url, "
2960 "nor in the user namespace.") % target)
2960 "nor in the user namespace.") % target)
2961 if isinstance(codeobj, basestring):
2961 if isinstance(codeobj, basestring):
2962 return codeobj
2962 return codeobj
2963 elif isinstance(codeobj, Macro):
2963 elif isinstance(codeobj, Macro):
2964 return codeobj.value
2964 return codeobj.value
2965
2965
2966 raise TypeError("%s is neither a string nor a macro." % target,
2966 raise TypeError("%s is neither a string nor a macro." % target,
2967 codeobj)
2967 codeobj)
2968
2968
2969 #-------------------------------------------------------------------------
2969 #-------------------------------------------------------------------------
2970 # Things related to IPython exiting
2970 # Things related to IPython exiting
2971 #-------------------------------------------------------------------------
2971 #-------------------------------------------------------------------------
2972 def atexit_operations(self):
2972 def atexit_operations(self):
2973 """This will be executed at the time of exit.
2973 """This will be executed at the time of exit.
2974
2974
2975 Cleanup operations and saving of persistent data that is done
2975 Cleanup operations and saving of persistent data that is done
2976 unconditionally by IPython should be performed here.
2976 unconditionally by IPython should be performed here.
2977
2977
2978 For things that may depend on startup flags or platform specifics (such
2978 For things that may depend on startup flags or platform specifics (such
2979 as having readline or not), register a separate atexit function in the
2979 as having readline or not), register a separate atexit function in the
2980 code that has the appropriate information, rather than trying to
2980 code that has the appropriate information, rather than trying to
2981 clutter
2981 clutter
2982 """
2982 """
2983 # Close the history session (this stores the end time and line count)
2983 # Close the history session (this stores the end time and line count)
2984 # this must be *before* the tempfile cleanup, in case of temporary
2984 # this must be *before* the tempfile cleanup, in case of temporary
2985 # history db
2985 # history db
2986 self.history_manager.end_session()
2986 self.history_manager.end_session()
2987
2987
2988 # Cleanup all tempfiles left around
2988 # Cleanup all tempfiles left around
2989 for tfile in self.tempfiles:
2989 for tfile in self.tempfiles:
2990 try:
2990 try:
2991 os.unlink(tfile)
2991 os.unlink(tfile)
2992 except OSError:
2992 except OSError:
2993 pass
2993 pass
2994
2994
2995 # Clear all user namespaces to release all references cleanly.
2995 # Clear all user namespaces to release all references cleanly.
2996 self.reset(new_session=False)
2996 self.reset(new_session=False)
2997
2997
2998 # Run user hooks
2998 # Run user hooks
2999 self.hooks.shutdown_hook()
2999 self.hooks.shutdown_hook()
3000
3000
3001 def cleanup(self):
3001 def cleanup(self):
3002 self.restore_sys_module_state()
3002 self.restore_sys_module_state()
3003
3003
3004
3004
3005 class InteractiveShellABC(object):
3005 class InteractiveShellABC(object):
3006 """An abstract base class for InteractiveShell."""
3006 """An abstract base class for InteractiveShell."""
3007 __metaclass__ = abc.ABCMeta
3007 __metaclass__ = abc.ABCMeta
3008
3008
3009 InteractiveShellABC.register(InteractiveShell)
3009 InteractiveShellABC.register(InteractiveShell)
@@ -1,617 +1,617 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Magic functions for InteractiveShell.
2 """Magic functions for InteractiveShell.
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
6 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
7 # Copyright (C) 2001 Fernando Perez <fperez@colorado.edu>
7 # Copyright (C) 2001 Fernando Perez <fperez@colorado.edu>
8 # Copyright (C) 2008 The IPython Development Team
8 # Copyright (C) 2008 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 # Stdlib
17 # Stdlib
18 import os
18 import os
19 import re
19 import re
20 import sys
20 import sys
21 import types
21 import types
22 from getopt import getopt, GetoptError
22 from getopt import getopt, GetoptError
23
23
24 # Our own
24 # Our own
25 from IPython.config.configurable import Configurable
25 from IPython.config.configurable import Configurable
26 from IPython.core import oinspect
26 from IPython.core import oinspect
27 from IPython.core.error import UsageError
27 from IPython.core.error import UsageError
28 from IPython.core.inputsplitter import ESC_MAGIC, ESC_MAGIC2
28 from IPython.core.inputsplitter import ESC_MAGIC, ESC_MAGIC2
29 from IPython.external.decorator import decorator
29 from IPython.external.decorator import decorator
30 from IPython.utils.ipstruct import Struct
30 from IPython.utils.ipstruct import Struct
31 from IPython.utils.process import arg_split
31 from IPython.utils.process import arg_split
32 from IPython.utils.text import dedent
32 from IPython.utils.text import dedent
33 from IPython.utils.traitlets import Bool, Dict, Instance, MetaHasTraits
33 from IPython.utils.traitlets import Bool, Dict, Instance, MetaHasTraits
34 from IPython.utils.warn import error, warn
34 from IPython.utils.warn import error, warn
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Globals
37 # Globals
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40 # A dict we'll use for each class that has magics, used as temporary storage to
40 # A dict we'll use for each class that has magics, used as temporary storage to
41 # pass information between the @line/cell_magic method decorators and the
41 # pass information between the @line/cell_magic method decorators and the
42 # @magics_class class decorator, because the method decorators have no
42 # @magics_class class decorator, because the method decorators have no
43 # access to the class when they run. See for more details:
43 # access to the class when they run. See for more details:
44 # http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class
44 # http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class
45
45
46 magics = dict(line={}, cell={})
46 magics = dict(line={}, cell={})
47
47
48 magic_kinds = ('line', 'cell')
48 magic_kinds = ('line', 'cell')
49 magic_spec = ('line', 'cell', 'line_cell')
49 magic_spec = ('line', 'cell', 'line_cell')
50 magic_escapes = dict(line=ESC_MAGIC, cell=ESC_MAGIC2)
50 magic_escapes = dict(line=ESC_MAGIC, cell=ESC_MAGIC2)
51
51
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53 # Utility classes and functions
53 # Utility classes and functions
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55
55
56 class Bunch: pass
56 class Bunch: pass
57
57
58
58
59 def on_off(tag):
59 def on_off(tag):
60 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
60 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
61 return ['OFF','ON'][tag]
61 return ['OFF','ON'][tag]
62
62
63
63
64 def compress_dhist(dh):
64 def compress_dhist(dh):
65 """Compress a directory history into a new one with at most 20 entries.
65 """Compress a directory history into a new one with at most 20 entries.
66
66
67 Return a new list made from the first and last 10 elements of dhist after
67 Return a new list made from the first and last 10 elements of dhist after
68 removal of duplicates.
68 removal of duplicates.
69 """
69 """
70 head, tail = dh[:-10], dh[-10:]
70 head, tail = dh[:-10], dh[-10:]
71
71
72 newhead = []
72 newhead = []
73 done = set()
73 done = set()
74 for h in head:
74 for h in head:
75 if h in done:
75 if h in done:
76 continue
76 continue
77 newhead.append(h)
77 newhead.append(h)
78 done.add(h)
78 done.add(h)
79
79
80 return newhead + tail
80 return newhead + tail
81
81
82
82
83 def needs_local_scope(func):
83 def needs_local_scope(func):
84 """Decorator to mark magic functions which need to local scope to run."""
84 """Decorator to mark magic functions which need to local scope to run."""
85 func.needs_local_scope = True
85 func.needs_local_scope = True
86 return func
86 return func
87
87
88 #-----------------------------------------------------------------------------
88 #-----------------------------------------------------------------------------
89 # Class and method decorators for registering magics
89 # Class and method decorators for registering magics
90 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
91
91
92 def magics_class(cls):
92 def magics_class(cls):
93 """Class decorator for all subclasses of the main Magics class.
93 """Class decorator for all subclasses of the main Magics class.
94
94
95 Any class that subclasses Magics *must* also apply this decorator, to
95 Any class that subclasses Magics *must* also apply this decorator, to
96 ensure that all the methods that have been decorated as line/cell magics
96 ensure that all the methods that have been decorated as line/cell magics
97 get correctly registered in the class instance. This is necessary because
97 get correctly registered in the class instance. This is necessary because
98 when method decorators run, the class does not exist yet, so they
98 when method decorators run, the class does not exist yet, so they
99 temporarily store their information into a module global. Application of
99 temporarily store their information into a module global. Application of
100 this class decorator copies that global data to the class instance and
100 this class decorator copies that global data to the class instance and
101 clears the global.
101 clears the global.
102
102
103 Obviously, this mechanism is not thread-safe, which means that the
103 Obviously, this mechanism is not thread-safe, which means that the
104 *creation* of subclasses of Magic should only be done in a single-thread
104 *creation* of subclasses of Magic should only be done in a single-thread
105 context. Instantiation of the classes has no restrictions. Given that
105 context. Instantiation of the classes has no restrictions. Given that
106 these classes are typically created at IPython startup time and before user
106 these classes are typically created at IPython startup time and before user
107 application code becomes active, in practice this should not pose any
107 application code becomes active, in practice this should not pose any
108 problems.
108 problems.
109 """
109 """
110 cls.registered = True
110 cls.registered = True
111 cls.magics = dict(line = magics['line'],
111 cls.magics = dict(line = magics['line'],
112 cell = magics['cell'])
112 cell = magics['cell'])
113 magics['line'] = {}
113 magics['line'] = {}
114 magics['cell'] = {}
114 magics['cell'] = {}
115 return cls
115 return cls
116
116
117
117
118 def record_magic(dct, magic_kind, magic_name, func):
118 def record_magic(dct, magic_kind, magic_name, func):
119 """Utility function to store a function as a magic of a specific kind.
119 """Utility function to store a function as a magic of a specific kind.
120
120
121 Parameters
121 Parameters
122 ----------
122 ----------
123 dct : dict
123 dct : dict
124 A dictionary with 'line' and 'cell' subdicts.
124 A dictionary with 'line' and 'cell' subdicts.
125
125
126 magic_kind : str
126 magic_kind : str
127 Kind of magic to be stored.
127 Kind of magic to be stored.
128
128
129 magic_name : str
129 magic_name : str
130 Key to store the magic as.
130 Key to store the magic as.
131
131
132 func : function
132 func : function
133 Callable object to store.
133 Callable object to store.
134 """
134 """
135 if magic_kind == 'line_cell':
135 if magic_kind == 'line_cell':
136 dct['line'][magic_name] = dct['cell'][magic_name] = func
136 dct['line'][magic_name] = dct['cell'][magic_name] = func
137 else:
137 else:
138 dct[magic_kind][magic_name] = func
138 dct[magic_kind][magic_name] = func
139
139
140
140
141 def validate_type(magic_kind):
141 def validate_type(magic_kind):
142 """Ensure that the given magic_kind is valid.
142 """Ensure that the given magic_kind is valid.
143
143
144 Check that the given magic_kind is one of the accepted spec types (stored
144 Check that the given magic_kind is one of the accepted spec types (stored
145 in the global `magic_spec`), raise ValueError otherwise.
145 in the global `magic_spec`), raise ValueError otherwise.
146 """
146 """
147 if magic_kind not in magic_spec:
147 if magic_kind not in magic_spec:
148 raise ValueError('magic_kind must be one of %s, %s given' %
148 raise ValueError('magic_kind must be one of %s, %s given' %
149 magic_kinds, magic_kind)
149 magic_kinds, magic_kind)
150
150
151
151
152 # The docstrings for the decorator below will be fairly similar for the two
152 # The docstrings for the decorator below will be fairly similar for the two
153 # types (method and function), so we generate them here once and reuse the
153 # types (method and function), so we generate them here once and reuse the
154 # templates below.
154 # templates below.
155 _docstring_template = \
155 _docstring_template = \
156 """Decorate the given {0} as {1} magic.
156 """Decorate the given {0} as {1} magic.
157
157
158 The decorator can be used with or without arguments, as follows.
158 The decorator can be used with or without arguments, as follows.
159
159
160 i) without arguments: it will create a {1} magic named as the {0} being
160 i) without arguments: it will create a {1} magic named as the {0} being
161 decorated::
161 decorated::
162
162
163 @deco
163 @deco
164 def foo(...)
164 def foo(...)
165
165
166 will create a {1} magic named `foo`.
166 will create a {1} magic named `foo`.
167
167
168 ii) with one string argument: which will be used as the actual name of the
168 ii) with one string argument: which will be used as the actual name of the
169 resulting magic::
169 resulting magic::
170
170
171 @deco('bar')
171 @deco('bar')
172 def foo(...)
172 def foo(...)
173
173
174 will create a {1} magic named `bar`.
174 will create a {1} magic named `bar`.
175 """
175 """
176
176
177 # These two are decorator factories. While they are conceptually very similar,
177 # These two are decorator factories. While they are conceptually very similar,
178 # there are enough differences in the details that it's simpler to have them
178 # there are enough differences in the details that it's simpler to have them
179 # written as completely standalone functions rather than trying to share code
179 # written as completely standalone functions rather than trying to share code
180 # and make a single one with convoluted logic.
180 # and make a single one with convoluted logic.
181
181
182 def _method_magic_marker(magic_kind):
182 def _method_magic_marker(magic_kind):
183 """Decorator factory for methods in Magics subclasses.
183 """Decorator factory for methods in Magics subclasses.
184 """
184 """
185
185
186 validate_type(magic_kind)
186 validate_type(magic_kind)
187
187
188 # This is a closure to capture the magic_kind. We could also use a class,
188 # This is a closure to capture the magic_kind. We could also use a class,
189 # but it's overkill for just that one bit of state.
189 # but it's overkill for just that one bit of state.
190 def magic_deco(arg):
190 def magic_deco(arg):
191 call = lambda f, *a, **k: f(*a, **k)
191 call = lambda f, *a, **k: f(*a, **k)
192
192
193 if callable(arg):
193 if callable(arg):
194 # "Naked" decorator call (just @foo, no args)
194 # "Naked" decorator call (just @foo, no args)
195 func = arg
195 func = arg
196 name = func.func_name
196 name = func.func_name
197 retval = decorator(call, func)
197 retval = decorator(call, func)
198 record_magic(magics, magic_kind, name, name)
198 record_magic(magics, magic_kind, name, name)
199 elif isinstance(arg, basestring):
199 elif isinstance(arg, basestring):
200 # Decorator called with arguments (@foo('bar'))
200 # Decorator called with arguments (@foo('bar'))
201 name = arg
201 name = arg
202 def mark(func, *a, **kw):
202 def mark(func, *a, **kw):
203 record_magic(magics, magic_kind, name, func.func_name)
203 record_magic(magics, magic_kind, name, func.func_name)
204 return decorator(call, func)
204 return decorator(call, func)
205 retval = mark
205 retval = mark
206 else:
206 else:
207 raise TypeError("Decorator can only be called with "
207 raise TypeError("Decorator can only be called with "
208 "string or function")
208 "string or function")
209 return retval
209 return retval
210
210
211 # Ensure the resulting decorator has a usable docstring
211 # Ensure the resulting decorator has a usable docstring
212 magic_deco.__doc__ = _docstring_template.format('method', magic_kind)
212 magic_deco.__doc__ = _docstring_template.format('method', magic_kind)
213 return magic_deco
213 return magic_deco
214
214
215
215
216 def _function_magic_marker(magic_kind):
216 def _function_magic_marker(magic_kind):
217 """Decorator factory for standalone functions.
217 """Decorator factory for standalone functions.
218 """
218 """
219 validate_type(magic_kind)
219 validate_type(magic_kind)
220
220
221 # This is a closure to capture the magic_kind. We could also use a class,
221 # This is a closure to capture the magic_kind. We could also use a class,
222 # but it's overkill for just that one bit of state.
222 # but it's overkill for just that one bit of state.
223 def magic_deco(arg):
223 def magic_deco(arg):
224 call = lambda f, *a, **k: f(*a, **k)
224 call = lambda f, *a, **k: f(*a, **k)
225
225
226 # Find get_ipython() in the caller's namespace
226 # Find get_ipython() in the caller's namespace
227 caller = sys._getframe(1)
227 caller = sys._getframe(1)
228 for ns in ['f_locals', 'f_globals', 'f_builtins']:
228 for ns in ['f_locals', 'f_globals', 'f_builtins']:
229 get_ipython = getattr(caller, ns).get('get_ipython')
229 get_ipython = getattr(caller, ns).get('get_ipython')
230 if get_ipython is not None:
230 if get_ipython is not None:
231 break
231 break
232 else:
232 else:
233 raise NameError('Decorator can only run in context where '
233 raise NameError('Decorator can only run in context where '
234 '`get_ipython` exists')
234 '`get_ipython` exists')
235
235
236 ip = get_ipython()
236 ip = get_ipython()
237
237
238 if callable(arg):
238 if callable(arg):
239 # "Naked" decorator call (just @foo, no args)
239 # "Naked" decorator call (just @foo, no args)
240 func = arg
240 func = arg
241 name = func.func_name
241 name = func.func_name
242 ip.register_magic_function(func, magic_kind, name)
242 ip.register_magic_function(func, magic_kind, name)
243 retval = decorator(call, func)
243 retval = decorator(call, func)
244 elif isinstance(arg, basestring):
244 elif isinstance(arg, basestring):
245 # Decorator called with arguments (@foo('bar'))
245 # Decorator called with arguments (@foo('bar'))
246 name = arg
246 name = arg
247 def mark(func, *a, **kw):
247 def mark(func, *a, **kw):
248 ip.register_magic_function(func, magic_kind, name)
248 ip.register_magic_function(func, magic_kind, name)
249 return decorator(call, func)
249 return decorator(call, func)
250 retval = mark
250 retval = mark
251 else:
251 else:
252 raise TypeError("Decorator can only be called with "
252 raise TypeError("Decorator can only be called with "
253 "string or function")
253 "string or function")
254 return retval
254 return retval
255
255
256 # Ensure the resulting decorator has a usable docstring
256 # Ensure the resulting decorator has a usable docstring
257 ds = _docstring_template.format('function', magic_kind)
257 ds = _docstring_template.format('function', magic_kind)
258
258
259 ds += dedent("""
259 ds += dedent("""
260 Note: this decorator can only be used in a context where IPython is already
260 Note: this decorator can only be used in a context where IPython is already
261 active, so that the `get_ipython()` call succeeds. You can therefore use
261 active, so that the `get_ipython()` call succeeds. You can therefore use
262 it in your startup files loaded after IPython initializes, but *not* in the
262 it in your startup files loaded after IPython initializes, but *not* in the
263 IPython configuration file itself, which is executed before IPython is
263 IPython configuration file itself, which is executed before IPython is
264 fully up and running. Any file located in the `startup` subdirectory of
264 fully up and running. Any file located in the `startup` subdirectory of
265 your configuration profile will be OK in this sense.
265 your configuration profile will be OK in this sense.
266 """)
266 """)
267
267
268 magic_deco.__doc__ = ds
268 magic_deco.__doc__ = ds
269 return magic_deco
269 return magic_deco
270
270
271
271
272 # Create the actual decorators for public use
272 # Create the actual decorators for public use
273
273
274 # These three are used to decorate methods in class definitions
274 # These three are used to decorate methods in class definitions
275 line_magic = _method_magic_marker('line')
275 line_magic = _method_magic_marker('line')
276 cell_magic = _method_magic_marker('cell')
276 cell_magic = _method_magic_marker('cell')
277 line_cell_magic = _method_magic_marker('line_cell')
277 line_cell_magic = _method_magic_marker('line_cell')
278
278
279 # These three decorate standalone functions and perform the decoration
279 # These three decorate standalone functions and perform the decoration
280 # immediately. They can only run where get_ipython() works
280 # immediately. They can only run where get_ipython() works
281 register_line_magic = _function_magic_marker('line')
281 register_line_magic = _function_magic_marker('line')
282 register_cell_magic = _function_magic_marker('cell')
282 register_cell_magic = _function_magic_marker('cell')
283 register_line_cell_magic = _function_magic_marker('line_cell')
283 register_line_cell_magic = _function_magic_marker('line_cell')
284
284
285 #-----------------------------------------------------------------------------
285 #-----------------------------------------------------------------------------
286 # Core Magic classes
286 # Core Magic classes
287 #-----------------------------------------------------------------------------
287 #-----------------------------------------------------------------------------
288
288
289 class MagicsManager(Configurable):
289 class MagicsManager(Configurable):
290 """Object that handles all magic-related functionality for IPython.
290 """Object that handles all magic-related functionality for IPython.
291 """
291 """
292 # Non-configurable class attributes
292 # Non-configurable class attributes
293
293
294 # A two-level dict, first keyed by magic type, then by magic function, and
294 # A two-level dict, first keyed by magic type, then by magic function, and
295 # holding the actual callable object as value. This is the dict used for
295 # holding the actual callable object as value. This is the dict used for
296 # magic function dispatch
296 # magic function dispatch
297 magics = Dict
297 magics = Dict
298
298
299 # A registry of the original objects that we've been given holding magics.
299 # A registry of the original objects that we've been given holding magics.
300 registry = Dict
300 registry = Dict
301
301
302 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
302 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
303
303
304 auto_magic = Bool(True, config=True, help=
304 auto_magic = Bool(True, config=True, help=
305 "Automatically call line magics without requiring explicit % prefix")
305 "Automatically call line magics without requiring explicit % prefix")
306
306
307 _auto_status = [
307 _auto_status = [
308 'Automagic is OFF, % prefix IS needed for line magics.',
308 'Automagic is OFF, % prefix IS needed for line magics.',
309 'Automagic is ON, % prefix IS NOT needed for line magics.']
309 'Automagic is ON, % prefix IS NOT needed for line magics.']
310
310
311 user_magics = Instance('IPython.core.magics.UserMagics')
311 user_magics = Instance('IPython.core.magics.UserMagics')
312
312
313 def __init__(self, shell=None, config=None, user_magics=None, **traits):
313 def __init__(self, shell=None, config=None, user_magics=None, **traits):
314
314
315 super(MagicsManager, self).__init__(shell=shell, config=config,
315 super(MagicsManager, self).__init__(shell=shell, config=config,
316 user_magics=user_magics, **traits)
316 user_magics=user_magics, **traits)
317 self.magics = dict(line={}, cell={})
317 self.magics = dict(line={}, cell={})
318 # Let's add the user_magics to the registry for uniformity, so *all*
318 # Let's add the user_magics to the registry for uniformity, so *all*
319 # registered magic containers can be found there.
319 # registered magic containers can be found there.
320 self.registry[user_magics.__class__.__name__] = user_magics
320 self.registry[user_magics.__class__.__name__] = user_magics
321
321
322 def auto_status(self):
322 def auto_status(self):
323 """Return descriptive string with automagic status."""
323 """Return descriptive string with automagic status."""
324 return self._auto_status[self.auto_magic]
324 return self._auto_status[self.auto_magic]
325
325
326 def lsmagic_info(self):
326 def lsmagic_info(self):
327 magic_list = []
327 magic_list = []
328 for m_type in self.magics :
328 for m_type in self.magics :
329 for m_name,mgc in self.magics[m_type].items():
329 for m_name,mgc in self.magics[m_type].items():
330 try :
330 try :
331 magic_list.append({'name':m_name,'type':m_type,'class':mgc.im_class.__name__})
331 magic_list.append({'name':m_name,'type':m_type,'class':mgc.im_class.__name__})
332 except AttributeError :
332 except AttributeError :
333 magic_list.append({'name':m_name,'type':m_type,'class':'Other'})
333 magic_list.append({'name':m_name,'type':m_type,'class':'Other'})
334 return magic_list
334 return magic_list
335
335
336 def lsmagic(self):
336 def lsmagic(self):
337 """Return a dict of currently available magic functions.
337 """Return a dict of currently available magic functions.
338
338
339 The return dict has the keys 'line' and 'cell', corresponding to the
339 The return dict has the keys 'line' and 'cell', corresponding to the
340 two types of magics we support. Each value is a list of names.
340 two types of magics we support. Each value is a list of names.
341 """
341 """
342 return self.magics
342 return self.magics
343
343
344 def lsmagic_docs(self, brief=False, missing=''):
344 def lsmagic_docs(self, brief=False, missing=''):
345 """Return dict of documentation of magic functions.
345 """Return dict of documentation of magic functions.
346
346
347 The return dict has the keys 'line' and 'cell', corresponding to the
347 The return dict has the keys 'line' and 'cell', corresponding to the
348 two types of magics we support. Each value is a dict keyed by magic
348 two types of magics we support. Each value is a dict keyed by magic
349 name whose value is the function docstring. If a docstring is
349 name whose value is the function docstring. If a docstring is
350 unavailable, the value of `missing` is used instead.
350 unavailable, the value of `missing` is used instead.
351
351
352 If brief is True, only the first line of each docstring will be returned.
352 If brief is True, only the first line of each docstring will be returned.
353 """
353 """
354 docs = {}
354 docs = {}
355 for m_type in self.magics:
355 for m_type in self.magics:
356 m_docs = {}
356 m_docs = {}
357 for m_name, m_func in self.magics[m_type].iteritems():
357 for m_name, m_func in self.magics[m_type].iteritems():
358 if m_func.__doc__:
358 if m_func.__doc__:
359 if brief:
359 if brief:
360 m_docs[m_name] = m_func.__doc__.split('\n', 1)[0]
360 m_docs[m_name] = m_func.__doc__.split('\n', 1)[0]
361 else:
361 else:
362 m_docs[m_name] = m_func.__doc__.rstrip()
362 m_docs[m_name] = m_func.__doc__.rstrip()
363 else:
363 else:
364 m_docs[m_name] = missing
364 m_docs[m_name] = missing
365 docs[m_type] = m_docs
365 docs[m_type] = m_docs
366 return docs
366 return docs
367
367
368 def register(self, *magic_objects):
368 def register(self, *magic_objects):
369 """Register one or more instances of Magics.
369 """Register one or more instances of Magics.
370
370
371 Take one or more classes or instances of classes that subclass the main
371 Take one or more classes or instances of classes that subclass the main
372 `core.Magic` class, and register them with IPython to use the magic
372 `core.Magic` class, and register them with IPython to use the magic
373 functions they provide. The registration process will then ensure that
373 functions they provide. The registration process will then ensure that
374 any methods that have decorated to provide line and/or cell magics will
374 any methods that have decorated to provide line and/or cell magics will
375 be recognized with the `%x`/`%%x` syntax as a line/cell magic
375 be recognized with the `%x`/`%%x` syntax as a line/cell magic
376 respectively.
376 respectively.
377
377
378 If classes are given, they will be instantiated with the default
378 If classes are given, they will be instantiated with the default
379 constructor. If your classes need a custom constructor, you should
379 constructor. If your classes need a custom constructor, you should
380 instanitate them first and pass the instance.
380 instanitate them first and pass the instance.
381
381
382 The provided arguments can be an arbitrary mix of classes and instances.
382 The provided arguments can be an arbitrary mix of classes and instances.
383
383
384 Parameters
384 Parameters
385 ----------
385 ----------
386 magic_objects : one or more classes or instances
386 magic_objects : one or more classes or instances
387 """
387 """
388 # Start by validating them to ensure they have all had their magic
388 # Start by validating them to ensure they have all had their magic
389 # methods registered at the instance level
389 # methods registered at the instance level
390 for m in magic_objects:
390 for m in magic_objects:
391 if not m.registered:
391 if not m.registered:
392 raise ValueError("Class of magics %r was constructed without "
392 raise ValueError("Class of magics %r was constructed without "
393 "the @register_magics class decorator")
393 "the @register_magics class decorator")
394 if type(m) in (type, MetaHasTraits):
394 if type(m) in (type, MetaHasTraits):
395 # If we're given an uninstantiated class
395 # If we're given an uninstantiated class
396 m = m(shell=self.shell)
396 m = m(shell=self.shell)
397
397
398 # Now that we have an instance, we can register it and update the
398 # Now that we have an instance, we can register it and update the
399 # table of callables
399 # table of callables
400 self.registry[m.__class__.__name__] = m
400 self.registry[m.__class__.__name__] = m
401 for mtype in magic_kinds:
401 for mtype in magic_kinds:
402 self.magics[mtype].update(m.magics[mtype])
402 self.magics[mtype].update(m.magics[mtype])
403
403
404 def register_function(self, func, magic_kind='line', magic_name=None):
404 def register_function(self, func, magic_kind='line', magic_name=None):
405 """Expose a standalone function as magic function for IPython.
405 """Expose a standalone function as magic function for IPython.
406
406
407 This will create an IPython magic (line, cell or both) from a
407 This will create an IPython magic (line, cell or both) from a
408 standalone function. The functions should have the following
408 standalone function. The functions should have the following
409 signatures:
409 signatures:
410
410
411 * For line magics: `def f(line)`
411 * For line magics: `def f(line)`
412 * For cell magics: `def f(line, cell)`
412 * For cell magics: `def f(line, cell)`
413 * For a function that does both: `def f(line, cell=None)`
413 * For a function that does both: `def f(line, cell=None)`
414
414
415 In the latter case, the function will be called with `cell==None` when
415 In the latter case, the function will be called with `cell==None` when
416 invoked as `%f`, and with cell as a string when invoked as `%%f`.
416 invoked as `%f`, and with cell as a string when invoked as `%%f`.
417
417
418 Parameters
418 Parameters
419 ----------
419 ----------
420 func : callable
420 func : callable
421 Function to be registered as a magic.
421 Function to be registered as a magic.
422
422
423 magic_kind : str
423 magic_kind : str
424 Kind of magic, one of 'line', 'cell' or 'line_cell'
424 Kind of magic, one of 'line', 'cell' or 'line_cell'
425
425
426 magic_name : optional str
426 magic_name : optional str
427 If given, the name the magic will have in the IPython namespace. By
427 If given, the name the magic will have in the IPython namespace. By
428 default, the name of the function itself is used.
428 default, the name of the function itself is used.
429 """
429 """
430
430
431 # Create the new method in the user_magics and register it in the
431 # Create the new method in the user_magics and register it in the
432 # global table
432 # global table
433 validate_type(magic_kind)
433 validate_type(magic_kind)
434 magic_name = func.func_name if magic_name is None else magic_name
434 magic_name = func.func_name if magic_name is None else magic_name
435 setattr(self.user_magics, magic_name, func)
435 setattr(self.user_magics, magic_name, func)
436 record_magic(self.magics, magic_kind, magic_name, func)
436 record_magic(self.magics, magic_kind, magic_name, func)
437
437
438 def define_magic(self, name, func):
438 def define_magic(self, name, func):
439 """[Deprecated] Expose own function as magic function for IPython.
439 """[Deprecated] Expose own function as magic function for IPython.
440
440
441 Example::
441 Example::
442
442
443 def foo_impl(self, parameter_s=''):
443 def foo_impl(self, parameter_s=''):
444 'My very own magic!. (Use docstrings, IPython reads them).'
444 'My very own magic!. (Use docstrings, IPython reads them).'
445 print 'Magic function. Passed parameter is between < >:'
445 print 'Magic function. Passed parameter is between < >:'
446 print '<%s>' % parameter_s
446 print '<%s>' % parameter_s
447 print 'The self object is:', self
447 print 'The self object is:', self
448
448
449 ip.define_magic('foo',foo_impl)
449 ip.define_magic('foo',foo_impl)
450 """
450 """
451 meth = types.MethodType(func, self.user_magics)
451 meth = types.MethodType(func, self.user_magics)
452 setattr(self.user_magics, name, meth)
452 setattr(self.user_magics, name, meth)
453 record_magic(self.magics, 'line', name, meth)
453 record_magic(self.magics, 'line', name, meth)
454
454
455 # Key base class that provides the central functionality for magics.
455 # Key base class that provides the central functionality for magics.
456
456
457 class Magics(object):
457 class Magics(object):
458 """Base class for implementing magic functions.
458 """Base class for implementing magic functions.
459
459
460 Shell functions which can be reached as %function_name. All magic
460 Shell functions which can be reached as %function_name. All magic
461 functions should accept a string, which they can parse for their own
461 functions should accept a string, which they can parse for their own
462 needs. This can make some functions easier to type, eg `%cd ../`
462 needs. This can make some functions easier to type, eg `%cd ../`
463 vs. `%cd("../")`
463 vs. `%cd("../")`
464
464
465 Classes providing magic functions need to subclass this class, and they
465 Classes providing magic functions need to subclass this class, and they
466 MUST:
466 MUST:
467
467
468 - Use the method decorators `@line_magic` and `@cell_magic` to decorate
468 - Use the method decorators `@line_magic` and `@cell_magic` to decorate
469 individual methods as magic functions, AND
469 individual methods as magic functions, AND
470
470
471 - Use the class decorator `@magics_class` to ensure that the magic
471 - Use the class decorator `@magics_class` to ensure that the magic
472 methods are properly registered at the instance level upon instance
472 methods are properly registered at the instance level upon instance
473 initialization.
473 initialization.
474
474
475 See :mod:`magic_functions` for examples of actual implementation classes.
475 See :mod:`magic_functions` for examples of actual implementation classes.
476 """
476 """
477 # Dict holding all command-line options for each magic.
477 # Dict holding all command-line options for each magic.
478 options_table = None
478 options_table = None
479 # Dict for the mapping of magic names to methods, set by class decorator
479 # Dict for the mapping of magic names to methods, set by class decorator
480 magics = None
480 magics = None
481 # Flag to check that the class decorator was properly applied
481 # Flag to check that the class decorator was properly applied
482 registered = False
482 registered = False
483 # Instance of IPython shell
483 # Instance of IPython shell
484 shell = None
484 shell = None
485
485
486 def __init__(self, shell):
486 def __init__(self, shell):
487 if not(self.__class__.registered):
487 if not(self.__class__.registered):
488 raise ValueError('Magics subclass without registration - '
488 raise ValueError('Magics subclass without registration - '
489 'did you forget to apply @magics_class?')
489 'did you forget to apply @magics_class?')
490 self.shell = shell
490 self.shell = shell
491 self.options_table = {}
491 self.options_table = {}
492 # The method decorators are run when the instance doesn't exist yet, so
492 # The method decorators are run when the instance doesn't exist yet, so
493 # they can only record the names of the methods they are supposed to
493 # they can only record the names of the methods they are supposed to
494 # grab. Only now, that the instance exists, can we create the proper
494 # grab. Only now, that the instance exists, can we create the proper
495 # mapping to bound methods. So we read the info off the original names
495 # mapping to bound methods. So we read the info off the original names
496 # table and replace each method name by the actual bound method.
496 # table and replace each method name by the actual bound method.
497 # But we mustn't clobber the *class* mapping, in case of multiple instances.
497 # But we mustn't clobber the *class* mapping, in case of multiple instances.
498 class_magics = self.magics
498 class_magics = self.magics
499 self.magics = {}
499 self.magics = {}
500 for mtype in magic_kinds:
500 for mtype in magic_kinds:
501 tab = self.magics[mtype] = {}
501 tab = self.magics[mtype] = {}
502 cls_tab = class_magics[mtype]
502 cls_tab = class_magics[mtype]
503 for magic_name, meth_name in cls_tab.iteritems():
503 for magic_name, meth_name in cls_tab.iteritems():
504 if isinstance(meth_name, basestring):
504 if isinstance(meth_name, basestring):
505 # it's a method name, grab it
505 # it's a method name, grab it
506 tab[magic_name] = getattr(self, meth_name)
506 tab[magic_name] = getattr(self, meth_name)
507 else:
507 else:
508 # it's the real thing
508 # it's the real thing
509 tab[magic_name] = meth_name
509 tab[magic_name] = meth_name
510
510
511 def arg_err(self,func):
511 def arg_err(self,func):
512 """Print docstring if incorrect arguments were passed"""
512 """Print docstring if incorrect arguments were passed"""
513 print 'Error in arguments:'
513 print 'Error in arguments:'
514 print oinspect.getdoc(func)
514 print oinspect.getdoc(func)
515
515
516 def format_latex(self, strng):
516 def format_latex(self, strng):
517 """Format a string for latex inclusion."""
517 """Format a string for latex inclusion."""
518
518
519 # Characters that need to be escaped for latex:
519 # Characters that need to be escaped for latex:
520 escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
520 escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
521 # Magic command names as headers:
521 # Magic command names as headers:
522 cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
522 cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
523 re.MULTILINE)
523 re.MULTILINE)
524 # Magic commands
524 # Magic commands
525 cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
525 cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
526 re.MULTILINE)
526 re.MULTILINE)
527 # Paragraph continue
527 # Paragraph continue
528 par_re = re.compile(r'\\$',re.MULTILINE)
528 par_re = re.compile(r'\\$',re.MULTILINE)
529
529
530 # The "\n" symbol
530 # The "\n" symbol
531 newline_re = re.compile(r'\\n')
531 newline_re = re.compile(r'\\n')
532
532
533 # Now build the string for output:
533 # Now build the string for output:
534 #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
534 #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
535 strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
535 strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
536 strng)
536 strng)
537 strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
537 strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
538 strng = par_re.sub(r'\\\\',strng)
538 strng = par_re.sub(r'\\\\',strng)
539 strng = escape_re.sub(r'\\\1',strng)
539 strng = escape_re.sub(r'\\\1',strng)
540 strng = newline_re.sub(r'\\textbackslash{}n',strng)
540 strng = newline_re.sub(r'\\textbackslash{}n',strng)
541 return strng
541 return strng
542
542
543 def parse_options(self, arg_str, opt_str, *long_opts, **kw):
543 def parse_options(self, arg_str, opt_str, *long_opts, **kw):
544 """Parse options passed to an argument string.
544 """Parse options passed to an argument string.
545
545
546 The interface is similar to that of getopt(), but it returns back a
546 The interface is similar to that of getopt(), but it returns back a
547 Struct with the options as keys and the stripped argument string still
547 Struct with the options as keys and the stripped argument string still
548 as a string.
548 as a string.
549
549
550 arg_str is quoted as a true sys.argv vector by using shlex.split.
550 arg_str is quoted as a true sys.argv vector by using shlex.split.
551 This allows us to easily expand variables, glob files, quote
551 This allows us to easily expand variables, glob files, quote
552 arguments, etc.
552 arguments, etc.
553
553
554 Options:
554 Options:
555 -mode: default 'string'. If given as 'list', the argument string is
555 -mode: default 'string'. If given as 'list', the argument string is
556 returned as a list (split on whitespace) instead of a string.
556 returned as a list (split on whitespace) instead of a string.
557
557
558 -list_all: put all option values in lists. Normally only options
558 -list_all: put all option values in lists. Normally only options
559 appearing more than once are put in a list.
559 appearing more than once are put in a list.
560
560
561 -posix (True): whether to split the input line in POSIX mode or not,
561 -posix (True): whether to split the input line in POSIX mode or not,
562 as per the conventions outlined in the shlex module from the
562 as per the conventions outlined in the shlex module from the
563 standard library."""
563 standard library."""
564
564
565 # inject default options at the beginning of the input line
565 # inject default options at the beginning of the input line
566 caller = sys._getframe(1).f_code.co_name
566 caller = sys._getframe(1).f_code.co_name
567 arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
567 arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
568
568
569 mode = kw.get('mode','string')
569 mode = kw.get('mode','string')
570 if mode not in ['string','list']:
570 if mode not in ['string','list']:
571 raise ValueError,'incorrect mode given: %s' % mode
571 raise ValueError,'incorrect mode given: %s' % mode
572 # Get options
572 # Get options
573 list_all = kw.get('list_all',0)
573 list_all = kw.get('list_all',0)
574 posix = kw.get('posix', os.name == 'posix')
574 posix = kw.get('posix', os.name == 'posix')
575 strict = kw.get('strict', True)
575 strict = kw.get('strict', True)
576
576
577 # Check if we have more than one argument to warrant extra processing:
577 # Check if we have more than one argument to warrant extra processing:
578 odict = {} # Dictionary with options
578 odict = {} # Dictionary with options
579 args = arg_str.split()
579 args = arg_str.split()
580 if len(args) >= 1:
580 if len(args) >= 1:
581 # If the list of inputs only has 0 or 1 thing in it, there's no
581 # If the list of inputs only has 0 or 1 thing in it, there's no
582 # need to look for options
582 # need to look for options
583 argv = arg_split(arg_str, posix, strict)
583 argv = arg_split(arg_str, posix, strict)
584 # Do regular option processing
584 # Do regular option processing
585 try:
585 try:
586 opts,args = getopt(argv, opt_str, long_opts)
586 opts,args = getopt(argv, opt_str, long_opts)
587 except GetoptError,e:
587 except GetoptError as e:
588 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
588 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
589 " ".join(long_opts)))
589 " ".join(long_opts)))
590 for o,a in opts:
590 for o,a in opts:
591 if o.startswith('--'):
591 if o.startswith('--'):
592 o = o[2:]
592 o = o[2:]
593 else:
593 else:
594 o = o[1:]
594 o = o[1:]
595 try:
595 try:
596 odict[o].append(a)
596 odict[o].append(a)
597 except AttributeError:
597 except AttributeError:
598 odict[o] = [odict[o],a]
598 odict[o] = [odict[o],a]
599 except KeyError:
599 except KeyError:
600 if list_all:
600 if list_all:
601 odict[o] = [a]
601 odict[o] = [a]
602 else:
602 else:
603 odict[o] = a
603 odict[o] = a
604
604
605 # Prepare opts,args for return
605 # Prepare opts,args for return
606 opts = Struct(odict)
606 opts = Struct(odict)
607 if mode == 'string':
607 if mode == 'string':
608 args = ' '.join(args)
608 args = ' '.join(args)
609
609
610 return opts,args
610 return opts,args
611
611
612 def default_option(self, fn, optstr):
612 def default_option(self, fn, optstr):
613 """Make an entry in the options_table for fn, with value optstr"""
613 """Make an entry in the options_table for fn, with value optstr"""
614
614
615 if fn not in self.lsmagic():
615 if fn not in self.lsmagic():
616 error("%s is not a magic function" % fn)
616 error("%s is not a magic function" % fn)
617 self.options_table[fn] = optstr
617 self.options_table[fn] = optstr
@@ -1,521 +1,521 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 This function uses the same syntax as %history for input ranges,
64 This function uses the same syntax as %history for input ranges,
65 then saves the lines to the filename you specify.
65 then saves the lines to the filename you specify.
66
66
67 It adds a '.py' extension to the file if you don't do so yourself, and
67 It adds a '.py' extension to the file if you don't do so yourself, and
68 it asks for confirmation before overwriting existing files.
68 it asks for confirmation before overwriting existing files.
69
69
70 If `-r` option is used, the default extension is `.ipy`.
70 If `-r` option is used, the default extension is `.ipy`.
71 """
71 """
72
72
73 opts,args = self.parse_options(parameter_s,'fr',mode='list')
73 opts,args = self.parse_options(parameter_s,'fr',mode='list')
74 raw = 'r' in opts
74 raw = 'r' in opts
75 force = 'f' in opts
75 force = 'f' in opts
76 ext = u'.ipy' if raw else u'.py'
76 ext = u'.ipy' if raw else u'.py'
77 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
77 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
78 if not fname.endswith((u'.py',u'.ipy')):
78 if not fname.endswith((u'.py',u'.ipy')):
79 fname += ext
79 fname += ext
80 if os.path.isfile(fname) and not force:
80 if os.path.isfile(fname) and not force:
81 try:
81 try:
82 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
82 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
83 except StdinNotImplementedError:
83 except StdinNotImplementedError:
84 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
84 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
85 return
85 return
86 if not overwrite :
86 if not overwrite :
87 print 'Operation cancelled.'
87 print 'Operation cancelled.'
88 return
88 return
89 try:
89 try:
90 cmds = self.shell.find_user_code(codefrom,raw)
90 cmds = self.shell.find_user_code(codefrom,raw)
91 except (TypeError, ValueError) as e:
91 except (TypeError, ValueError) as e:
92 print e.args[0]
92 print e.args[0]
93 return
93 return
94 with io.open(fname,'w', encoding="utf-8") as f:
94 with io.open(fname,'w', encoding="utf-8") as f:
95 f.write(u"# coding: utf-8\n")
95 f.write(u"# coding: utf-8\n")
96 f.write(py3compat.cast_unicode(cmds))
96 f.write(py3compat.cast_unicode(cmds))
97 print 'The following commands were written to file `%s`:' % fname
97 print 'The following commands were written to file `%s`:' % fname
98 print cmds
98 print cmds
99
99
100 @line_magic
100 @line_magic
101 def pastebin(self, parameter_s=''):
101 def pastebin(self, parameter_s=''):
102 """Upload code to Github's Gist paste bin, returning the URL.
102 """Upload code to Github's Gist paste bin, returning the URL.
103
103
104 Usage:\\
104 Usage:\\
105 %pastebin [-d "Custom description"] 1-7
105 %pastebin [-d "Custom description"] 1-7
106
106
107 The argument can be an input history range, a filename, or the name of a
107 The argument can be an input history range, a filename, or the name of a
108 string or macro.
108 string or macro.
109
109
110 Options:
110 Options:
111
111
112 -d: Pass a custom description for the gist. The default will say
112 -d: Pass a custom description for the gist. The default will say
113 "Pasted from IPython".
113 "Pasted from IPython".
114 """
114 """
115 opts, args = self.parse_options(parameter_s, 'd:')
115 opts, args = self.parse_options(parameter_s, 'd:')
116
116
117 try:
117 try:
118 code = self.shell.find_user_code(args)
118 code = self.shell.find_user_code(args)
119 except (ValueError, TypeError) as e:
119 except (ValueError, TypeError) as e:
120 print e.args[0]
120 print e.args[0]
121 return
121 return
122
122
123 post_data = json.dumps({
123 post_data = json.dumps({
124 "description": opts.get('d', "Pasted from IPython"),
124 "description": opts.get('d', "Pasted from IPython"),
125 "public": True,
125 "public": True,
126 "files": {
126 "files": {
127 "file1.py": {
127 "file1.py": {
128 "content": code
128 "content": code
129 }
129 }
130 }
130 }
131 }).encode('utf-8')
131 }).encode('utf-8')
132
132
133 response = urlopen("https://api.github.com/gists", post_data)
133 response = urlopen("https://api.github.com/gists", post_data)
134 response_data = json.loads(response.read().decode('utf-8'))
134 response_data = json.loads(response.read().decode('utf-8'))
135 return response_data['html_url']
135 return response_data['html_url']
136
136
137 @line_magic
137 @line_magic
138 def loadpy(self, arg_s):
138 def loadpy(self, arg_s):
139 """Alias of `%load`
139 """Alias of `%load`
140
140
141 `%loadpy` has gained some flexibility and droped the requirement of a `.py`
141 `%loadpy` has gained some flexibility and droped the requirement of a `.py`
142 extension. So it has been renamed simply into %load. You can look at
142 extension. So it has been renamed simply into %load. You can look at
143 `%load`'s docstring for more info.
143 `%load`'s docstring for more info.
144 """
144 """
145 self.load(arg_s)
145 self.load(arg_s)
146
146
147 @line_magic
147 @line_magic
148 def load(self, arg_s):
148 def load(self, arg_s):
149 """Load code into the current frontend.
149 """Load code into the current frontend.
150
150
151 Usage:\\
151 Usage:\\
152 %load [options] source
152 %load [options] source
153
153
154 where source can be a filename, URL, input history range or macro
154 where source can be a filename, URL, input history range or macro
155
155
156 Options:
156 Options:
157 --------
157 --------
158 -y : Don't ask confirmation for loading source above 200 000 characters.
158 -y : Don't ask confirmation for loading source above 200 000 characters.
159
159
160 This magic command can either take a local filename, a URL, an history
160 This magic command can either take a local filename, a URL, an history
161 range (see %history) or a macro as argument, it will prompt for
161 range (see %history) or a macro as argument, it will prompt for
162 confirmation before loading source with more than 200 000 characters, unless
162 confirmation before loading source with more than 200 000 characters, unless
163 -y flag is passed or if the frontend does not support raw_input::
163 -y flag is passed or if the frontend does not support raw_input::
164
164
165 %load myscript.py
165 %load myscript.py
166 %load 7-27
166 %load 7-27
167 %load myMacro
167 %load myMacro
168 %load http://www.example.com/myscript.py
168 %load http://www.example.com/myscript.py
169 """
169 """
170 opts,args = self.parse_options(arg_s,'y')
170 opts,args = self.parse_options(arg_s,'y')
171
171
172 contents = self.shell.find_user_code(args)
172 contents = self.shell.find_user_code(args)
173 l = len(contents)
173 l = len(contents)
174
174
175 # 200 000 is ~ 2500 full 80 caracter lines
175 # 200 000 is ~ 2500 full 80 caracter lines
176 # so in average, more than 5000 lines
176 # so in average, more than 5000 lines
177 if l > 200000 and 'y' not in opts:
177 if l > 200000 and 'y' not in opts:
178 try:
178 try:
179 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
179 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
180 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
180 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
181 except StdinNotImplementedError:
181 except StdinNotImplementedError:
182 #asume yes if raw input not implemented
182 #asume yes if raw input not implemented
183 ans = True
183 ans = True
184
184
185 if ans is False :
185 if ans is False :
186 print 'Operation cancelled.'
186 print 'Operation cancelled.'
187 return
187 return
188
188
189 self.shell.set_next_input(contents)
189 self.shell.set_next_input(contents)
190
190
191 @staticmethod
191 @staticmethod
192 def _find_edit_target(shell, args, opts, last_call):
192 def _find_edit_target(shell, args, opts, last_call):
193 """Utility method used by magic_edit to find what to edit."""
193 """Utility method used by magic_edit to find what to edit."""
194
194
195 def make_filename(arg):
195 def make_filename(arg):
196 "Make a filename from the given args"
196 "Make a filename from the given args"
197 arg = unquote_filename(arg)
197 arg = unquote_filename(arg)
198 try:
198 try:
199 filename = get_py_filename(arg)
199 filename = get_py_filename(arg)
200 except IOError:
200 except IOError:
201 # If it ends with .py but doesn't already exist, assume we want
201 # If it ends with .py but doesn't already exist, assume we want
202 # a new file.
202 # a new file.
203 if arg.endswith('.py'):
203 if arg.endswith('.py'):
204 filename = arg
204 filename = arg
205 else:
205 else:
206 filename = None
206 filename = None
207 return filename
207 return filename
208
208
209 # Set a few locals from the options for convenience:
209 # Set a few locals from the options for convenience:
210 opts_prev = 'p' in opts
210 opts_prev = 'p' in opts
211 opts_raw = 'r' in opts
211 opts_raw = 'r' in opts
212
212
213 # custom exceptions
213 # custom exceptions
214 class DataIsObject(Exception): pass
214 class DataIsObject(Exception): pass
215
215
216 # Default line number value
216 # Default line number value
217 lineno = opts.get('n',None)
217 lineno = opts.get('n',None)
218
218
219 if opts_prev:
219 if opts_prev:
220 args = '_%s' % last_call[0]
220 args = '_%s' % last_call[0]
221 if not shell.user_ns.has_key(args):
221 if not shell.user_ns.has_key(args):
222 args = last_call[1]
222 args = last_call[1]
223
223
224 # use last_call to remember the state of the previous call, but don't
224 # use last_call to remember the state of the previous call, but don't
225 # let it be clobbered by successive '-p' calls.
225 # let it be clobbered by successive '-p' calls.
226 try:
226 try:
227 last_call[0] = shell.displayhook.prompt_count
227 last_call[0] = shell.displayhook.prompt_count
228 if not opts_prev:
228 if not opts_prev:
229 last_call[1] = args
229 last_call[1] = args
230 except:
230 except:
231 pass
231 pass
232
232
233 # by default this is done with temp files, except when the given
233 # by default this is done with temp files, except when the given
234 # arg is a filename
234 # arg is a filename
235 use_temp = True
235 use_temp = True
236
236
237 data = ''
237 data = ''
238
238
239 # First, see if the arguments should be a filename.
239 # First, see if the arguments should be a filename.
240 filename = make_filename(args)
240 filename = make_filename(args)
241 if filename:
241 if filename:
242 use_temp = False
242 use_temp = False
243 elif args:
243 elif args:
244 # Mode where user specifies ranges of lines, like in %macro.
244 # Mode where user specifies ranges of lines, like in %macro.
245 data = shell.extract_input_lines(args, opts_raw)
245 data = shell.extract_input_lines(args, opts_raw)
246 if not data:
246 if not data:
247 try:
247 try:
248 # Load the parameter given as a variable. If not a string,
248 # Load the parameter given as a variable. If not a string,
249 # process it as an object instead (below)
249 # process it as an object instead (below)
250
250
251 #print '*** args',args,'type',type(args) # dbg
251 #print '*** args',args,'type',type(args) # dbg
252 data = eval(args, shell.user_ns)
252 data = eval(args, shell.user_ns)
253 if not isinstance(data, basestring):
253 if not isinstance(data, basestring):
254 raise DataIsObject
254 raise DataIsObject
255
255
256 except (NameError,SyntaxError):
256 except (NameError,SyntaxError):
257 # given argument is not a variable, try as a filename
257 # given argument is not a variable, try as a filename
258 filename = make_filename(args)
258 filename = make_filename(args)
259 if filename is None:
259 if filename is None:
260 warn("Argument given (%s) can't be found as a variable "
260 warn("Argument given (%s) can't be found as a variable "
261 "or as a filename." % args)
261 "or as a filename." % args)
262 return
262 return
263 use_temp = False
263 use_temp = False
264
264
265 except DataIsObject:
265 except DataIsObject:
266 # macros have a special edit function
266 # macros have a special edit function
267 if isinstance(data, Macro):
267 if isinstance(data, Macro):
268 raise MacroToEdit(data)
268 raise MacroToEdit(data)
269
269
270 # For objects, try to edit the file where they are defined
270 # For objects, try to edit the file where they are defined
271 filename = find_file(data)
271 filename = find_file(data)
272 if filename:
272 if filename:
273 if 'fakemodule' in filename.lower() and \
273 if 'fakemodule' in filename.lower() and \
274 inspect.isclass(data):
274 inspect.isclass(data):
275 # class created by %edit? Try to find source
275 # class created by %edit? Try to find source
276 # by looking for method definitions instead, the
276 # by looking for method definitions instead, the
277 # __module__ in those classes is FakeModule.
277 # __module__ in those classes is FakeModule.
278 attrs = [getattr(data, aname) for aname in dir(data)]
278 attrs = [getattr(data, aname) for aname in dir(data)]
279 for attr in attrs:
279 for attr in attrs:
280 if not inspect.ismethod(attr):
280 if not inspect.ismethod(attr):
281 continue
281 continue
282 filename = find_file(attr)
282 filename = find_file(attr)
283 if filename and \
283 if filename and \
284 'fakemodule' not in filename.lower():
284 'fakemodule' not in filename.lower():
285 # change the attribute to be the edit
285 # change the attribute to be the edit
286 # target instead
286 # target instead
287 data = attr
287 data = attr
288 break
288 break
289
289
290 datafile = 1
290 datafile = 1
291 if filename is None:
291 if filename is None:
292 filename = make_filename(args)
292 filename = make_filename(args)
293 datafile = 1
293 datafile = 1
294 warn('Could not find file where `%s` is defined.\n'
294 warn('Could not find file where `%s` is defined.\n'
295 'Opening a file named `%s`' % (args, filename))
295 'Opening a file named `%s`' % (args, filename))
296 # Now, make sure we can actually read the source (if it was
296 # Now, make sure we can actually read the source (if it was
297 # in a temp file it's gone by now).
297 # in a temp file it's gone by now).
298 if datafile:
298 if datafile:
299 if lineno is None:
299 if lineno is None:
300 lineno = find_source_lines(data)
300 lineno = find_source_lines(data)
301 if lineno is None:
301 if lineno is None:
302 filename = make_filename(args)
302 filename = make_filename(args)
303 if filename is None:
303 if filename is None:
304 warn('The file `%s` where `%s` was defined '
304 warn('The file `%s` where `%s` was defined '
305 'cannot be read.' % (filename, data))
305 'cannot be read.' % (filename, data))
306 return
306 return
307 use_temp = False
307 use_temp = False
308
308
309 if use_temp:
309 if use_temp:
310 filename = shell.mktempfile(data)
310 filename = shell.mktempfile(data)
311 print 'IPython will make a temporary file named:',filename
311 print 'IPython will make a temporary file named:',filename
312
312
313 return filename, lineno, use_temp
313 return filename, lineno, use_temp
314
314
315 def _edit_macro(self,mname,macro):
315 def _edit_macro(self,mname,macro):
316 """open an editor with the macro data in a file"""
316 """open an editor with the macro data in a file"""
317 filename = self.shell.mktempfile(macro.value)
317 filename = self.shell.mktempfile(macro.value)
318 self.shell.hooks.editor(filename)
318 self.shell.hooks.editor(filename)
319
319
320 # and make a new macro object, to replace the old one
320 # and make a new macro object, to replace the old one
321 mfile = open(filename)
321 mfile = open(filename)
322 mvalue = mfile.read()
322 mvalue = mfile.read()
323 mfile.close()
323 mfile.close()
324 self.shell.user_ns[mname] = Macro(mvalue)
324 self.shell.user_ns[mname] = Macro(mvalue)
325
325
326 @line_magic
326 @line_magic
327 def ed(self, parameter_s=''):
327 def ed(self, parameter_s=''):
328 """Alias to %edit."""
328 """Alias to %edit."""
329 return self.edit(parameter_s)
329 return self.edit(parameter_s)
330
330
331 @skip_doctest
331 @skip_doctest
332 @line_magic
332 @line_magic
333 def edit(self, parameter_s='',last_call=['','']):
333 def edit(self, parameter_s='',last_call=['','']):
334 """Bring up an editor and execute the resulting code.
334 """Bring up an editor and execute the resulting code.
335
335
336 Usage:
336 Usage:
337 %edit [options] [args]
337 %edit [options] [args]
338
338
339 %edit runs IPython's editor hook. The default version of this hook is
339 %edit runs IPython's editor hook. The default version of this hook is
340 set to call the editor specified by your $EDITOR environment variable.
340 set to call the editor specified by your $EDITOR environment variable.
341 If this isn't found, it will default to vi under Linux/Unix and to
341 If this isn't found, it will default to vi under Linux/Unix and to
342 notepad under Windows. See the end of this docstring for how to change
342 notepad under Windows. See the end of this docstring for how to change
343 the editor hook.
343 the editor hook.
344
344
345 You can also set the value of this editor via the
345 You can also set the value of this editor via the
346 ``TerminalInteractiveShell.editor`` option in your configuration file.
346 ``TerminalInteractiveShell.editor`` option in your configuration file.
347 This is useful if you wish to use a different editor from your typical
347 This is useful if you wish to use a different editor from your typical
348 default with IPython (and for Windows users who typically don't set
348 default with IPython (and for Windows users who typically don't set
349 environment variables).
349 environment variables).
350
350
351 This command allows you to conveniently edit multi-line code right in
351 This command allows you to conveniently edit multi-line code right in
352 your IPython session.
352 your IPython session.
353
353
354 If called without arguments, %edit opens up an empty editor with a
354 If called without arguments, %edit opens up an empty editor with a
355 temporary file and will execute the contents of this file when you
355 temporary file and will execute the contents of this file when you
356 close it (don't forget to save it!).
356 close it (don't forget to save it!).
357
357
358
358
359 Options:
359 Options:
360
360
361 -n <number>: open the editor at a specified line number. By default,
361 -n <number>: open the editor at a specified line number. By default,
362 the IPython editor hook uses the unix syntax 'editor +N filename', but
362 the IPython editor hook uses the unix syntax 'editor +N filename', but
363 you can configure this by providing your own modified hook if your
363 you can configure this by providing your own modified hook if your
364 favorite editor supports line-number specifications with a different
364 favorite editor supports line-number specifications with a different
365 syntax.
365 syntax.
366
366
367 -p: this will call the editor with the same data as the previous time
367 -p: this will call the editor with the same data as the previous time
368 it was used, regardless of how long ago (in your current session) it
368 it was used, regardless of how long ago (in your current session) it
369 was.
369 was.
370
370
371 -r: use 'raw' input. This option only applies to input taken from the
371 -r: use 'raw' input. This option only applies to input taken from the
372 user's history. By default, the 'processed' history is used, so that
372 user's history. By default, the 'processed' history is used, so that
373 magics are loaded in their transformed version to valid Python. If
373 magics are loaded in their transformed version to valid Python. If
374 this option is given, the raw input as typed as the command line is
374 this option is given, the raw input as typed as the command line is
375 used instead. When you exit the editor, it will be executed by
375 used instead. When you exit the editor, it will be executed by
376 IPython's own processor.
376 IPython's own processor.
377
377
378 -x: do not execute the edited code immediately upon exit. This is
378 -x: do not execute the edited code immediately upon exit. This is
379 mainly useful if you are editing programs which need to be called with
379 mainly useful if you are editing programs which need to be called with
380 command line arguments, which you can then do using %run.
380 command line arguments, which you can then do using %run.
381
381
382
382
383 Arguments:
383 Arguments:
384
384
385 If arguments are given, the following possibilities exist:
385 If arguments are given, the following possibilities exist:
386
386
387 - If the argument is a filename, IPython will load that into the
387 - If the argument is a filename, IPython will load that into the
388 editor. It will execute its contents with execfile() when you exit,
388 editor. It will execute its contents with execfile() when you exit,
389 loading any code in the file into your interactive namespace.
389 loading any code in the file into your interactive namespace.
390
390
391 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
391 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
392 The syntax is the same as in the %history magic.
392 The syntax is the same as in the %history magic.
393
393
394 - If the argument is a string variable, its contents are loaded
394 - If the argument is a string variable, its contents are loaded
395 into the editor. You can thus edit any string which contains
395 into the editor. You can thus edit any string which contains
396 python code (including the result of previous edits).
396 python code (including the result of previous edits).
397
397
398 - If the argument is the name of an object (other than a string),
398 - If the argument is the name of an object (other than a string),
399 IPython will try to locate the file where it was defined and open the
399 IPython will try to locate the file where it was defined and open the
400 editor at the point where it is defined. You can use `%edit function`
400 editor at the point where it is defined. You can use `%edit function`
401 to load an editor exactly at the point where 'function' is defined,
401 to load an editor exactly at the point where 'function' is defined,
402 edit it and have the file be executed automatically.
402 edit it and have the file be executed automatically.
403
403
404 - If the object is a macro (see %macro for details), this opens up your
404 - If the object is a macro (see %macro for details), this opens up your
405 specified editor with a temporary file containing the macro's data.
405 specified editor with a temporary file containing the macro's data.
406 Upon exit, the macro is reloaded with the contents of the file.
406 Upon exit, the macro is reloaded with the contents of the file.
407
407
408 Note: opening at an exact line is only supported under Unix, and some
408 Note: opening at an exact line is only supported under Unix, and some
409 editors (like kedit and gedit up to Gnome 2.8) do not understand the
409 editors (like kedit and gedit up to Gnome 2.8) do not understand the
410 '+NUMBER' parameter necessary for this feature. Good editors like
410 '+NUMBER' parameter necessary for this feature. Good editors like
411 (X)Emacs, vi, jed, pico and joe all do.
411 (X)Emacs, vi, jed, pico and joe all do.
412
412
413 After executing your code, %edit will return as output the code you
413 After executing your code, %edit will return as output the code you
414 typed in the editor (except when it was an existing file). This way
414 typed in the editor (except when it was an existing file). This way
415 you can reload the code in further invocations of %edit as a variable,
415 you can reload the code in further invocations of %edit as a variable,
416 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
416 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
417 the output.
417 the output.
418
418
419 Note that %edit is also available through the alias %ed.
419 Note that %edit is also available through the alias %ed.
420
420
421 This is an example of creating a simple function inside the editor and
421 This is an example of creating a simple function inside the editor and
422 then modifying it. First, start up the editor::
422 then modifying it. First, start up the editor::
423
423
424 In [1]: ed
424 In [1]: ed
425 Editing... done. Executing edited code...
425 Editing... done. Executing edited code...
426 Out[1]: 'def foo():\\n print "foo() was defined in an editing
426 Out[1]: 'def foo():\\n print "foo() was defined in an editing
427 session"\\n'
427 session"\\n'
428
428
429 We can then call the function foo()::
429 We can then call the function foo()::
430
430
431 In [2]: foo()
431 In [2]: foo()
432 foo() was defined in an editing session
432 foo() was defined in an editing session
433
433
434 Now we edit foo. IPython automatically loads the editor with the
434 Now we edit foo. IPython automatically loads the editor with the
435 (temporary) file where foo() was previously defined::
435 (temporary) file where foo() was previously defined::
436
436
437 In [3]: ed foo
437 In [3]: ed foo
438 Editing... done. Executing edited code...
438 Editing... done. Executing edited code...
439
439
440 And if we call foo() again we get the modified version::
440 And if we call foo() again we get the modified version::
441
441
442 In [4]: foo()
442 In [4]: foo()
443 foo() has now been changed!
443 foo() has now been changed!
444
444
445 Here is an example of how to edit a code snippet successive
445 Here is an example of how to edit a code snippet successive
446 times. First we call the editor::
446 times. First we call the editor::
447
447
448 In [5]: ed
448 In [5]: ed
449 Editing... done. Executing edited code...
449 Editing... done. Executing edited code...
450 hello
450 hello
451 Out[5]: "print 'hello'\\n"
451 Out[5]: "print 'hello'\\n"
452
452
453 Now we call it again with the previous output (stored in _)::
453 Now we call it again with the previous output (stored in _)::
454
454
455 In [6]: ed _
455 In [6]: ed _
456 Editing... done. Executing edited code...
456 Editing... done. Executing edited code...
457 hello world
457 hello world
458 Out[6]: "print 'hello world'\\n"
458 Out[6]: "print 'hello world'\\n"
459
459
460 Now we call it with the output #8 (stored in _8, also as Out[8])::
460 Now we call it with the output #8 (stored in _8, also as Out[8])::
461
461
462 In [7]: ed _8
462 In [7]: ed _8
463 Editing... done. Executing edited code...
463 Editing... done. Executing edited code...
464 hello again
464 hello again
465 Out[7]: "print 'hello again'\\n"
465 Out[7]: "print 'hello again'\\n"
466
466
467
467
468 Changing the default editor hook:
468 Changing the default editor hook:
469
469
470 If you wish to write your own editor hook, you can put it in a
470 If you wish to write your own editor hook, you can put it in a
471 configuration file which you load at startup time. The default hook
471 configuration file which you load at startup time. The default hook
472 is defined in the IPython.core.hooks module, and you can use that as a
472 is defined in the IPython.core.hooks module, and you can use that as a
473 starting example for further modifications. That file also has
473 starting example for further modifications. That file also has
474 general instructions on how to set a new hook for use once you've
474 general instructions on how to set a new hook for use once you've
475 defined it."""
475 defined it."""
476 opts,args = self.parse_options(parameter_s,'prxn:')
476 opts,args = self.parse_options(parameter_s,'prxn:')
477
477
478 try:
478 try:
479 filename, lineno, is_temp = self._find_edit_target(self.shell,
479 filename, lineno, is_temp = self._find_edit_target(self.shell,
480 args, opts, last_call)
480 args, opts, last_call)
481 except MacroToEdit as e:
481 except MacroToEdit as e:
482 self._edit_macro(args, e.args[0])
482 self._edit_macro(args, e.args[0])
483 return
483 return
484
484
485 # do actual editing here
485 # do actual editing here
486 print 'Editing...',
486 print 'Editing...',
487 sys.stdout.flush()
487 sys.stdout.flush()
488 try:
488 try:
489 # Quote filenames that may have spaces in them
489 # Quote filenames that may have spaces in them
490 if ' ' in filename:
490 if ' ' in filename:
491 filename = "'%s'" % filename
491 filename = "'%s'" % filename
492 self.shell.hooks.editor(filename,lineno)
492 self.shell.hooks.editor(filename,lineno)
493 except TryNext:
493 except TryNext:
494 warn('Could not open editor')
494 warn('Could not open editor')
495 return
495 return
496
496
497 # XXX TODO: should this be generalized for all string vars?
497 # XXX TODO: should this be generalized for all string vars?
498 # For now, this is special-cased to blocks created by cpaste
498 # For now, this is special-cased to blocks created by cpaste
499 if args.strip() == 'pasted_block':
499 if args.strip() == 'pasted_block':
500 self.shell.user_ns['pasted_block'] = file_read(filename)
500 self.shell.user_ns['pasted_block'] = file_read(filename)
501
501
502 if 'x' in opts: # -x prevents actual execution
502 if 'x' in opts: # -x prevents actual execution
503 print
503 print
504 else:
504 else:
505 print 'done. Executing edited code...'
505 print 'done. Executing edited code...'
506 if 'r' in opts: # Untranslated IPython code
506 if 'r' in opts: # Untranslated IPython code
507 self.shell.run_cell(file_read(filename),
507 self.shell.run_cell(file_read(filename),
508 store_history=False)
508 store_history=False)
509 else:
509 else:
510 self.shell.safe_execfile(filename, self.shell.user_ns,
510 self.shell.safe_execfile(filename, self.shell.user_ns,
511 self.shell.user_ns)
511 self.shell.user_ns)
512
512
513 if is_temp:
513 if is_temp:
514 try:
514 try:
515 return open(filename).read()
515 return open(filename).read()
516 except IOError,msg:
516 except IOError as msg:
517 if msg.filename == filename:
517 if msg.filename == filename:
518 warn('File not found. Did you forget to save?')
518 warn('File not found. Did you forget to save?')
519 return
519 return
520 else:
520 else:
521 self.shell.showtraceback()
521 self.shell.showtraceback()
@@ -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,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 opts.has_key('i'):
218 ignore_case = True
218 ignore_case = True
219 elif opts.has_key('c'):
219 elif opts.has_key('c'):
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 opts.has_key('f'):
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,340 +1,340 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Paging capabilities for IPython.core
3 Paging capabilities for IPython.core
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 * Fernando Perez
8 * Fernando Perez
9
9
10 Notes
10 Notes
11 -----
11 -----
12
12
13 For now this uses ipapi, so it can't be in IPython.utils. If we can get
13 For now this uses ipapi, so it can't be in IPython.utils. If we can get
14 rid of that dependency, we could move it there.
14 rid of that dependency, we could move it there.
15 -----
15 -----
16 """
16 """
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Copyright (C) 2008-2011 The IPython Development Team
19 # Copyright (C) 2008-2011 The IPython Development Team
20 #
20 #
21 # Distributed under the terms of the BSD License. The full license is in
21 # Distributed under the terms of the BSD License. The full license is in
22 # the file COPYING, distributed as part of this software.
22 # the file COPYING, distributed as part of this software.
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Imports
26 # Imports
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28
28
29 import os
29 import os
30 import re
30 import re
31 import sys
31 import sys
32 import tempfile
32 import tempfile
33
33
34 from io import UnsupportedOperation
34 from io import UnsupportedOperation
35
35
36 from IPython.core import ipapi
36 from IPython.core import ipapi
37 from IPython.core.error import TryNext
37 from IPython.core.error import TryNext
38 from IPython.utils.cursesimport import use_curses
38 from IPython.utils.cursesimport import use_curses
39 from IPython.utils.data import chop
39 from IPython.utils.data import chop
40 from IPython.utils import io
40 from IPython.utils import io
41 from IPython.utils.process import system
41 from IPython.utils.process import system
42 from IPython.utils.terminal import get_terminal_size
42 from IPython.utils.terminal import get_terminal_size
43
43
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Classes and functions
46 # Classes and functions
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 esc_re = re.compile(r"(\x1b[^m]+m)")
49 esc_re = re.compile(r"(\x1b[^m]+m)")
50
50
51 def page_dumb(strng, start=0, screen_lines=25):
51 def page_dumb(strng, start=0, screen_lines=25):
52 """Very dumb 'pager' in Python, for when nothing else works.
52 """Very dumb 'pager' in Python, for when nothing else works.
53
53
54 Only moves forward, same interface as page(), except for pager_cmd and
54 Only moves forward, same interface as page(), except for pager_cmd and
55 mode."""
55 mode."""
56
56
57 out_ln = strng.splitlines()[start:]
57 out_ln = strng.splitlines()[start:]
58 screens = chop(out_ln,screen_lines-1)
58 screens = chop(out_ln,screen_lines-1)
59 if len(screens) == 1:
59 if len(screens) == 1:
60 print >>io.stdout, os.linesep.join(screens[0])
60 print >>io.stdout, os.linesep.join(screens[0])
61 else:
61 else:
62 last_escape = ""
62 last_escape = ""
63 for scr in screens[0:-1]:
63 for scr in screens[0:-1]:
64 hunk = os.linesep.join(scr)
64 hunk = os.linesep.join(scr)
65 print >>io.stdout, last_escape + hunk
65 print >>io.stdout, last_escape + hunk
66 if not page_more():
66 if not page_more():
67 return
67 return
68 esc_list = esc_re.findall(hunk)
68 esc_list = esc_re.findall(hunk)
69 if len(esc_list) > 0:
69 if len(esc_list) > 0:
70 last_escape = esc_list[-1]
70 last_escape = esc_list[-1]
71 print >>io.stdout, last_escape + os.linesep.join(screens[-1])
71 print >>io.stdout, last_escape + os.linesep.join(screens[-1])
72
72
73 def _detect_screen_size(use_curses, screen_lines_def):
73 def _detect_screen_size(use_curses, screen_lines_def):
74 """Attempt to work out the number of lines on the screen.
74 """Attempt to work out the number of lines on the screen.
75
75
76 This is called by page(). It can raise an error (e.g. when run in the
76 This is called by page(). It can raise an error (e.g. when run in the
77 test suite), so it's separated out so it can easily be called in a try block.
77 test suite), so it's separated out so it can easily be called in a try block.
78 """
78 """
79 TERM = os.environ.get('TERM',None)
79 TERM = os.environ.get('TERM',None)
80 if (TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5':
80 if (TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5':
81 local_use_curses = use_curses
81 local_use_curses = use_curses
82 else:
82 else:
83 # curses causes problems on many terminals other than xterm, and
83 # curses causes problems on many terminals other than xterm, and
84 # some termios calls lock up on Sun OS5.
84 # some termios calls lock up on Sun OS5.
85 local_use_curses = False
85 local_use_curses = False
86 if local_use_curses:
86 if local_use_curses:
87 import termios
87 import termios
88 import curses
88 import curses
89 # There is a bug in curses, where *sometimes* it fails to properly
89 # There is a bug in curses, where *sometimes* it fails to properly
90 # initialize, and then after the endwin() call is made, the
90 # initialize, and then after the endwin() call is made, the
91 # terminal is left in an unusable state. Rather than trying to
91 # terminal is left in an unusable state. Rather than trying to
92 # check everytime for this (by requesting and comparing termios
92 # check everytime for this (by requesting and comparing termios
93 # flags each time), we just save the initial terminal state and
93 # flags each time), we just save the initial terminal state and
94 # unconditionally reset it every time. It's cheaper than making
94 # unconditionally reset it every time. It's cheaper than making
95 # the checks.
95 # the checks.
96 term_flags = termios.tcgetattr(sys.stdout)
96 term_flags = termios.tcgetattr(sys.stdout)
97
97
98 # Curses modifies the stdout buffer size by default, which messes
98 # Curses modifies the stdout buffer size by default, which messes
99 # up Python's normal stdout buffering. This would manifest itself
99 # up Python's normal stdout buffering. This would manifest itself
100 # to IPython users as delayed printing on stdout after having used
100 # to IPython users as delayed printing on stdout after having used
101 # the pager.
101 # the pager.
102 #
102 #
103 # We can prevent this by manually setting the NCURSES_NO_SETBUF
103 # We can prevent this by manually setting the NCURSES_NO_SETBUF
104 # environment variable. For more details, see:
104 # environment variable. For more details, see:
105 # http://bugs.python.org/issue10144
105 # http://bugs.python.org/issue10144
106 NCURSES_NO_SETBUF = os.environ.get('NCURSES_NO_SETBUF', None)
106 NCURSES_NO_SETBUF = os.environ.get('NCURSES_NO_SETBUF', None)
107 os.environ['NCURSES_NO_SETBUF'] = ''
107 os.environ['NCURSES_NO_SETBUF'] = ''
108
108
109 # Proceed with curses initialization
109 # Proceed with curses initialization
110 scr = curses.initscr()
110 scr = curses.initscr()
111 screen_lines_real,screen_cols = scr.getmaxyx()
111 screen_lines_real,screen_cols = scr.getmaxyx()
112 curses.endwin()
112 curses.endwin()
113
113
114 # Restore environment
114 # Restore environment
115 if NCURSES_NO_SETBUF is None:
115 if NCURSES_NO_SETBUF is None:
116 del os.environ['NCURSES_NO_SETBUF']
116 del os.environ['NCURSES_NO_SETBUF']
117 else:
117 else:
118 os.environ['NCURSES_NO_SETBUF'] = NCURSES_NO_SETBUF
118 os.environ['NCURSES_NO_SETBUF'] = NCURSES_NO_SETBUF
119
119
120 # Restore terminal state in case endwin() didn't.
120 # Restore terminal state in case endwin() didn't.
121 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
121 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
122 # Now we have what we needed: the screen size in rows/columns
122 # Now we have what we needed: the screen size in rows/columns
123 return screen_lines_real
123 return screen_lines_real
124 #print '***Screen size:',screen_lines_real,'lines x',\
124 #print '***Screen size:',screen_lines_real,'lines x',\
125 #screen_cols,'columns.' # dbg
125 #screen_cols,'columns.' # dbg
126 else:
126 else:
127 return screen_lines_def
127 return screen_lines_def
128
128
129 def page(strng, start=0, screen_lines=0, pager_cmd=None):
129 def page(strng, start=0, screen_lines=0, pager_cmd=None):
130 """Print a string, piping through a pager after a certain length.
130 """Print a string, piping through a pager after a certain length.
131
131
132 The screen_lines parameter specifies the number of *usable* lines of your
132 The screen_lines parameter specifies the number of *usable* lines of your
133 terminal screen (total lines minus lines you need to reserve to show other
133 terminal screen (total lines minus lines you need to reserve to show other
134 information).
134 information).
135
135
136 If you set screen_lines to a number <=0, page() will try to auto-determine
136 If you set screen_lines to a number <=0, page() will try to auto-determine
137 your screen size and will only use up to (screen_size+screen_lines) for
137 your screen size and will only use up to (screen_size+screen_lines) for
138 printing, paging after that. That is, if you want auto-detection but need
138 printing, paging after that. That is, if you want auto-detection but need
139 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
139 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
140 auto-detection without any lines reserved simply use screen_lines = 0.
140 auto-detection without any lines reserved simply use screen_lines = 0.
141
141
142 If a string won't fit in the allowed lines, it is sent through the
142 If a string won't fit in the allowed lines, it is sent through the
143 specified pager command. If none given, look for PAGER in the environment,
143 specified pager command. If none given, look for PAGER in the environment,
144 and ultimately default to less.
144 and ultimately default to less.
145
145
146 If no system pager works, the string is sent through a 'dumb pager'
146 If no system pager works, the string is sent through a 'dumb pager'
147 written in python, very simplistic.
147 written in python, very simplistic.
148 """
148 """
149
149
150 # Some routines may auto-compute start offsets incorrectly and pass a
150 # Some routines may auto-compute start offsets incorrectly and pass a
151 # negative value. Offset to 0 for robustness.
151 # negative value. Offset to 0 for robustness.
152 start = max(0, start)
152 start = max(0, start)
153
153
154 # first, try the hook
154 # first, try the hook
155 ip = ipapi.get()
155 ip = ipapi.get()
156 if ip:
156 if ip:
157 try:
157 try:
158 ip.hooks.show_in_pager(strng)
158 ip.hooks.show_in_pager(strng)
159 return
159 return
160 except TryNext:
160 except TryNext:
161 pass
161 pass
162
162
163 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
163 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
164 TERM = os.environ.get('TERM','dumb')
164 TERM = os.environ.get('TERM','dumb')
165 if TERM in ['dumb','emacs'] and os.name != 'nt':
165 if TERM in ['dumb','emacs'] and os.name != 'nt':
166 print strng
166 print strng
167 return
167 return
168 # chop off the topmost part of the string we don't want to see
168 # chop off the topmost part of the string we don't want to see
169 str_lines = strng.splitlines()[start:]
169 str_lines = strng.splitlines()[start:]
170 str_toprint = os.linesep.join(str_lines)
170 str_toprint = os.linesep.join(str_lines)
171 num_newlines = len(str_lines)
171 num_newlines = len(str_lines)
172 len_str = len(str_toprint)
172 len_str = len(str_toprint)
173
173
174 # Dumb heuristics to guesstimate number of on-screen lines the string
174 # Dumb heuristics to guesstimate number of on-screen lines the string
175 # takes. Very basic, but good enough for docstrings in reasonable
175 # takes. Very basic, but good enough for docstrings in reasonable
176 # terminals. If someone later feels like refining it, it's not hard.
176 # terminals. If someone later feels like refining it, it's not hard.
177 numlines = max(num_newlines,int(len_str/80)+1)
177 numlines = max(num_newlines,int(len_str/80)+1)
178
178
179 screen_lines_def = get_terminal_size()[1]
179 screen_lines_def = get_terminal_size()[1]
180
180
181 # auto-determine screen size
181 # auto-determine screen size
182 if screen_lines <= 0:
182 if screen_lines <= 0:
183 try:
183 try:
184 screen_lines += _detect_screen_size(use_curses, screen_lines_def)
184 screen_lines += _detect_screen_size(use_curses, screen_lines_def)
185 except (TypeError, UnsupportedOperation):
185 except (TypeError, UnsupportedOperation):
186 print >>io.stdout, str_toprint
186 print >>io.stdout, str_toprint
187 return
187 return
188
188
189 #print 'numlines',numlines,'screenlines',screen_lines # dbg
189 #print 'numlines',numlines,'screenlines',screen_lines # dbg
190 if numlines <= screen_lines :
190 if numlines <= screen_lines :
191 #print '*** normal print' # dbg
191 #print '*** normal print' # dbg
192 print >>io.stdout, str_toprint
192 print >>io.stdout, str_toprint
193 else:
193 else:
194 # Try to open pager and default to internal one if that fails.
194 # Try to open pager and default to internal one if that fails.
195 # All failure modes are tagged as 'retval=1', to match the return
195 # All failure modes are tagged as 'retval=1', to match the return
196 # value of a failed system command. If any intermediate attempt
196 # value of a failed system command. If any intermediate attempt
197 # sets retval to 1, at the end we resort to our own page_dumb() pager.
197 # sets retval to 1, at the end we resort to our own page_dumb() pager.
198 pager_cmd = get_pager_cmd(pager_cmd)
198 pager_cmd = get_pager_cmd(pager_cmd)
199 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
199 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
200 if os.name == 'nt':
200 if os.name == 'nt':
201 if pager_cmd.startswith('type'):
201 if pager_cmd.startswith('type'):
202 # The default WinXP 'type' command is failing on complex strings.
202 # The default WinXP 'type' command is failing on complex strings.
203 retval = 1
203 retval = 1
204 else:
204 else:
205 tmpname = tempfile.mktemp('.txt')
205 tmpname = tempfile.mktemp('.txt')
206 tmpfile = open(tmpname,'wt')
206 tmpfile = open(tmpname,'wt')
207 tmpfile.write(strng)
207 tmpfile.write(strng)
208 tmpfile.close()
208 tmpfile.close()
209 cmd = "%s < %s" % (pager_cmd,tmpname)
209 cmd = "%s < %s" % (pager_cmd,tmpname)
210 if os.system(cmd):
210 if os.system(cmd):
211 retval = 1
211 retval = 1
212 else:
212 else:
213 retval = None
213 retval = None
214 os.remove(tmpname)
214 os.remove(tmpname)
215 else:
215 else:
216 try:
216 try:
217 retval = None
217 retval = None
218 # if I use popen4, things hang. No idea why.
218 # if I use popen4, things hang. No idea why.
219 #pager,shell_out = os.popen4(pager_cmd)
219 #pager,shell_out = os.popen4(pager_cmd)
220 pager = os.popen(pager_cmd,'w')
220 pager = os.popen(pager_cmd,'w')
221 pager.write(strng)
221 pager.write(strng)
222 pager.close()
222 pager.close()
223 retval = pager.close() # success returns None
223 retval = pager.close() # success returns None
224 except IOError,msg: # broken pipe when user quits
224 except IOError as msg: # broken pipe when user quits
225 if msg.args == (32,'Broken pipe'):
225 if msg.args == (32,'Broken pipe'):
226 retval = None
226 retval = None
227 else:
227 else:
228 retval = 1
228 retval = 1
229 except OSError:
229 except OSError:
230 # Other strange problems, sometimes seen in Win2k/cygwin
230 # Other strange problems, sometimes seen in Win2k/cygwin
231 retval = 1
231 retval = 1
232 if retval is not None:
232 if retval is not None:
233 page_dumb(strng,screen_lines=screen_lines)
233 page_dumb(strng,screen_lines=screen_lines)
234
234
235
235
236 def page_file(fname, start=0, pager_cmd=None):
236 def page_file(fname, start=0, pager_cmd=None):
237 """Page a file, using an optional pager command and starting line.
237 """Page a file, using an optional pager command and starting line.
238 """
238 """
239
239
240 pager_cmd = get_pager_cmd(pager_cmd)
240 pager_cmd = get_pager_cmd(pager_cmd)
241 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
241 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
242
242
243 try:
243 try:
244 if os.environ['TERM'] in ['emacs','dumb']:
244 if os.environ['TERM'] in ['emacs','dumb']:
245 raise EnvironmentError
245 raise EnvironmentError
246 system(pager_cmd + ' ' + fname)
246 system(pager_cmd + ' ' + fname)
247 except:
247 except:
248 try:
248 try:
249 if start > 0:
249 if start > 0:
250 start -= 1
250 start -= 1
251 page(open(fname).read(),start)
251 page(open(fname).read(),start)
252 except:
252 except:
253 print 'Unable to show file',`fname`
253 print 'Unable to show file',`fname`
254
254
255
255
256 def get_pager_cmd(pager_cmd=None):
256 def get_pager_cmd(pager_cmd=None):
257 """Return a pager command.
257 """Return a pager command.
258
258
259 Makes some attempts at finding an OS-correct one.
259 Makes some attempts at finding an OS-correct one.
260 """
260 """
261 if os.name == 'posix':
261 if os.name == 'posix':
262 default_pager_cmd = 'less -r' # -r for color control sequences
262 default_pager_cmd = 'less -r' # -r for color control sequences
263 elif os.name in ['nt','dos']:
263 elif os.name in ['nt','dos']:
264 default_pager_cmd = 'type'
264 default_pager_cmd = 'type'
265
265
266 if pager_cmd is None:
266 if pager_cmd is None:
267 try:
267 try:
268 pager_cmd = os.environ['PAGER']
268 pager_cmd = os.environ['PAGER']
269 except:
269 except:
270 pager_cmd = default_pager_cmd
270 pager_cmd = default_pager_cmd
271 return pager_cmd
271 return pager_cmd
272
272
273
273
274 def get_pager_start(pager, start):
274 def get_pager_start(pager, start):
275 """Return the string for paging files with an offset.
275 """Return the string for paging files with an offset.
276
276
277 This is the '+N' argument which less and more (under Unix) accept.
277 This is the '+N' argument which less and more (under Unix) accept.
278 """
278 """
279
279
280 if pager in ['less','more']:
280 if pager in ['less','more']:
281 if start:
281 if start:
282 start_string = '+' + str(start)
282 start_string = '+' + str(start)
283 else:
283 else:
284 start_string = ''
284 start_string = ''
285 else:
285 else:
286 start_string = ''
286 start_string = ''
287 return start_string
287 return start_string
288
288
289
289
290 # (X)emacs on win32 doesn't like to be bypassed with msvcrt.getch()
290 # (X)emacs on win32 doesn't like to be bypassed with msvcrt.getch()
291 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
291 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
292 import msvcrt
292 import msvcrt
293 def page_more():
293 def page_more():
294 """ Smart pausing between pages
294 """ Smart pausing between pages
295
295
296 @return: True if need print more lines, False if quit
296 @return: True if need print more lines, False if quit
297 """
297 """
298 io.stdout.write('---Return to continue, q to quit--- ')
298 io.stdout.write('---Return to continue, q to quit--- ')
299 ans = msvcrt.getch()
299 ans = msvcrt.getch()
300 if ans in ("q", "Q"):
300 if ans in ("q", "Q"):
301 result = False
301 result = False
302 else:
302 else:
303 result = True
303 result = True
304 io.stdout.write("\b"*37 + " "*37 + "\b"*37)
304 io.stdout.write("\b"*37 + " "*37 + "\b"*37)
305 return result
305 return result
306 else:
306 else:
307 def page_more():
307 def page_more():
308 ans = raw_input('---Return to continue, q to quit--- ')
308 ans = raw_input('---Return to continue, q to quit--- ')
309 if ans.lower().startswith('q'):
309 if ans.lower().startswith('q'):
310 return False
310 return False
311 else:
311 else:
312 return True
312 return True
313
313
314
314
315 def snip_print(str,width = 75,print_full = 0,header = ''):
315 def snip_print(str,width = 75,print_full = 0,header = ''):
316 """Print a string snipping the midsection to fit in width.
316 """Print a string snipping the midsection to fit in width.
317
317
318 print_full: mode control:
318 print_full: mode control:
319 - 0: only snip long strings
319 - 0: only snip long strings
320 - 1: send to page() directly.
320 - 1: send to page() directly.
321 - 2: snip long strings and ask for full length viewing with page()
321 - 2: snip long strings and ask for full length viewing with page()
322 Return 1 if snipping was necessary, 0 otherwise."""
322 Return 1 if snipping was necessary, 0 otherwise."""
323
323
324 if print_full == 1:
324 if print_full == 1:
325 page(header+str)
325 page(header+str)
326 return 0
326 return 0
327
327
328 print header,
328 print header,
329 if len(str) < width:
329 if len(str) < width:
330 print str
330 print str
331 snip = 0
331 snip = 0
332 else:
332 else:
333 whalf = int((width -5)/2)
333 whalf = int((width -5)/2)
334 print str[:whalf] + ' <...> ' + str[-whalf:]
334 print str[:whalf] + ' <...> ' + str[-whalf:]
335 snip = 1
335 snip = 1
336 if snip and print_full == 2:
336 if snip and print_full == 2:
337 if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
337 if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
338 page(str)
338 page(str)
339 return snip
339 return snip
340
340
@@ -1,250 +1,250 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for code execution (%run and related), which is particularly tricky.
2 """Tests for code execution (%run and related), which is particularly tricky.
3
3
4 Because of how %run manages namespaces, and the fact that we are trying here to
4 Because of how %run manages namespaces, and the fact that we are trying here to
5 verify subtle object deletion and reference counting issues, the %run tests
5 verify subtle object deletion and reference counting issues, the %run tests
6 will be kept in this separate file. This makes it easier to aggregate in one
6 will be kept in this separate file. This makes it easier to aggregate in one
7 place the tricks needed to handle it; most other magics are much easier to test
7 place the tricks needed to handle it; most other magics are much easier to test
8 and we do so in a common test_magic file.
8 and we do so in a common test_magic file.
9 """
9 """
10 from __future__ import absolute_import
10 from __future__ import absolute_import
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 import os
16 import os
17 import sys
17 import sys
18 import tempfile
18 import tempfile
19
19
20 import nose.tools as nt
20 import nose.tools as nt
21 from nose import SkipTest
21 from nose import SkipTest
22
22
23 from IPython.testing import decorators as dec
23 from IPython.testing import decorators as dec
24 from IPython.testing import tools as tt
24 from IPython.testing import tools as tt
25 from IPython.utils import py3compat
25 from IPython.utils import py3compat
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Test functions begin
28 # Test functions begin
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 def doctest_refbug():
31 def doctest_refbug():
32 """Very nasty problem with references held by multiple runs of a script.
32 """Very nasty problem with references held by multiple runs of a script.
33 See: https://github.com/ipython/ipython/issues/141
33 See: https://github.com/ipython/ipython/issues/141
34
34
35 In [1]: _ip.clear_main_mod_cache()
35 In [1]: _ip.clear_main_mod_cache()
36 # random
36 # random
37
37
38 In [2]: %run refbug
38 In [2]: %run refbug
39
39
40 In [3]: call_f()
40 In [3]: call_f()
41 lowercased: hello
41 lowercased: hello
42
42
43 In [4]: %run refbug
43 In [4]: %run refbug
44
44
45 In [5]: call_f()
45 In [5]: call_f()
46 lowercased: hello
46 lowercased: hello
47 lowercased: hello
47 lowercased: hello
48 """
48 """
49
49
50
50
51 def doctest_run_builtins():
51 def doctest_run_builtins():
52 r"""Check that %run doesn't damage __builtins__.
52 r"""Check that %run doesn't damage __builtins__.
53
53
54 In [1]: import tempfile
54 In [1]: import tempfile
55
55
56 In [2]: bid1 = id(__builtins__)
56 In [2]: bid1 = id(__builtins__)
57
57
58 In [3]: fname = tempfile.mkstemp('.py')[1]
58 In [3]: fname = tempfile.mkstemp('.py')[1]
59
59
60 In [3]: f = open(fname,'w')
60 In [3]: f = open(fname,'w')
61
61
62 In [4]: dummy= f.write('pass\n')
62 In [4]: dummy= f.write('pass\n')
63
63
64 In [5]: f.flush()
64 In [5]: f.flush()
65
65
66 In [6]: t1 = type(__builtins__)
66 In [6]: t1 = type(__builtins__)
67
67
68 In [7]: %run $fname
68 In [7]: %run $fname
69
69
70 In [7]: f.close()
70 In [7]: f.close()
71
71
72 In [8]: bid2 = id(__builtins__)
72 In [8]: bid2 = id(__builtins__)
73
73
74 In [9]: t2 = type(__builtins__)
74 In [9]: t2 = type(__builtins__)
75
75
76 In [10]: t1 == t2
76 In [10]: t1 == t2
77 Out[10]: True
77 Out[10]: True
78
78
79 In [10]: bid1 == bid2
79 In [10]: bid1 == bid2
80 Out[10]: True
80 Out[10]: True
81
81
82 In [12]: try:
82 In [12]: try:
83 ....: os.unlink(fname)
83 ....: os.unlink(fname)
84 ....: except:
84 ....: except:
85 ....: pass
85 ....: pass
86 ....:
86 ....:
87 """
87 """
88
88
89 @py3compat.doctest_refactor_print
89 @py3compat.doctest_refactor_print
90 def doctest_reset_del():
90 def doctest_reset_del():
91 """Test that resetting doesn't cause errors in __del__ methods.
91 """Test that resetting doesn't cause errors in __del__ methods.
92
92
93 In [2]: class A(object):
93 In [2]: class A(object):
94 ...: def __del__(self):
94 ...: def __del__(self):
95 ...: print str("Hi")
95 ...: print str("Hi")
96 ...:
96 ...:
97
97
98 In [3]: a = A()
98 In [3]: a = A()
99
99
100 In [4]: get_ipython().reset()
100 In [4]: get_ipython().reset()
101 Hi
101 Hi
102
102
103 In [5]: 1+1
103 In [5]: 1+1
104 Out[5]: 2
104 Out[5]: 2
105 """
105 """
106
106
107 # For some tests, it will be handy to organize them in a class with a common
107 # For some tests, it will be handy to organize them in a class with a common
108 # setup that makes a temp file
108 # setup that makes a temp file
109
109
110 class TestMagicRunPass(tt.TempFileMixin):
110 class TestMagicRunPass(tt.TempFileMixin):
111
111
112 def setup(self):
112 def setup(self):
113 """Make a valid python temp file."""
113 """Make a valid python temp file."""
114 self.mktmp('pass\n')
114 self.mktmp('pass\n')
115
115
116 def run_tmpfile(self):
116 def run_tmpfile(self):
117 _ip = get_ipython()
117 _ip = get_ipython()
118 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
118 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
119 # See below and ticket https://bugs.launchpad.net/bugs/366353
119 # See below and ticket https://bugs.launchpad.net/bugs/366353
120 _ip.magic('run %s' % self.fname)
120 _ip.magic('run %s' % self.fname)
121
121
122 def run_tmpfile_p(self):
122 def run_tmpfile_p(self):
123 _ip = get_ipython()
123 _ip = get_ipython()
124 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
124 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
125 # See below and ticket https://bugs.launchpad.net/bugs/366353
125 # See below and ticket https://bugs.launchpad.net/bugs/366353
126 _ip.magic('run -p %s' % self.fname)
126 _ip.magic('run -p %s' % self.fname)
127
127
128 def test_builtins_id(self):
128 def test_builtins_id(self):
129 """Check that %run doesn't damage __builtins__ """
129 """Check that %run doesn't damage __builtins__ """
130 _ip = get_ipython()
130 _ip = get_ipython()
131 # Test that the id of __builtins__ is not modified by %run
131 # Test that the id of __builtins__ is not modified by %run
132 bid1 = id(_ip.user_ns['__builtins__'])
132 bid1 = id(_ip.user_ns['__builtins__'])
133 self.run_tmpfile()
133 self.run_tmpfile()
134 bid2 = id(_ip.user_ns['__builtins__'])
134 bid2 = id(_ip.user_ns['__builtins__'])
135 tt.assert_equals(bid1, bid2)
135 tt.assert_equals(bid1, bid2)
136
136
137 def test_builtins_type(self):
137 def test_builtins_type(self):
138 """Check that the type of __builtins__ doesn't change with %run.
138 """Check that the type of __builtins__ doesn't change with %run.
139
139
140 However, the above could pass if __builtins__ was already modified to
140 However, the above could pass if __builtins__ was already modified to
141 be a dict (it should be a module) by a previous use of %run. So we
141 be a dict (it should be a module) by a previous use of %run. So we
142 also check explicitly that it really is a module:
142 also check explicitly that it really is a module:
143 """
143 """
144 _ip = get_ipython()
144 _ip = get_ipython()
145 self.run_tmpfile()
145 self.run_tmpfile()
146 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
146 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
147
147
148 def test_prompts(self):
148 def test_prompts(self):
149 """Test that prompts correctly generate after %run"""
149 """Test that prompts correctly generate after %run"""
150 self.run_tmpfile()
150 self.run_tmpfile()
151 _ip = get_ipython()
151 _ip = get_ipython()
152 p2 = _ip.prompt_manager.render('in2').strip()
152 p2 = _ip.prompt_manager.render('in2').strip()
153 nt.assert_equals(p2[:3], '...')
153 nt.assert_equals(p2[:3], '...')
154
154
155 def test_run_profile( self ):
155 def test_run_profile( self ):
156 """Test that the option -p, which invokes the profiler, do not
156 """Test that the option -p, which invokes the profiler, do not
157 crash by invoking execfile"""
157 crash by invoking execfile"""
158 _ip = get_ipython()
158 _ip = get_ipython()
159 self.run_tmpfile_p()
159 self.run_tmpfile_p()
160
160
161
161
162 class TestMagicRunSimple(tt.TempFileMixin):
162 class TestMagicRunSimple(tt.TempFileMixin):
163
163
164 def test_simpledef(self):
164 def test_simpledef(self):
165 """Test that simple class definitions work."""
165 """Test that simple class definitions work."""
166 src = ("class foo: pass\n"
166 src = ("class foo: pass\n"
167 "def f(): return foo()")
167 "def f(): return foo()")
168 self.mktmp(src)
168 self.mktmp(src)
169 _ip.magic('run %s' % self.fname)
169 _ip.magic('run %s' % self.fname)
170 _ip.run_cell('t = isinstance(f(), foo)')
170 _ip.run_cell('t = isinstance(f(), foo)')
171 nt.assert_true(_ip.user_ns['t'])
171 nt.assert_true(_ip.user_ns['t'])
172
172
173 def test_obj_del(self):
173 def test_obj_del(self):
174 """Test that object's __del__ methods are called on exit."""
174 """Test that object's __del__ methods are called on exit."""
175 if sys.platform == 'win32':
175 if sys.platform == 'win32':
176 try:
176 try:
177 import win32api
177 import win32api
178 except ImportError:
178 except ImportError:
179 raise SkipTest("Test requires pywin32")
179 raise SkipTest("Test requires pywin32")
180 src = ("class A(object):\n"
180 src = ("class A(object):\n"
181 " def __del__(self):\n"
181 " def __del__(self):\n"
182 " print 'object A deleted'\n"
182 " print 'object A deleted'\n"
183 "a = A()\n")
183 "a = A()\n")
184 self.mktmp(py3compat.doctest_refactor_print(src))
184 self.mktmp(py3compat.doctest_refactor_print(src))
185 if dec.module_not_available('sqlite3'):
185 if dec.module_not_available('sqlite3'):
186 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
186 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
187 else:
187 else:
188 err = None
188 err = None
189 tt.ipexec_validate(self.fname, 'object A deleted', err)
189 tt.ipexec_validate(self.fname, 'object A deleted', err)
190
190
191 @dec.skip_known_failure
191 @dec.skip_known_failure
192 def test_aggressive_namespace_cleanup(self):
192 def test_aggressive_namespace_cleanup(self):
193 """Test that namespace cleanup is not too aggressive GH-238
193 """Test that namespace cleanup is not too aggressive GH-238
194
194
195 Returning from another run magic deletes the namespace"""
195 Returning from another run magic deletes the namespace"""
196 # see ticket https://github.com/ipython/ipython/issues/238
196 # see ticket https://github.com/ipython/ipython/issues/238
197 class secondtmp(tt.TempFileMixin): pass
197 class secondtmp(tt.TempFileMixin): pass
198 empty = secondtmp()
198 empty = secondtmp()
199 empty.mktmp('')
199 empty.mktmp('')
200 src = ("ip = get_ipython()\n"
200 src = ("ip = get_ipython()\n"
201 "for i in range(5):\n"
201 "for i in range(5):\n"
202 " try:\n"
202 " try:\n"
203 " ip.magic('run %s')\n"
203 " ip.magic('run %s')\n"
204 " except NameError, e:\n"
204 " except NameError as e:\n"
205 " print i;break\n" % empty.fname)
205 " print i;break\n" % empty.fname)
206 self.mktmp(py3compat.doctest_refactor_print(src))
206 self.mktmp(py3compat.doctest_refactor_print(src))
207 _ip.magic('run %s' % self.fname)
207 _ip.magic('run %s' % self.fname)
208 _ip.run_cell('ip == get_ipython()')
208 _ip.run_cell('ip == get_ipython()')
209 tt.assert_equals(_ip.user_ns['i'], 5)
209 tt.assert_equals(_ip.user_ns['i'], 5)
210
210
211 @dec.skip_win32
211 @dec.skip_win32
212 def test_tclass(self):
212 def test_tclass(self):
213 mydir = os.path.dirname(__file__)
213 mydir = os.path.dirname(__file__)
214 tc = os.path.join(mydir, 'tclass')
214 tc = os.path.join(mydir, 'tclass')
215 src = ("%%run '%s' C-first\n"
215 src = ("%%run '%s' C-first\n"
216 "%%run '%s' C-second\n"
216 "%%run '%s' C-second\n"
217 "%%run '%s' C-third\n") % (tc, tc, tc)
217 "%%run '%s' C-third\n") % (tc, tc, tc)
218 self.mktmp(src, '.ipy')
218 self.mktmp(src, '.ipy')
219 out = """\
219 out = """\
220 ARGV 1-: ['C-first']
220 ARGV 1-: ['C-first']
221 ARGV 1-: ['C-second']
221 ARGV 1-: ['C-second']
222 tclass.py: deleting object: C-first
222 tclass.py: deleting object: C-first
223 ARGV 1-: ['C-third']
223 ARGV 1-: ['C-third']
224 tclass.py: deleting object: C-second
224 tclass.py: deleting object: C-second
225 tclass.py: deleting object: C-third
225 tclass.py: deleting object: C-third
226 """
226 """
227 if dec.module_not_available('sqlite3'):
227 if dec.module_not_available('sqlite3'):
228 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
228 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
229 else:
229 else:
230 err = None
230 err = None
231 tt.ipexec_validate(self.fname, out, err)
231 tt.ipexec_validate(self.fname, out, err)
232
232
233 def test_run_i_after_reset(self):
233 def test_run_i_after_reset(self):
234 """Check that %run -i still works after %reset (gh-693)"""
234 """Check that %run -i still works after %reset (gh-693)"""
235 src = "yy = zz\n"
235 src = "yy = zz\n"
236 self.mktmp(src)
236 self.mktmp(src)
237 _ip.run_cell("zz = 23")
237 _ip.run_cell("zz = 23")
238 _ip.magic('run -i %s' % self.fname)
238 _ip.magic('run -i %s' % self.fname)
239 tt.assert_equals(_ip.user_ns['yy'], 23)
239 tt.assert_equals(_ip.user_ns['yy'], 23)
240 _ip.magic('reset -f')
240 _ip.magic('reset -f')
241 _ip.run_cell("zz = 23")
241 _ip.run_cell("zz = 23")
242 _ip.magic('run -i %s' % self.fname)
242 _ip.magic('run -i %s' % self.fname)
243 tt.assert_equals(_ip.user_ns['yy'], 23)
243 tt.assert_equals(_ip.user_ns['yy'], 23)
244
244
245 def test_unicode(self):
245 def test_unicode(self):
246 """Check that files in odd encodings are accepted."""
246 """Check that files in odd encodings are accepted."""
247 mydir = os.path.dirname(__file__)
247 mydir = os.path.dirname(__file__)
248 na = os.path.join(mydir, 'nonascii.py')
248 na = os.path.join(mydir, 'nonascii.py')
249 _ip.magic('run "%s"' % na)
249 _ip.magic('run "%s"' % na)
250 tt.assert_equals(_ip.user_ns['u'], u'ΠŽΡ‚β„–Π€')
250 tt.assert_equals(_ip.user_ns['u'], u'ΠŽΡ‚β„–Π€')
@@ -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,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 locals.has_key(name_base):
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 frame.f_globals.has_key(name_base):
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 apply(handler, sys.exc_info() )
1234 apply(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 apply(handler, sys.exc_info() )
1242 apply(handler, sys.exc_info() )
1243 print ''
1243 print ''
1244
1244
@@ -1,1767 +1,1767 b''
1 # -*- coding: iso-8859-1 -*-
1 # -*- coding: iso-8859-1 -*-
2
2
3 import curses, fcntl, signal, struct, tty, textwrap, inspect
3 import curses, fcntl, signal, struct, tty, textwrap, inspect
4
4
5 from IPython.core import ipapi
5 from IPython.core import ipapi
6
6
7 import astyle, ipipe
7 import astyle, ipipe
8
8
9
9
10 # Python 2.3 compatibility
10 # Python 2.3 compatibility
11 try:
11 try:
12 set
12 set
13 except NameError:
13 except NameError:
14 import sets
14 import sets
15 set = sets.Set
15 set = sets.Set
16
16
17 # Python 2.3 compatibility
17 # Python 2.3 compatibility
18 try:
18 try:
19 sorted
19 sorted
20 except NameError:
20 except NameError:
21 from ipipe import sorted
21 from ipipe import sorted
22
22
23
23
24 class UnassignedKeyError(Exception):
24 class UnassignedKeyError(Exception):
25 """
25 """
26 Exception that is used for reporting unassigned keys.
26 Exception that is used for reporting unassigned keys.
27 """
27 """
28
28
29
29
30 class UnknownCommandError(Exception):
30 class UnknownCommandError(Exception):
31 """
31 """
32 Exception that is used for reporting unknown commands (this should never
32 Exception that is used for reporting unknown commands (this should never
33 happen).
33 happen).
34 """
34 """
35
35
36
36
37 class CommandError(Exception):
37 class CommandError(Exception):
38 """
38 """
39 Exception that is used for reporting that a command can't be executed.
39 Exception that is used for reporting that a command can't be executed.
40 """
40 """
41
41
42
42
43 class Keymap(dict):
43 class Keymap(dict):
44 """
44 """
45 Stores mapping of keys to commands.
45 Stores mapping of keys to commands.
46 """
46 """
47 def __init__(self):
47 def __init__(self):
48 self._keymap = {}
48 self._keymap = {}
49
49
50 def __setitem__(self, key, command):
50 def __setitem__(self, key, command):
51 if isinstance(key, str):
51 if isinstance(key, str):
52 for c in key:
52 for c in key:
53 dict.__setitem__(self, ord(c), command)
53 dict.__setitem__(self, ord(c), command)
54 else:
54 else:
55 dict.__setitem__(self, key, command)
55 dict.__setitem__(self, key, command)
56
56
57 def __getitem__(self, key):
57 def __getitem__(self, key):
58 if isinstance(key, str):
58 if isinstance(key, str):
59 key = ord(key)
59 key = ord(key)
60 return dict.__getitem__(self, key)
60 return dict.__getitem__(self, key)
61
61
62 def __detitem__(self, key):
62 def __detitem__(self, key):
63 if isinstance(key, str):
63 if isinstance(key, str):
64 key = ord(key)
64 key = ord(key)
65 dict.__detitem__(self, key)
65 dict.__detitem__(self, key)
66
66
67 def register(self, command, *keys):
67 def register(self, command, *keys):
68 for key in keys:
68 for key in keys:
69 self[key] = command
69 self[key] = command
70
70
71 def get(self, key, default=None):
71 def get(self, key, default=None):
72 if isinstance(key, str):
72 if isinstance(key, str):
73 key = ord(key)
73 key = ord(key)
74 return dict.get(self, key, default)
74 return dict.get(self, key, default)
75
75
76 def findkey(self, command, default=ipipe.noitem):
76 def findkey(self, command, default=ipipe.noitem):
77 for (key, commandcandidate) in self.iteritems():
77 for (key, commandcandidate) in self.iteritems():
78 if commandcandidate == command:
78 if commandcandidate == command:
79 return key
79 return key
80 if default is ipipe.noitem:
80 if default is ipipe.noitem:
81 raise KeyError(command)
81 raise KeyError(command)
82 return default
82 return default
83
83
84
84
85 class _BrowserCachedItem(object):
85 class _BrowserCachedItem(object):
86 # This is used internally by ``ibrowse`` to store a item together with its
86 # This is used internally by ``ibrowse`` to store a item together with its
87 # marked status.
87 # marked status.
88 __slots__ = ("item", "marked")
88 __slots__ = ("item", "marked")
89
89
90 def __init__(self, item):
90 def __init__(self, item):
91 self.item = item
91 self.item = item
92 self.marked = False
92 self.marked = False
93
93
94
94
95 class _BrowserHelp(object):
95 class _BrowserHelp(object):
96 style_header = astyle.Style.fromstr("yellow:black:bold")
96 style_header = astyle.Style.fromstr("yellow:black:bold")
97 # This is used internally by ``ibrowse`` for displaying the help screen.
97 # This is used internally by ``ibrowse`` for displaying the help screen.
98 def __init__(self, browser):
98 def __init__(self, browser):
99 self.browser = browser
99 self.browser = browser
100
100
101 def __xrepr__(self, mode):
101 def __xrepr__(self, mode):
102 yield (-1, True)
102 yield (-1, True)
103 if mode == "header" or mode == "footer":
103 if mode == "header" or mode == "footer":
104 yield (astyle.style_default, "ibrowse help screen")
104 yield (astyle.style_default, "ibrowse help screen")
105 else:
105 else:
106 yield (astyle.style_default, repr(self))
106 yield (astyle.style_default, repr(self))
107
107
108 def __iter__(self):
108 def __iter__(self):
109 # Get reverse key mapping
109 # Get reverse key mapping
110 allkeys = {}
110 allkeys = {}
111 for (key, cmd) in self.browser.keymap.iteritems():
111 for (key, cmd) in self.browser.keymap.iteritems():
112 allkeys.setdefault(cmd, []).append(key)
112 allkeys.setdefault(cmd, []).append(key)
113
113
114 fields = ("key", "description")
114 fields = ("key", "description")
115
115
116 commands = []
116 commands = []
117 for name in dir(self.browser):
117 for name in dir(self.browser):
118 if name.startswith("cmd_"):
118 if name.startswith("cmd_"):
119 command = getattr(self.browser, name)
119 command = getattr(self.browser, name)
120 commands.append((inspect.getsourcelines(command)[-1], name[4:], command))
120 commands.append((inspect.getsourcelines(command)[-1], name[4:], command))
121 commands.sort()
121 commands.sort()
122 commands = [(c[1], c[2]) for c in commands]
122 commands = [(c[1], c[2]) for c in commands]
123 for (i, (name, command)) in enumerate(commands):
123 for (i, (name, command)) in enumerate(commands):
124 if i:
124 if i:
125 yield ipipe.Fields(fields, key="", description="")
125 yield ipipe.Fields(fields, key="", description="")
126
126
127 description = command.__doc__
127 description = command.__doc__
128 if description is None:
128 if description is None:
129 lines = []
129 lines = []
130 else:
130 else:
131 lines = [l.strip() for l in description.splitlines() if l.strip()]
131 lines = [l.strip() for l in description.splitlines() if l.strip()]
132 description = "\n".join(lines)
132 description = "\n".join(lines)
133 lines = textwrap.wrap(description, 60)
133 lines = textwrap.wrap(description, 60)
134 keys = allkeys.get(name, [])
134 keys = allkeys.get(name, [])
135
135
136 yield ipipe.Fields(fields, key="", description=astyle.Text((self.style_header, name)))
136 yield ipipe.Fields(fields, key="", description=astyle.Text((self.style_header, name)))
137 for i in xrange(max(len(keys), len(lines))):
137 for i in xrange(max(len(keys), len(lines))):
138 try:
138 try:
139 key = self.browser.keylabel(keys[i])
139 key = self.browser.keylabel(keys[i])
140 except IndexError:
140 except IndexError:
141 key = ""
141 key = ""
142 try:
142 try:
143 line = lines[i]
143 line = lines[i]
144 except IndexError:
144 except IndexError:
145 line = ""
145 line = ""
146 yield ipipe.Fields(fields, key=key, description=line)
146 yield ipipe.Fields(fields, key=key, description=line)
147
147
148
148
149 class _BrowserLevel(object):
149 class _BrowserLevel(object):
150 # This is used internally to store the state (iterator, fetch items,
150 # This is used internally to store the state (iterator, fetch items,
151 # position of cursor and screen, etc.) of one browser level
151 # position of cursor and screen, etc.) of one browser level
152 # An ``ibrowse`` object keeps multiple ``_BrowserLevel`` objects in
152 # An ``ibrowse`` object keeps multiple ``_BrowserLevel`` objects in
153 # a stack.
153 # a stack.
154 def __init__(self, browser, input, mainsizey, *attrs):
154 def __init__(self, browser, input, mainsizey, *attrs):
155 self.browser = browser
155 self.browser = browser
156 self.input = input
156 self.input = input
157 self.header = [x for x in ipipe.xrepr(input, "header") if not isinstance(x[0], int)]
157 self.header = [x for x in ipipe.xrepr(input, "header") if not isinstance(x[0], int)]
158 # iterator for the input
158 # iterator for the input
159 self.iterator = ipipe.xiter(input)
159 self.iterator = ipipe.xiter(input)
160
160
161 # is the iterator exhausted?
161 # is the iterator exhausted?
162 self.exhausted = False
162 self.exhausted = False
163
163
164 # attributes to be display (autodetected if empty)
164 # attributes to be display (autodetected if empty)
165 self.attrs = attrs
165 self.attrs = attrs
166
166
167 # fetched items (+ marked flag)
167 # fetched items (+ marked flag)
168 self.items = ipipe.deque()
168 self.items = ipipe.deque()
169
169
170 # Number of marked objects
170 # Number of marked objects
171 self.marked = 0
171 self.marked = 0
172
172
173 # Vertical cursor position
173 # Vertical cursor position
174 self.cury = 0
174 self.cury = 0
175
175
176 # Horizontal cursor position
176 # Horizontal cursor position
177 self.curx = 0
177 self.curx = 0
178
178
179 # Index of first data column
179 # Index of first data column
180 self.datastartx = 0
180 self.datastartx = 0
181
181
182 # Index of first data line
182 # Index of first data line
183 self.datastarty = 0
183 self.datastarty = 0
184
184
185 # height of the data display area
185 # height of the data display area
186 self.mainsizey = mainsizey
186 self.mainsizey = mainsizey
187
187
188 # width of the data display area (changes when scrolling)
188 # width of the data display area (changes when scrolling)
189 self.mainsizex = 0
189 self.mainsizex = 0
190
190
191 # Size of row number (changes when scrolling)
191 # Size of row number (changes when scrolling)
192 self.numbersizex = 0
192 self.numbersizex = 0
193
193
194 # Attributes to display (in this order)
194 # Attributes to display (in this order)
195 self.displayattrs = []
195 self.displayattrs = []
196
196
197 # index and attribute under the cursor
197 # index and attribute under the cursor
198 self.displayattr = (None, ipipe.noitem)
198 self.displayattr = (None, ipipe.noitem)
199
199
200 # Maps attributes to column widths
200 # Maps attributes to column widths
201 self.colwidths = {}
201 self.colwidths = {}
202
202
203 # Set of hidden attributes
203 # Set of hidden attributes
204 self.hiddenattrs = set()
204 self.hiddenattrs = set()
205
205
206 # This takes care of all the caches etc.
206 # This takes care of all the caches etc.
207 self.moveto(0, 0, refresh=True)
207 self.moveto(0, 0, refresh=True)
208
208
209 def fetch(self, count):
209 def fetch(self, count):
210 # Try to fill ``self.items`` with at least ``count`` objects.
210 # Try to fill ``self.items`` with at least ``count`` objects.
211 have = len(self.items)
211 have = len(self.items)
212 while not self.exhausted and have < count:
212 while not self.exhausted and have < count:
213 try:
213 try:
214 item = self.iterator.next()
214 item = self.iterator.next()
215 except StopIteration:
215 except StopIteration:
216 self.exhausted = True
216 self.exhausted = True
217 break
217 break
218 except (KeyboardInterrupt, SystemExit):
218 except (KeyboardInterrupt, SystemExit):
219 raise
219 raise
220 except Exception, exc:
220 except Exception as exc:
221 have += 1
221 have += 1
222 self.items.append(_BrowserCachedItem(exc))
222 self.items.append(_BrowserCachedItem(exc))
223 self.exhausted = True
223 self.exhausted = True
224 break
224 break
225 else:
225 else:
226 have += 1
226 have += 1
227 self.items.append(_BrowserCachedItem(item))
227 self.items.append(_BrowserCachedItem(item))
228
228
229 def calcdisplayattrs(self):
229 def calcdisplayattrs(self):
230 # Calculate which attributes are available from the objects that are
230 # Calculate which attributes are available from the objects that are
231 # currently visible on screen (and store it in ``self.displayattrs``)
231 # currently visible on screen (and store it in ``self.displayattrs``)
232
232
233 attrs = set()
233 attrs = set()
234 self.displayattrs = []
234 self.displayattrs = []
235 if self.attrs:
235 if self.attrs:
236 # If the browser object specifies a fixed list of attributes,
236 # If the browser object specifies a fixed list of attributes,
237 # simply use it (removing hidden attributes).
237 # simply use it (removing hidden attributes).
238 for attr in self.attrs:
238 for attr in self.attrs:
239 attr = ipipe.upgradexattr(attr)
239 attr = ipipe.upgradexattr(attr)
240 if attr not in attrs and attr not in self.hiddenattrs:
240 if attr not in attrs and attr not in self.hiddenattrs:
241 self.displayattrs.append(attr)
241 self.displayattrs.append(attr)
242 attrs.add(attr)
242 attrs.add(attr)
243 else:
243 else:
244 endy = min(self.datastarty+self.mainsizey, len(self.items))
244 endy = min(self.datastarty+self.mainsizey, len(self.items))
245 for i in xrange(self.datastarty, endy):
245 for i in xrange(self.datastarty, endy):
246 for attr in ipipe.xattrs(self.items[i].item, "default"):
246 for attr in ipipe.xattrs(self.items[i].item, "default"):
247 if attr not in attrs and attr not in self.hiddenattrs:
247 if attr not in attrs and attr not in self.hiddenattrs:
248 self.displayattrs.append(attr)
248 self.displayattrs.append(attr)
249 attrs.add(attr)
249 attrs.add(attr)
250
250
251 def getrow(self, i):
251 def getrow(self, i):
252 # Return a dictionary with the attributes for the object
252 # Return a dictionary with the attributes for the object
253 # ``self.items[i]``. Attribute names are taken from
253 # ``self.items[i]``. Attribute names are taken from
254 # ``self.displayattrs`` so ``calcdisplayattrs()`` must have been
254 # ``self.displayattrs`` so ``calcdisplayattrs()`` must have been
255 # called before.
255 # called before.
256 row = {}
256 row = {}
257 item = self.items[i].item
257 item = self.items[i].item
258 for attr in self.displayattrs:
258 for attr in self.displayattrs:
259 try:
259 try:
260 value = attr.value(item)
260 value = attr.value(item)
261 except (KeyboardInterrupt, SystemExit):
261 except (KeyboardInterrupt, SystemExit):
262 raise
262 raise
263 except Exception, exc:
263 except Exception as exc:
264 value = exc
264 value = exc
265 # only store attribute if it exists (or we got an exception)
265 # only store attribute if it exists (or we got an exception)
266 if value is not ipipe.noitem:
266 if value is not ipipe.noitem:
267 # remember alignment, length and colored text
267 # remember alignment, length and colored text
268 row[attr] = ipipe.xformat(value, "cell", self.browser.maxattrlength)
268 row[attr] = ipipe.xformat(value, "cell", self.browser.maxattrlength)
269 return row
269 return row
270
270
271 def calcwidths(self):
271 def calcwidths(self):
272 # Recalculate the displayed fields and their widths.
272 # Recalculate the displayed fields and their widths.
273 # ``calcdisplayattrs()'' must have been called and the cache
273 # ``calcdisplayattrs()'' must have been called and the cache
274 # for attributes of the objects on screen (``self.displayrows``)
274 # for attributes of the objects on screen (``self.displayrows``)
275 # must have been filled. This sets ``self.colwidths`` which maps
275 # must have been filled. This sets ``self.colwidths`` which maps
276 # attribute descriptors to widths.
276 # attribute descriptors to widths.
277 self.colwidths = {}
277 self.colwidths = {}
278 for row in self.displayrows:
278 for row in self.displayrows:
279 for attr in self.displayattrs:
279 for attr in self.displayattrs:
280 try:
280 try:
281 length = row[attr][1]
281 length = row[attr][1]
282 except KeyError:
282 except KeyError:
283 length = 0
283 length = 0
284 # always add attribute to colwidths, even if it doesn't exist
284 # always add attribute to colwidths, even if it doesn't exist
285 if attr not in self.colwidths:
285 if attr not in self.colwidths:
286 self.colwidths[attr] = len(attr.name())
286 self.colwidths[attr] = len(attr.name())
287 newwidth = max(self.colwidths[attr], length)
287 newwidth = max(self.colwidths[attr], length)
288 self.colwidths[attr] = newwidth
288 self.colwidths[attr] = newwidth
289
289
290 # How many characters do we need to paint the largest item number?
290 # How many characters do we need to paint the largest item number?
291 self.numbersizex = len(str(self.datastarty+self.mainsizey-1))
291 self.numbersizex = len(str(self.datastarty+self.mainsizey-1))
292 # How must space have we got to display data?
292 # How must space have we got to display data?
293 self.mainsizex = self.browser.scrsizex-self.numbersizex-3
293 self.mainsizex = self.browser.scrsizex-self.numbersizex-3
294 # width of all columns
294 # width of all columns
295 self.datasizex = sum(self.colwidths.itervalues()) + len(self.colwidths)
295 self.datasizex = sum(self.colwidths.itervalues()) + len(self.colwidths)
296
296
297 def calcdisplayattr(self):
297 def calcdisplayattr(self):
298 # Find out which attribute the cursor is on and store this
298 # Find out which attribute the cursor is on and store this
299 # information in ``self.displayattr``.
299 # information in ``self.displayattr``.
300 pos = 0
300 pos = 0
301 for (i, attr) in enumerate(self.displayattrs):
301 for (i, attr) in enumerate(self.displayattrs):
302 if pos+self.colwidths[attr] >= self.curx:
302 if pos+self.colwidths[attr] >= self.curx:
303 self.displayattr = (i, attr)
303 self.displayattr = (i, attr)
304 break
304 break
305 pos += self.colwidths[attr]+1
305 pos += self.colwidths[attr]+1
306 else:
306 else:
307 self.displayattr = (None, ipipe.noitem)
307 self.displayattr = (None, ipipe.noitem)
308
308
309 def moveto(self, x, y, refresh=False):
309 def moveto(self, x, y, refresh=False):
310 # Move the cursor to the position ``(x,y)`` (in data coordinates,
310 # Move the cursor to the position ``(x,y)`` (in data coordinates,
311 # not in screen coordinates). If ``refresh`` is true, all cached
311 # not in screen coordinates). If ``refresh`` is true, all cached
312 # values will be recalculated (e.g. because the list has been
312 # values will be recalculated (e.g. because the list has been
313 # resorted, so screen positions etc. are no longer valid).
313 # resorted, so screen positions etc. are no longer valid).
314 olddatastarty = self.datastarty
314 olddatastarty = self.datastarty
315 oldx = self.curx
315 oldx = self.curx
316 oldy = self.cury
316 oldy = self.cury
317 x = int(x+0.5)
317 x = int(x+0.5)
318 y = int(y+0.5)
318 y = int(y+0.5)
319 newx = x # remember where we wanted to move
319 newx = x # remember where we wanted to move
320 newy = y # remember where we wanted to move
320 newy = y # remember where we wanted to move
321
321
322 scrollbordery = min(self.browser.scrollbordery, self.mainsizey//2)
322 scrollbordery = min(self.browser.scrollbordery, self.mainsizey//2)
323 scrollborderx = min(self.browser.scrollborderx, self.mainsizex//2)
323 scrollborderx = min(self.browser.scrollborderx, self.mainsizex//2)
324
324
325 # Make sure that the cursor didn't leave the main area vertically
325 # Make sure that the cursor didn't leave the main area vertically
326 if y < 0:
326 if y < 0:
327 y = 0
327 y = 0
328 # try to get enough items to fill the screen
328 # try to get enough items to fill the screen
329 self.fetch(max(y+scrollbordery+1, self.mainsizey))
329 self.fetch(max(y+scrollbordery+1, self.mainsizey))
330 if y >= len(self.items):
330 if y >= len(self.items):
331 y = max(0, len(self.items)-1)
331 y = max(0, len(self.items)-1)
332
332
333 # Make sure that the cursor stays on screen vertically
333 # Make sure that the cursor stays on screen vertically
334 if y < self.datastarty+scrollbordery:
334 if y < self.datastarty+scrollbordery:
335 self.datastarty = max(0, y-scrollbordery)
335 self.datastarty = max(0, y-scrollbordery)
336 elif y >= self.datastarty+self.mainsizey-scrollbordery:
336 elif y >= self.datastarty+self.mainsizey-scrollbordery:
337 self.datastarty = max(0, min(y-self.mainsizey+scrollbordery+1,
337 self.datastarty = max(0, min(y-self.mainsizey+scrollbordery+1,
338 len(self.items)-self.mainsizey))
338 len(self.items)-self.mainsizey))
339
339
340 if refresh: # Do we need to refresh the complete display?
340 if refresh: # Do we need to refresh the complete display?
341 self.calcdisplayattrs()
341 self.calcdisplayattrs()
342 endy = min(self.datastarty+self.mainsizey, len(self.items))
342 endy = min(self.datastarty+self.mainsizey, len(self.items))
343 self.displayrows = map(self.getrow, xrange(self.datastarty, endy))
343 self.displayrows = map(self.getrow, xrange(self.datastarty, endy))
344 self.calcwidths()
344 self.calcwidths()
345 # Did we scroll vertically => update displayrows
345 # Did we scroll vertically => update displayrows
346 # and various other attributes
346 # and various other attributes
347 elif self.datastarty != olddatastarty:
347 elif self.datastarty != olddatastarty:
348 # Recalculate which attributes we have to display
348 # Recalculate which attributes we have to display
349 olddisplayattrs = self.displayattrs
349 olddisplayattrs = self.displayattrs
350 self.calcdisplayattrs()
350 self.calcdisplayattrs()
351 # If there are new attributes, recreate the cache
351 # If there are new attributes, recreate the cache
352 if self.displayattrs != olddisplayattrs:
352 if self.displayattrs != olddisplayattrs:
353 endy = min(self.datastarty+self.mainsizey, len(self.items))
353 endy = min(self.datastarty+self.mainsizey, len(self.items))
354 self.displayrows = map(self.getrow, xrange(self.datastarty, endy))
354 self.displayrows = map(self.getrow, xrange(self.datastarty, endy))
355 elif self.datastarty<olddatastarty: # we did scroll up
355 elif self.datastarty<olddatastarty: # we did scroll up
356 # drop rows from the end
356 # drop rows from the end
357 del self.displayrows[self.datastarty-olddatastarty:]
357 del self.displayrows[self.datastarty-olddatastarty:]
358 # fetch new items
358 # fetch new items
359 for i in xrange(min(olddatastarty, self.datastarty+self.mainsizey)-1,
359 for i in xrange(min(olddatastarty, self.datastarty+self.mainsizey)-1,
360 self.datastarty-1, -1):
360 self.datastarty-1, -1):
361 try:
361 try:
362 row = self.getrow(i)
362 row = self.getrow(i)
363 except IndexError:
363 except IndexError:
364 # we didn't have enough objects to fill the screen
364 # we didn't have enough objects to fill the screen
365 break
365 break
366 self.displayrows.insert(0, row)
366 self.displayrows.insert(0, row)
367 else: # we did scroll down
367 else: # we did scroll down
368 # drop rows from the start
368 # drop rows from the start
369 del self.displayrows[:self.datastarty-olddatastarty]
369 del self.displayrows[:self.datastarty-olddatastarty]
370 # fetch new items
370 # fetch new items
371 for i in xrange(max(olddatastarty+self.mainsizey, self.datastarty),
371 for i in xrange(max(olddatastarty+self.mainsizey, self.datastarty),
372 self.datastarty+self.mainsizey):
372 self.datastarty+self.mainsizey):
373 try:
373 try:
374 row = self.getrow(i)
374 row = self.getrow(i)
375 except IndexError:
375 except IndexError:
376 # we didn't have enough objects to fill the screen
376 # we didn't have enough objects to fill the screen
377 break
377 break
378 self.displayrows.append(row)
378 self.displayrows.append(row)
379 self.calcwidths()
379 self.calcwidths()
380
380
381 # Make sure that the cursor didn't leave the data area horizontally
381 # Make sure that the cursor didn't leave the data area horizontally
382 if x < 0:
382 if x < 0:
383 x = 0
383 x = 0
384 elif x >= self.datasizex:
384 elif x >= self.datasizex:
385 x = max(0, self.datasizex-1)
385 x = max(0, self.datasizex-1)
386
386
387 # Make sure that the cursor stays on screen horizontally
387 # Make sure that the cursor stays on screen horizontally
388 if x < self.datastartx+scrollborderx:
388 if x < self.datastartx+scrollborderx:
389 self.datastartx = max(0, x-scrollborderx)
389 self.datastartx = max(0, x-scrollborderx)
390 elif x >= self.datastartx+self.mainsizex-scrollborderx:
390 elif x >= self.datastartx+self.mainsizex-scrollborderx:
391 self.datastartx = max(0, min(x-self.mainsizex+scrollborderx+1,
391 self.datastartx = max(0, min(x-self.mainsizex+scrollborderx+1,
392 self.datasizex-self.mainsizex))
392 self.datasizex-self.mainsizex))
393
393
394 if x == oldx and y == oldy and (x != newx or y != newy): # couldn't move
394 if x == oldx and y == oldy and (x != newx or y != newy): # couldn't move
395 self.browser.beep()
395 self.browser.beep()
396 else:
396 else:
397 self.curx = x
397 self.curx = x
398 self.cury = y
398 self.cury = y
399 self.calcdisplayattr()
399 self.calcdisplayattr()
400
400
401 def sort(self, key, reverse=False):
401 def sort(self, key, reverse=False):
402 """
402 """
403 Sort the currently list of items using the key function ``key``. If
403 Sort the currently list of items using the key function ``key``. If
404 ``reverse`` is true the sort order is reversed.
404 ``reverse`` is true the sort order is reversed.
405 """
405 """
406 curitem = self.items[self.cury] # Remember where the cursor is now
406 curitem = self.items[self.cury] # Remember where the cursor is now
407
407
408 # Sort items
408 # Sort items
409 def realkey(item):
409 def realkey(item):
410 return key(item.item)
410 return key(item.item)
411 self.items = ipipe.deque(sorted(self.items, key=realkey, reverse=reverse))
411 self.items = ipipe.deque(sorted(self.items, key=realkey, reverse=reverse))
412
412
413 # Find out where the object under the cursor went
413 # Find out where the object under the cursor went
414 cury = self.cury
414 cury = self.cury
415 for (i, item) in enumerate(self.items):
415 for (i, item) in enumerate(self.items):
416 if item is curitem:
416 if item is curitem:
417 cury = i
417 cury = i
418 break
418 break
419
419
420 self.moveto(self.curx, cury, refresh=True)
420 self.moveto(self.curx, cury, refresh=True)
421
421
422 def refresh(self):
422 def refresh(self):
423 """
423 """
424 Restart iterating the input.
424 Restart iterating the input.
425 """
425 """
426 self.iterator = ipipe.xiter(self.input)
426 self.iterator = ipipe.xiter(self.input)
427 self.items.clear()
427 self.items.clear()
428 self.exhausted = False
428 self.exhausted = False
429 self.datastartx = self.datastarty = 0
429 self.datastartx = self.datastarty = 0
430 self.moveto(0, 0, refresh=True)
430 self.moveto(0, 0, refresh=True)
431
431
432 def refreshfind(self):
432 def refreshfind(self):
433 """
433 """
434 Restart iterating the input and go back to the same object as before
434 Restart iterating the input and go back to the same object as before
435 (if it can be found in the new iterator).
435 (if it can be found in the new iterator).
436 """
436 """
437 try:
437 try:
438 oldobject = self.items[self.cury].item
438 oldobject = self.items[self.cury].item
439 except IndexError:
439 except IndexError:
440 oldobject = ipipe.noitem
440 oldobject = ipipe.noitem
441 self.iterator = ipipe.xiter(self.input)
441 self.iterator = ipipe.xiter(self.input)
442 self.items.clear()
442 self.items.clear()
443 self.exhausted = False
443 self.exhausted = False
444 while True:
444 while True:
445 self.fetch(len(self.items)+1)
445 self.fetch(len(self.items)+1)
446 if self.exhausted:
446 if self.exhausted:
447 curses.beep()
447 curses.beep()
448 self.datastartx = self.datastarty = 0
448 self.datastartx = self.datastarty = 0
449 self.moveto(self.curx, 0, refresh=True)
449 self.moveto(self.curx, 0, refresh=True)
450 break
450 break
451 if self.items[-1].item == oldobject:
451 if self.items[-1].item == oldobject:
452 self.datastartx = self.datastarty = 0
452 self.datastartx = self.datastarty = 0
453 self.moveto(self.curx, len(self.items)-1, refresh=True)
453 self.moveto(self.curx, len(self.items)-1, refresh=True)
454 break
454 break
455
455
456
456
457 class _CommandInput(object):
457 class _CommandInput(object):
458 keymap = Keymap()
458 keymap = Keymap()
459 keymap.register("left", curses.KEY_LEFT)
459 keymap.register("left", curses.KEY_LEFT)
460 keymap.register("right", curses.KEY_RIGHT)
460 keymap.register("right", curses.KEY_RIGHT)
461 keymap.register("home", curses.KEY_HOME, "\x01") # Ctrl-A
461 keymap.register("home", curses.KEY_HOME, "\x01") # Ctrl-A
462 keymap.register("end", curses.KEY_END, "\x05") # Ctrl-E
462 keymap.register("end", curses.KEY_END, "\x05") # Ctrl-E
463 # FIXME: What's happening here?
463 # FIXME: What's happening here?
464 keymap.register("backspace", curses.KEY_BACKSPACE, "\x08\x7f")
464 keymap.register("backspace", curses.KEY_BACKSPACE, "\x08\x7f")
465 keymap.register("delete", curses.KEY_DC)
465 keymap.register("delete", curses.KEY_DC)
466 keymap.register("delend", 0x0b) # Ctrl-K
466 keymap.register("delend", 0x0b) # Ctrl-K
467 keymap.register("execute", "\r\n")
467 keymap.register("execute", "\r\n")
468 keymap.register("up", curses.KEY_UP)
468 keymap.register("up", curses.KEY_UP)
469 keymap.register("down", curses.KEY_DOWN)
469 keymap.register("down", curses.KEY_DOWN)
470 keymap.register("incsearchup", curses.KEY_PPAGE)
470 keymap.register("incsearchup", curses.KEY_PPAGE)
471 keymap.register("incsearchdown", curses.KEY_NPAGE)
471 keymap.register("incsearchdown", curses.KEY_NPAGE)
472 keymap.register("exit", "\x18"), # Ctrl-X
472 keymap.register("exit", "\x18"), # Ctrl-X
473
473
474 def __init__(self, prompt):
474 def __init__(self, prompt):
475 self.prompt = prompt
475 self.prompt = prompt
476 self.history = []
476 self.history = []
477 self.maxhistory = 100
477 self.maxhistory = 100
478 self.input = ""
478 self.input = ""
479 self.curx = 0
479 self.curx = 0
480 self.cury = -1 # blank line
480 self.cury = -1 # blank line
481
481
482 def start(self):
482 def start(self):
483 self.input = ""
483 self.input = ""
484 self.curx = 0
484 self.curx = 0
485 self.cury = -1 # blank line
485 self.cury = -1 # blank line
486
486
487 def handlekey(self, browser, key):
487 def handlekey(self, browser, key):
488 cmdname = self.keymap.get(key, None)
488 cmdname = self.keymap.get(key, None)
489 if cmdname is not None:
489 if cmdname is not None:
490 cmdfunc = getattr(self, "cmd_%s" % cmdname, None)
490 cmdfunc = getattr(self, "cmd_%s" % cmdname, None)
491 if cmdfunc is not None:
491 if cmdfunc is not None:
492 return cmdfunc(browser)
492 return cmdfunc(browser)
493 curses.beep()
493 curses.beep()
494 elif key != -1:
494 elif key != -1:
495 try:
495 try:
496 char = chr(key)
496 char = chr(key)
497 except ValueError:
497 except ValueError:
498 curses.beep()
498 curses.beep()
499 else:
499 else:
500 return self.handlechar(browser, char)
500 return self.handlechar(browser, char)
501
501
502 def handlechar(self, browser, char):
502 def handlechar(self, browser, char):
503 self.input = self.input[:self.curx] + char + self.input[self.curx:]
503 self.input = self.input[:self.curx] + char + self.input[self.curx:]
504 self.curx += 1
504 self.curx += 1
505 return True
505 return True
506
506
507 def dohistory(self):
507 def dohistory(self):
508 self.history.insert(0, self.input)
508 self.history.insert(0, self.input)
509 del self.history[:-self.maxhistory]
509 del self.history[:-self.maxhistory]
510
510
511 def cmd_backspace(self, browser):
511 def cmd_backspace(self, browser):
512 if self.curx:
512 if self.curx:
513 self.input = self.input[:self.curx-1] + self.input[self.curx:]
513 self.input = self.input[:self.curx-1] + self.input[self.curx:]
514 self.curx -= 1
514 self.curx -= 1
515 return True
515 return True
516 else:
516 else:
517 curses.beep()
517 curses.beep()
518
518
519 def cmd_delete(self, browser):
519 def cmd_delete(self, browser):
520 if self.curx<len(self.input):
520 if self.curx<len(self.input):
521 self.input = self.input[:self.curx] + self.input[self.curx+1:]
521 self.input = self.input[:self.curx] + self.input[self.curx+1:]
522 return True
522 return True
523 else:
523 else:
524 curses.beep()
524 curses.beep()
525
525
526 def cmd_delend(self, browser):
526 def cmd_delend(self, browser):
527 if self.curx<len(self.input):
527 if self.curx<len(self.input):
528 self.input = self.input[:self.curx]
528 self.input = self.input[:self.curx]
529 return True
529 return True
530
530
531 def cmd_left(self, browser):
531 def cmd_left(self, browser):
532 if self.curx:
532 if self.curx:
533 self.curx -= 1
533 self.curx -= 1
534 return True
534 return True
535 else:
535 else:
536 curses.beep()
536 curses.beep()
537
537
538 def cmd_right(self, browser):
538 def cmd_right(self, browser):
539 if self.curx < len(self.input):
539 if self.curx < len(self.input):
540 self.curx += 1
540 self.curx += 1
541 return True
541 return True
542 else:
542 else:
543 curses.beep()
543 curses.beep()
544
544
545 def cmd_home(self, browser):
545 def cmd_home(self, browser):
546 if self.curx:
546 if self.curx:
547 self.curx = 0
547 self.curx = 0
548 return True
548 return True
549 else:
549 else:
550 curses.beep()
550 curses.beep()
551
551
552 def cmd_end(self, browser):
552 def cmd_end(self, browser):
553 if self.curx < len(self.input):
553 if self.curx < len(self.input):
554 self.curx = len(self.input)
554 self.curx = len(self.input)
555 return True
555 return True
556 else:
556 else:
557 curses.beep()
557 curses.beep()
558
558
559 def cmd_up(self, browser):
559 def cmd_up(self, browser):
560 if self.cury < len(self.history)-1:
560 if self.cury < len(self.history)-1:
561 self.cury += 1
561 self.cury += 1
562 self.input = self.history[self.cury]
562 self.input = self.history[self.cury]
563 self.curx = len(self.input)
563 self.curx = len(self.input)
564 return True
564 return True
565 else:
565 else:
566 curses.beep()
566 curses.beep()
567
567
568 def cmd_down(self, browser):
568 def cmd_down(self, browser):
569 if self.cury >= 0:
569 if self.cury >= 0:
570 self.cury -= 1
570 self.cury -= 1
571 if self.cury>=0:
571 if self.cury>=0:
572 self.input = self.history[self.cury]
572 self.input = self.history[self.cury]
573 else:
573 else:
574 self.input = ""
574 self.input = ""
575 self.curx = len(self.input)
575 self.curx = len(self.input)
576 return True
576 return True
577 else:
577 else:
578 curses.beep()
578 curses.beep()
579
579
580 def cmd_incsearchup(self, browser):
580 def cmd_incsearchup(self, browser):
581 prefix = self.input[:self.curx]
581 prefix = self.input[:self.curx]
582 cury = self.cury
582 cury = self.cury
583 while True:
583 while True:
584 cury += 1
584 cury += 1
585 if cury >= len(self.history):
585 if cury >= len(self.history):
586 break
586 break
587 if self.history[cury].startswith(prefix):
587 if self.history[cury].startswith(prefix):
588 self.input = self.history[cury]
588 self.input = self.history[cury]
589 self.cury = cury
589 self.cury = cury
590 return True
590 return True
591 curses.beep()
591 curses.beep()
592
592
593 def cmd_incsearchdown(self, browser):
593 def cmd_incsearchdown(self, browser):
594 prefix = self.input[:self.curx]
594 prefix = self.input[:self.curx]
595 cury = self.cury
595 cury = self.cury
596 while True:
596 while True:
597 cury -= 1
597 cury -= 1
598 if cury <= 0:
598 if cury <= 0:
599 break
599 break
600 if self.history[cury].startswith(prefix):
600 if self.history[cury].startswith(prefix):
601 self.input = self.history[self.cury]
601 self.input = self.history[self.cury]
602 self.cury = cury
602 self.cury = cury
603 return True
603 return True
604 curses.beep()
604 curses.beep()
605
605
606 def cmd_exit(self, browser):
606 def cmd_exit(self, browser):
607 browser.mode = "default"
607 browser.mode = "default"
608 return True
608 return True
609
609
610 def cmd_execute(self, browser):
610 def cmd_execute(self, browser):
611 raise NotImplementedError
611 raise NotImplementedError
612
612
613
613
614 class _CommandGoto(_CommandInput):
614 class _CommandGoto(_CommandInput):
615 def __init__(self):
615 def __init__(self):
616 _CommandInput.__init__(self, "goto object #")
616 _CommandInput.__init__(self, "goto object #")
617
617
618 def handlechar(self, browser, char):
618 def handlechar(self, browser, char):
619 # Only accept digits
619 # Only accept digits
620 if not "0" <= char <= "9":
620 if not "0" <= char <= "9":
621 curses.beep()
621 curses.beep()
622 else:
622 else:
623 return _CommandInput.handlechar(self, browser, char)
623 return _CommandInput.handlechar(self, browser, char)
624
624
625 def cmd_execute(self, browser):
625 def cmd_execute(self, browser):
626 level = browser.levels[-1]
626 level = browser.levels[-1]
627 if self.input:
627 if self.input:
628 self.dohistory()
628 self.dohistory()
629 level.moveto(level.curx, int(self.input))
629 level.moveto(level.curx, int(self.input))
630 browser.mode = "default"
630 browser.mode = "default"
631 return True
631 return True
632
632
633
633
634 class _CommandFind(_CommandInput):
634 class _CommandFind(_CommandInput):
635 def __init__(self):
635 def __init__(self):
636 _CommandInput.__init__(self, "find expression")
636 _CommandInput.__init__(self, "find expression")
637
637
638 def cmd_execute(self, browser):
638 def cmd_execute(self, browser):
639 level = browser.levels[-1]
639 level = browser.levels[-1]
640 if self.input:
640 if self.input:
641 self.dohistory()
641 self.dohistory()
642 while True:
642 while True:
643 cury = level.cury
643 cury = level.cury
644 level.moveto(level.curx, cury+1)
644 level.moveto(level.curx, cury+1)
645 if cury == level.cury:
645 if cury == level.cury:
646 curses.beep()
646 curses.beep()
647 break # hit end
647 break # hit end
648 item = level.items[level.cury].item
648 item = level.items[level.cury].item
649 try:
649 try:
650 globals = ipipe.getglobals(None)
650 globals = ipipe.getglobals(None)
651 if eval(self.input, globals, ipipe.AttrNamespace(item)):
651 if eval(self.input, globals, ipipe.AttrNamespace(item)):
652 break # found something
652 break # found something
653 except (KeyboardInterrupt, SystemExit):
653 except (KeyboardInterrupt, SystemExit):
654 raise
654 raise
655 except Exception, exc:
655 except Exception as exc:
656 browser.report(exc)
656 browser.report(exc)
657 curses.beep()
657 curses.beep()
658 break # break on error
658 break # break on error
659 browser.mode = "default"
659 browser.mode = "default"
660 return True
660 return True
661
661
662
662
663 class _CommandFindBackwards(_CommandInput):
663 class _CommandFindBackwards(_CommandInput):
664 def __init__(self):
664 def __init__(self):
665 _CommandInput.__init__(self, "find backwards expression")
665 _CommandInput.__init__(self, "find backwards expression")
666
666
667 def cmd_execute(self, browser):
667 def cmd_execute(self, browser):
668 level = browser.levels[-1]
668 level = browser.levels[-1]
669 if self.input:
669 if self.input:
670 self.dohistory()
670 self.dohistory()
671 while level.cury:
671 while level.cury:
672 level.moveto(level.curx, level.cury-1)
672 level.moveto(level.curx, level.cury-1)
673 item = level.items[level.cury].item
673 item = level.items[level.cury].item
674 try:
674 try:
675 globals = ipipe.getglobals(None)
675 globals = ipipe.getglobals(None)
676 if eval(self.input, globals, ipipe.AttrNamespace(item)):
676 if eval(self.input, globals, ipipe.AttrNamespace(item)):
677 break # found something
677 break # found something
678 except (KeyboardInterrupt, SystemExit):
678 except (KeyboardInterrupt, SystemExit):
679 raise
679 raise
680 except Exception, exc:
680 except Exception as exc:
681 browser.report(exc)
681 browser.report(exc)
682 curses.beep()
682 curses.beep()
683 break # break on error
683 break # break on error
684 else:
684 else:
685 curses.beep()
685 curses.beep()
686 browser.mode = "default"
686 browser.mode = "default"
687 return True
687 return True
688
688
689
689
690 class ibrowse(ipipe.Display):
690 class ibrowse(ipipe.Display):
691 # Show this many lines from the previous screen when paging horizontally
691 # Show this many lines from the previous screen when paging horizontally
692 pageoverlapx = 1
692 pageoverlapx = 1
693
693
694 # Show this many lines from the previous screen when paging vertically
694 # Show this many lines from the previous screen when paging vertically
695 pageoverlapy = 1
695 pageoverlapy = 1
696
696
697 # Start scrolling when the cursor is less than this number of columns
697 # Start scrolling when the cursor is less than this number of columns
698 # away from the left or right screen edge
698 # away from the left or right screen edge
699 scrollborderx = 10
699 scrollborderx = 10
700
700
701 # Start scrolling when the cursor is less than this number of lines
701 # Start scrolling when the cursor is less than this number of lines
702 # away from the top or bottom screen edge
702 # away from the top or bottom screen edge
703 scrollbordery = 5
703 scrollbordery = 5
704
704
705 # Accelerate by this factor when scrolling horizontally
705 # Accelerate by this factor when scrolling horizontally
706 acceleratex = 1.05
706 acceleratex = 1.05
707
707
708 # Accelerate by this factor when scrolling vertically
708 # Accelerate by this factor when scrolling vertically
709 acceleratey = 1.05
709 acceleratey = 1.05
710
710
711 # The maximum horizontal scroll speed
711 # The maximum horizontal scroll speed
712 # (as a factor of the screen width (i.e. 0.5 == half a screen width)
712 # (as a factor of the screen width (i.e. 0.5 == half a screen width)
713 maxspeedx = 0.5
713 maxspeedx = 0.5
714
714
715 # The maximum vertical scroll speed
715 # The maximum vertical scroll speed
716 # (as a factor of the screen height (i.e. 0.5 == half a screen height)
716 # (as a factor of the screen height (i.e. 0.5 == half a screen height)
717 maxspeedy = 0.5
717 maxspeedy = 0.5
718
718
719 # The maximum number of header lines for browser level
719 # The maximum number of header lines for browser level
720 # if the nesting is deeper, only the innermost levels are displayed
720 # if the nesting is deeper, only the innermost levels are displayed
721 maxheaders = 5
721 maxheaders = 5
722
722
723 # The approximate maximum length of a column entry
723 # The approximate maximum length of a column entry
724 maxattrlength = 200
724 maxattrlength = 200
725
725
726 # Styles for various parts of the GUI
726 # Styles for various parts of the GUI
727 style_objheadertext = astyle.Style.fromstr("white:black:bold|reverse")
727 style_objheadertext = astyle.Style.fromstr("white:black:bold|reverse")
728 style_objheadernumber = astyle.Style.fromstr("white:blue:bold|reverse")
728 style_objheadernumber = astyle.Style.fromstr("white:blue:bold|reverse")
729 style_objheaderobject = astyle.Style.fromstr("white:black:reverse")
729 style_objheaderobject = astyle.Style.fromstr("white:black:reverse")
730 style_colheader = astyle.Style.fromstr("blue:white:reverse")
730 style_colheader = astyle.Style.fromstr("blue:white:reverse")
731 style_colheaderhere = astyle.Style.fromstr("green:black:bold|reverse")
731 style_colheaderhere = astyle.Style.fromstr("green:black:bold|reverse")
732 style_colheadersep = astyle.Style.fromstr("blue:black:reverse")
732 style_colheadersep = astyle.Style.fromstr("blue:black:reverse")
733 style_number = astyle.Style.fromstr("blue:white:reverse")
733 style_number = astyle.Style.fromstr("blue:white:reverse")
734 style_numberhere = astyle.Style.fromstr("green:black:bold|reverse")
734 style_numberhere = astyle.Style.fromstr("green:black:bold|reverse")
735 style_sep = astyle.Style.fromstr("blue:black")
735 style_sep = astyle.Style.fromstr("blue:black")
736 style_data = astyle.Style.fromstr("white:black")
736 style_data = astyle.Style.fromstr("white:black")
737 style_datapad = astyle.Style.fromstr("blue:black:bold")
737 style_datapad = astyle.Style.fromstr("blue:black:bold")
738 style_footer = astyle.Style.fromstr("black:white")
738 style_footer = astyle.Style.fromstr("black:white")
739 style_report = astyle.Style.fromstr("white:black")
739 style_report = astyle.Style.fromstr("white:black")
740
740
741 # Column separator in header
741 # Column separator in header
742 headersepchar = "|"
742 headersepchar = "|"
743
743
744 # Character for padding data cell entries
744 # Character for padding data cell entries
745 datapadchar = "."
745 datapadchar = "."
746
746
747 # Column separator in data area
747 # Column separator in data area
748 datasepchar = "|"
748 datasepchar = "|"
749
749
750 # Character to use for "empty" cell (i.e. for non-existing attributes)
750 # Character to use for "empty" cell (i.e. for non-existing attributes)
751 nodatachar = "-"
751 nodatachar = "-"
752
752
753 # Prompts for modes that require keyboard input
753 # Prompts for modes that require keyboard input
754 prompts = {
754 prompts = {
755 "goto": _CommandGoto(),
755 "goto": _CommandGoto(),
756 "find": _CommandFind(),
756 "find": _CommandFind(),
757 "findbackwards": _CommandFindBackwards()
757 "findbackwards": _CommandFindBackwards()
758 }
758 }
759
759
760 # Maps curses key codes to "function" names
760 # Maps curses key codes to "function" names
761 keymap = Keymap()
761 keymap = Keymap()
762 keymap.register("quit", "q")
762 keymap.register("quit", "q")
763 keymap.register("up", curses.KEY_UP)
763 keymap.register("up", curses.KEY_UP)
764 keymap.register("down", curses.KEY_DOWN)
764 keymap.register("down", curses.KEY_DOWN)
765 keymap.register("pageup", curses.KEY_PPAGE)
765 keymap.register("pageup", curses.KEY_PPAGE)
766 keymap.register("pagedown", curses.KEY_NPAGE)
766 keymap.register("pagedown", curses.KEY_NPAGE)
767 keymap.register("left", curses.KEY_LEFT)
767 keymap.register("left", curses.KEY_LEFT)
768 keymap.register("right", curses.KEY_RIGHT)
768 keymap.register("right", curses.KEY_RIGHT)
769 keymap.register("home", curses.KEY_HOME, "\x01")
769 keymap.register("home", curses.KEY_HOME, "\x01")
770 keymap.register("end", curses.KEY_END, "\x05")
770 keymap.register("end", curses.KEY_END, "\x05")
771 keymap.register("prevattr", "<\x1b")
771 keymap.register("prevattr", "<\x1b")
772 keymap.register("nextattr", ">\t")
772 keymap.register("nextattr", ">\t")
773 keymap.register("pick", "p")
773 keymap.register("pick", "p")
774 keymap.register("pickattr", "P")
774 keymap.register("pickattr", "P")
775 keymap.register("pickallattrs", "C")
775 keymap.register("pickallattrs", "C")
776 keymap.register("pickmarked", "m")
776 keymap.register("pickmarked", "m")
777 keymap.register("pickmarkedattr", "M")
777 keymap.register("pickmarkedattr", "M")
778 keymap.register("pickinput", "i")
778 keymap.register("pickinput", "i")
779 keymap.register("pickinputattr", "I")
779 keymap.register("pickinputattr", "I")
780 keymap.register("hideattr", "h")
780 keymap.register("hideattr", "h")
781 keymap.register("unhideattrs", "H")
781 keymap.register("unhideattrs", "H")
782 keymap.register("help", "?")
782 keymap.register("help", "?")
783 keymap.register("enter", "\r\n")
783 keymap.register("enter", "\r\n")
784 keymap.register("enterattr", "E")
784 keymap.register("enterattr", "E")
785 # FIXME: What's happening here?
785 # FIXME: What's happening here?
786 keymap.register("leave", curses.KEY_BACKSPACE, "x\x08\x7f")
786 keymap.register("leave", curses.KEY_BACKSPACE, "x\x08\x7f")
787 keymap.register("detail", "d")
787 keymap.register("detail", "d")
788 keymap.register("detailattr", "D")
788 keymap.register("detailattr", "D")
789 keymap.register("tooglemark", " ")
789 keymap.register("tooglemark", " ")
790 keymap.register("markrange", "%")
790 keymap.register("markrange", "%")
791 keymap.register("sortattrasc", "v")
791 keymap.register("sortattrasc", "v")
792 keymap.register("sortattrdesc", "V")
792 keymap.register("sortattrdesc", "V")
793 keymap.register("goto", "g")
793 keymap.register("goto", "g")
794 keymap.register("find", "f")
794 keymap.register("find", "f")
795 keymap.register("findbackwards", "b")
795 keymap.register("findbackwards", "b")
796 keymap.register("refresh", "r")
796 keymap.register("refresh", "r")
797 keymap.register("refreshfind", "R")
797 keymap.register("refreshfind", "R")
798
798
799 def __init__(self, input=None, *attrs):
799 def __init__(self, input=None, *attrs):
800 """
800 """
801 Create a new browser. If ``attrs`` is not empty, it is the list
801 Create a new browser. If ``attrs`` is not empty, it is the list
802 of attributes that will be displayed in the browser, otherwise
802 of attributes that will be displayed in the browser, otherwise
803 these will be determined by the objects on screen.
803 these will be determined by the objects on screen.
804 """
804 """
805 ipipe.Display.__init__(self, input)
805 ipipe.Display.__init__(self, input)
806
806
807 self.attrs = attrs
807 self.attrs = attrs
808
808
809 # Stack of browser levels
809 # Stack of browser levels
810 self.levels = []
810 self.levels = []
811 # how many colums to scroll (Changes when accelerating)
811 # how many colums to scroll (Changes when accelerating)
812 self.stepx = 1.
812 self.stepx = 1.
813
813
814 # how many rows to scroll (Changes when accelerating)
814 # how many rows to scroll (Changes when accelerating)
815 self.stepy = 1.
815 self.stepy = 1.
816
816
817 # Beep on the edges of the data area? (Will be set to ``False``
817 # Beep on the edges of the data area? (Will be set to ``False``
818 # once the cursor hits the edge of the screen, so we don't get
818 # once the cursor hits the edge of the screen, so we don't get
819 # multiple beeps).
819 # multiple beeps).
820 self._dobeep = True
820 self._dobeep = True
821
821
822 # Cache for registered ``curses`` colors and styles.
822 # Cache for registered ``curses`` colors and styles.
823 self._styles = {}
823 self._styles = {}
824 self._colors = {}
824 self._colors = {}
825 self._maxcolor = 1
825 self._maxcolor = 1
826
826
827 # How many header lines do we want to paint (the numbers of levels
827 # How many header lines do we want to paint (the numbers of levels
828 # we have, but with an upper bound)
828 # we have, but with an upper bound)
829 self._headerlines = 1
829 self._headerlines = 1
830
830
831 # Index of first header line
831 # Index of first header line
832 self._firstheaderline = 0
832 self._firstheaderline = 0
833
833
834 # curses window
834 # curses window
835 self.scr = None
835 self.scr = None
836 # report in the footer line (error, executed command etc.)
836 # report in the footer line (error, executed command etc.)
837 self._report = None
837 self._report = None
838
838
839 # value to be returned to the caller (set by commands)
839 # value to be returned to the caller (set by commands)
840 self.returnvalue = None
840 self.returnvalue = None
841
841
842 # The mode the browser is in
842 # The mode the browser is in
843 # e.g. normal browsing or entering an argument for a command
843 # e.g. normal browsing or entering an argument for a command
844 self.mode = "default"
844 self.mode = "default"
845
845
846 # set by the SIGWINCH signal handler
846 # set by the SIGWINCH signal handler
847 self.resized = False
847 self.resized = False
848
848
849 def nextstepx(self, step):
849 def nextstepx(self, step):
850 """
850 """
851 Accelerate horizontally.
851 Accelerate horizontally.
852 """
852 """
853 return max(1., min(step*self.acceleratex,
853 return max(1., min(step*self.acceleratex,
854 self.maxspeedx*self.levels[-1].mainsizex))
854 self.maxspeedx*self.levels[-1].mainsizex))
855
855
856 def nextstepy(self, step):
856 def nextstepy(self, step):
857 """
857 """
858 Accelerate vertically.
858 Accelerate vertically.
859 """
859 """
860 return max(1., min(step*self.acceleratey,
860 return max(1., min(step*self.acceleratey,
861 self.maxspeedy*self.levels[-1].mainsizey))
861 self.maxspeedy*self.levels[-1].mainsizey))
862
862
863 def getstyle(self, style):
863 def getstyle(self, style):
864 """
864 """
865 Register the ``style`` with ``curses`` or get it from the cache,
865 Register the ``style`` with ``curses`` or get it from the cache,
866 if it has been registered before.
866 if it has been registered before.
867 """
867 """
868 try:
868 try:
869 return self._styles[style.fg, style.bg, style.attrs]
869 return self._styles[style.fg, style.bg, style.attrs]
870 except KeyError:
870 except KeyError:
871 attrs = 0
871 attrs = 0
872 for b in astyle.A2CURSES:
872 for b in astyle.A2CURSES:
873 if style.attrs & b:
873 if style.attrs & b:
874 attrs |= astyle.A2CURSES[b]
874 attrs |= astyle.A2CURSES[b]
875 try:
875 try:
876 color = self._colors[style.fg, style.bg]
876 color = self._colors[style.fg, style.bg]
877 except KeyError:
877 except KeyError:
878 curses.init_pair(
878 curses.init_pair(
879 self._maxcolor,
879 self._maxcolor,
880 astyle.COLOR2CURSES[style.fg],
880 astyle.COLOR2CURSES[style.fg],
881 astyle.COLOR2CURSES[style.bg]
881 astyle.COLOR2CURSES[style.bg]
882 )
882 )
883 color = curses.color_pair(self._maxcolor)
883 color = curses.color_pair(self._maxcolor)
884 self._colors[style.fg, style.bg] = color
884 self._colors[style.fg, style.bg] = color
885 self._maxcolor += 1
885 self._maxcolor += 1
886 c = color | attrs
886 c = color | attrs
887 self._styles[style.fg, style.bg, style.attrs] = c
887 self._styles[style.fg, style.bg, style.attrs] = c
888 return c
888 return c
889
889
890 def addstr(self, y, x, begx, endx, text, style):
890 def addstr(self, y, x, begx, endx, text, style):
891 """
891 """
892 A version of ``curses.addstr()`` that can handle ``x`` coordinates
892 A version of ``curses.addstr()`` that can handle ``x`` coordinates
893 that are outside the screen.
893 that are outside the screen.
894 """
894 """
895 text2 = text[max(0, begx-x):max(0, endx-x)]
895 text2 = text[max(0, begx-x):max(0, endx-x)]
896 if text2:
896 if text2:
897 self.scr.addstr(y, max(x, begx), text2, self.getstyle(style))
897 self.scr.addstr(y, max(x, begx), text2, self.getstyle(style))
898 return len(text)
898 return len(text)
899
899
900 def addchr(self, y, x, begx, endx, c, l, style):
900 def addchr(self, y, x, begx, endx, c, l, style):
901 x0 = max(x, begx)
901 x0 = max(x, begx)
902 x1 = min(x+l, endx)
902 x1 = min(x+l, endx)
903 if x1>x0:
903 if x1>x0:
904 self.scr.addstr(y, x0, c*(x1-x0), self.getstyle(style))
904 self.scr.addstr(y, x0, c*(x1-x0), self.getstyle(style))
905 return l
905 return l
906
906
907 def _calcheaderlines(self, levels):
907 def _calcheaderlines(self, levels):
908 # Calculate how many headerlines do we have to display, if we have
908 # Calculate how many headerlines do we have to display, if we have
909 # ``levels`` browser levels
909 # ``levels`` browser levels
910 if levels is None:
910 if levels is None:
911 levels = len(self.levels)
911 levels = len(self.levels)
912 self._headerlines = min(self.maxheaders, levels)
912 self._headerlines = min(self.maxheaders, levels)
913 self._firstheaderline = levels-self._headerlines
913 self._firstheaderline = levels-self._headerlines
914
914
915 def getstylehere(self, style):
915 def getstylehere(self, style):
916 """
916 """
917 Return a style for displaying the original style ``style``
917 Return a style for displaying the original style ``style``
918 in the row the cursor is on.
918 in the row the cursor is on.
919 """
919 """
920 return astyle.Style(style.fg, astyle.COLOR_BLUE, style.attrs | astyle.A_BOLD)
920 return astyle.Style(style.fg, astyle.COLOR_BLUE, style.attrs | astyle.A_BOLD)
921
921
922 def report(self, msg):
922 def report(self, msg):
923 """
923 """
924 Store the message ``msg`` for display below the footer line. This
924 Store the message ``msg`` for display below the footer line. This
925 will be displayed as soon as the screen is redrawn.
925 will be displayed as soon as the screen is redrawn.
926 """
926 """
927 self._report = msg
927 self._report = msg
928
928
929 def enter(self, item, *attrs):
929 def enter(self, item, *attrs):
930 """
930 """
931 Enter the object ``item``. If ``attrs`` is specified, it will be used
931 Enter the object ``item``. If ``attrs`` is specified, it will be used
932 as a fixed list of attributes to display.
932 as a fixed list of attributes to display.
933 """
933 """
934 if self.levels and item is self.levels[-1].input:
934 if self.levels and item is self.levels[-1].input:
935 curses.beep()
935 curses.beep()
936 self.report(CommandError("Recursion on input object"))
936 self.report(CommandError("Recursion on input object"))
937 else:
937 else:
938 oldlevels = len(self.levels)
938 oldlevels = len(self.levels)
939 self._calcheaderlines(oldlevels+1)
939 self._calcheaderlines(oldlevels+1)
940 try:
940 try:
941 level = _BrowserLevel(
941 level = _BrowserLevel(
942 self,
942 self,
943 item,
943 item,
944 self.scrsizey-1-self._headerlines-2,
944 self.scrsizey-1-self._headerlines-2,
945 *attrs
945 *attrs
946 )
946 )
947 except (KeyboardInterrupt, SystemExit):
947 except (KeyboardInterrupt, SystemExit):
948 raise
948 raise
949 except Exception, exc:
949 except Exception as exc:
950 if not self.levels:
950 if not self.levels:
951 raise
951 raise
952 self._calcheaderlines(oldlevels)
952 self._calcheaderlines(oldlevels)
953 curses.beep()
953 curses.beep()
954 self.report(exc)
954 self.report(exc)
955 else:
955 else:
956 self.levels.append(level)
956 self.levels.append(level)
957
957
958 def startkeyboardinput(self, mode):
958 def startkeyboardinput(self, mode):
959 """
959 """
960 Enter mode ``mode``, which requires keyboard input.
960 Enter mode ``mode``, which requires keyboard input.
961 """
961 """
962 self.mode = mode
962 self.mode = mode
963 self.prompts[mode].start()
963 self.prompts[mode].start()
964
964
965 def keylabel(self, keycode):
965 def keylabel(self, keycode):
966 """
966 """
967 Return a pretty name for the ``curses`` key ``keycode`` (used in the
967 Return a pretty name for the ``curses`` key ``keycode`` (used in the
968 help screen and in reports about unassigned keys).
968 help screen and in reports about unassigned keys).
969 """
969 """
970 if keycode <= 0xff:
970 if keycode <= 0xff:
971 specialsnames = {
971 specialsnames = {
972 ord("\n"): "RETURN",
972 ord("\n"): "RETURN",
973 ord(" "): "SPACE",
973 ord(" "): "SPACE",
974 ord("\t"): "TAB",
974 ord("\t"): "TAB",
975 ord("\x7f"): "DELETE",
975 ord("\x7f"): "DELETE",
976 ord("\x08"): "BACKSPACE",
976 ord("\x08"): "BACKSPACE",
977 }
977 }
978 if keycode in specialsnames:
978 if keycode in specialsnames:
979 return specialsnames[keycode]
979 return specialsnames[keycode]
980 elif 0x00 < keycode < 0x20:
980 elif 0x00 < keycode < 0x20:
981 return "CTRL-%s" % chr(keycode + 64)
981 return "CTRL-%s" % chr(keycode + 64)
982 return repr(chr(keycode))
982 return repr(chr(keycode))
983 for name in dir(curses):
983 for name in dir(curses):
984 if name.startswith("KEY_") and getattr(curses, name) == keycode:
984 if name.startswith("KEY_") and getattr(curses, name) == keycode:
985 return name
985 return name
986 return str(keycode)
986 return str(keycode)
987
987
988 def beep(self, force=False):
988 def beep(self, force=False):
989 if force or self._dobeep:
989 if force or self._dobeep:
990 curses.beep()
990 curses.beep()
991 # don't beep again (as long as the same key is pressed)
991 # don't beep again (as long as the same key is pressed)
992 self._dobeep = False
992 self._dobeep = False
993
993
994 def cmd_up(self):
994 def cmd_up(self):
995 """
995 """
996 Move the cursor to the previous row.
996 Move the cursor to the previous row.
997 """
997 """
998 level = self.levels[-1]
998 level = self.levels[-1]
999 self.report("up")
999 self.report("up")
1000 level.moveto(level.curx, level.cury-self.stepy)
1000 level.moveto(level.curx, level.cury-self.stepy)
1001
1001
1002 def cmd_down(self):
1002 def cmd_down(self):
1003 """
1003 """
1004 Move the cursor to the next row.
1004 Move the cursor to the next row.
1005 """
1005 """
1006 level = self.levels[-1]
1006 level = self.levels[-1]
1007 self.report("down")
1007 self.report("down")
1008 level.moveto(level.curx, level.cury+self.stepy)
1008 level.moveto(level.curx, level.cury+self.stepy)
1009
1009
1010 def cmd_pageup(self):
1010 def cmd_pageup(self):
1011 """
1011 """
1012 Move the cursor up one page.
1012 Move the cursor up one page.
1013 """
1013 """
1014 level = self.levels[-1]
1014 level = self.levels[-1]
1015 self.report("page up")
1015 self.report("page up")
1016 level.moveto(level.curx, level.cury-level.mainsizey+self.pageoverlapy)
1016 level.moveto(level.curx, level.cury-level.mainsizey+self.pageoverlapy)
1017
1017
1018 def cmd_pagedown(self):
1018 def cmd_pagedown(self):
1019 """
1019 """
1020 Move the cursor down one page.
1020 Move the cursor down one page.
1021 """
1021 """
1022 level = self.levels[-1]
1022 level = self.levels[-1]
1023 self.report("page down")
1023 self.report("page down")
1024 level.moveto(level.curx, level.cury+level.mainsizey-self.pageoverlapy)
1024 level.moveto(level.curx, level.cury+level.mainsizey-self.pageoverlapy)
1025
1025
1026 def cmd_left(self):
1026 def cmd_left(self):
1027 """
1027 """
1028 Move the cursor left.
1028 Move the cursor left.
1029 """
1029 """
1030 level = self.levels[-1]
1030 level = self.levels[-1]
1031 self.report("left")
1031 self.report("left")
1032 level.moveto(level.curx-self.stepx, level.cury)
1032 level.moveto(level.curx-self.stepx, level.cury)
1033
1033
1034 def cmd_right(self):
1034 def cmd_right(self):
1035 """
1035 """
1036 Move the cursor right.
1036 Move the cursor right.
1037 """
1037 """
1038 level = self.levels[-1]
1038 level = self.levels[-1]
1039 self.report("right")
1039 self.report("right")
1040 level.moveto(level.curx+self.stepx, level.cury)
1040 level.moveto(level.curx+self.stepx, level.cury)
1041
1041
1042 def cmd_home(self):
1042 def cmd_home(self):
1043 """
1043 """
1044 Move the cursor to the first column.
1044 Move the cursor to the first column.
1045 """
1045 """
1046 level = self.levels[-1]
1046 level = self.levels[-1]
1047 self.report("home")
1047 self.report("home")
1048 level.moveto(0, level.cury)
1048 level.moveto(0, level.cury)
1049
1049
1050 def cmd_end(self):
1050 def cmd_end(self):
1051 """
1051 """
1052 Move the cursor to the last column.
1052 Move the cursor to the last column.
1053 """
1053 """
1054 level = self.levels[-1]
1054 level = self.levels[-1]
1055 self.report("end")
1055 self.report("end")
1056 level.moveto(level.datasizex+level.mainsizey-self.pageoverlapx, level.cury)
1056 level.moveto(level.datasizex+level.mainsizey-self.pageoverlapx, level.cury)
1057
1057
1058 def cmd_prevattr(self):
1058 def cmd_prevattr(self):
1059 """
1059 """
1060 Move the cursor one attribute column to the left.
1060 Move the cursor one attribute column to the left.
1061 """
1061 """
1062 level = self.levels[-1]
1062 level = self.levels[-1]
1063 if level.displayattr[0] is None or level.displayattr[0] == 0:
1063 if level.displayattr[0] is None or level.displayattr[0] == 0:
1064 self.beep()
1064 self.beep()
1065 else:
1065 else:
1066 self.report("prevattr")
1066 self.report("prevattr")
1067 pos = 0
1067 pos = 0
1068 for (i, attrname) in enumerate(level.displayattrs):
1068 for (i, attrname) in enumerate(level.displayattrs):
1069 if i == level.displayattr[0]-1:
1069 if i == level.displayattr[0]-1:
1070 break
1070 break
1071 pos += level.colwidths[attrname] + 1
1071 pos += level.colwidths[attrname] + 1
1072 level.moveto(pos, level.cury)
1072 level.moveto(pos, level.cury)
1073
1073
1074 def cmd_nextattr(self):
1074 def cmd_nextattr(self):
1075 """
1075 """
1076 Move the cursor one attribute column to the right.
1076 Move the cursor one attribute column to the right.
1077 """
1077 """
1078 level = self.levels[-1]
1078 level = self.levels[-1]
1079 if level.displayattr[0] is None or level.displayattr[0] == len(level.displayattrs)-1:
1079 if level.displayattr[0] is None or level.displayattr[0] == len(level.displayattrs)-1:
1080 self.beep()
1080 self.beep()
1081 else:
1081 else:
1082 self.report("nextattr")
1082 self.report("nextattr")
1083 pos = 0
1083 pos = 0
1084 for (i, attrname) in enumerate(level.displayattrs):
1084 for (i, attrname) in enumerate(level.displayattrs):
1085 if i == level.displayattr[0]+1:
1085 if i == level.displayattr[0]+1:
1086 break
1086 break
1087 pos += level.colwidths[attrname] + 1
1087 pos += level.colwidths[attrname] + 1
1088 level.moveto(pos, level.cury)
1088 level.moveto(pos, level.cury)
1089
1089
1090 def cmd_pick(self):
1090 def cmd_pick(self):
1091 """
1091 """
1092 'Pick' the object under the cursor (i.e. the row the cursor is on).
1092 'Pick' the object under the cursor (i.e. the row the cursor is on).
1093 This leaves the browser and returns the picked object to the caller.
1093 This leaves the browser and returns the picked object to the caller.
1094 (In IPython this object will be available as the ``_`` variable.)
1094 (In IPython this object will be available as the ``_`` variable.)
1095 """
1095 """
1096 level = self.levels[-1]
1096 level = self.levels[-1]
1097 self.returnvalue = level.items[level.cury].item
1097 self.returnvalue = level.items[level.cury].item
1098 return True
1098 return True
1099
1099
1100 def cmd_pickattr(self):
1100 def cmd_pickattr(self):
1101 """
1101 """
1102 'Pick' the attribute under the cursor (i.e. the row/column the
1102 'Pick' the attribute under the cursor (i.e. the row/column the
1103 cursor is on).
1103 cursor is on).
1104 """
1104 """
1105 level = self.levels[-1]
1105 level = self.levels[-1]
1106 attr = level.displayattr[1]
1106 attr = level.displayattr[1]
1107 if attr is ipipe.noitem:
1107 if attr is ipipe.noitem:
1108 curses.beep()
1108 curses.beep()
1109 self.report(CommandError("no column under cursor"))
1109 self.report(CommandError("no column under cursor"))
1110 return
1110 return
1111 value = attr.value(level.items[level.cury].item)
1111 value = attr.value(level.items[level.cury].item)
1112 if value is ipipe.noitem:
1112 if value is ipipe.noitem:
1113 curses.beep()
1113 curses.beep()
1114 self.report(AttributeError(attr.name()))
1114 self.report(AttributeError(attr.name()))
1115 else:
1115 else:
1116 self.returnvalue = value
1116 self.returnvalue = value
1117 return True
1117 return True
1118
1118
1119 def cmd_pickallattrs(self):
1119 def cmd_pickallattrs(self):
1120 """
1120 """
1121 Pick' the complete column under the cursor (i.e. the attribute under
1121 Pick' the complete column under the cursor (i.e. the attribute under
1122 the cursor) from all currently fetched objects. These attributes
1122 the cursor) from all currently fetched objects. These attributes
1123 will be returned as a list.
1123 will be returned as a list.
1124 """
1124 """
1125 level = self.levels[-1]
1125 level = self.levels[-1]
1126 attr = level.displayattr[1]
1126 attr = level.displayattr[1]
1127 if attr is ipipe.noitem:
1127 if attr is ipipe.noitem:
1128 curses.beep()
1128 curses.beep()
1129 self.report(CommandError("no column under cursor"))
1129 self.report(CommandError("no column under cursor"))
1130 return
1130 return
1131 result = []
1131 result = []
1132 for cache in level.items:
1132 for cache in level.items:
1133 value = attr.value(cache.item)
1133 value = attr.value(cache.item)
1134 if value is not ipipe.noitem:
1134 if value is not ipipe.noitem:
1135 result.append(value)
1135 result.append(value)
1136 self.returnvalue = result
1136 self.returnvalue = result
1137 return True
1137 return True
1138
1138
1139 def cmd_pickmarked(self):
1139 def cmd_pickmarked(self):
1140 """
1140 """
1141 'Pick' marked objects. Marked objects will be returned as a list.
1141 'Pick' marked objects. Marked objects will be returned as a list.
1142 """
1142 """
1143 level = self.levels[-1]
1143 level = self.levels[-1]
1144 self.returnvalue = [cache.item for cache in level.items if cache.marked]
1144 self.returnvalue = [cache.item for cache in level.items if cache.marked]
1145 return True
1145 return True
1146
1146
1147 def cmd_pickmarkedattr(self):
1147 def cmd_pickmarkedattr(self):
1148 """
1148 """
1149 'Pick' the attribute under the cursor from all marked objects
1149 'Pick' the attribute under the cursor from all marked objects
1150 (This returns a list).
1150 (This returns a list).
1151 """
1151 """
1152
1152
1153 level = self.levels[-1]
1153 level = self.levels[-1]
1154 attr = level.displayattr[1]
1154 attr = level.displayattr[1]
1155 if attr is ipipe.noitem:
1155 if attr is ipipe.noitem:
1156 curses.beep()
1156 curses.beep()
1157 self.report(CommandError("no column under cursor"))
1157 self.report(CommandError("no column under cursor"))
1158 return
1158 return
1159 result = []
1159 result = []
1160 for cache in level.items:
1160 for cache in level.items:
1161 if cache.marked:
1161 if cache.marked:
1162 value = attr.value(cache.item)
1162 value = attr.value(cache.item)
1163 if value is not ipipe.noitem:
1163 if value is not ipipe.noitem:
1164 result.append(value)
1164 result.append(value)
1165 self.returnvalue = result
1165 self.returnvalue = result
1166 return True
1166 return True
1167
1167
1168 def cmd_pickinput(self):
1168 def cmd_pickinput(self):
1169 """
1169 """
1170 Use the object under the cursor (i.e. the row the cursor is on) as
1170 Use the object under the cursor (i.e. the row the cursor is on) as
1171 the next input line. This leaves the browser and puts the picked object
1171 the next input line. This leaves the browser and puts the picked object
1172 in the input.
1172 in the input.
1173 """
1173 """
1174 level = self.levels[-1]
1174 level = self.levels[-1]
1175 value = level.items[level.cury].item
1175 value = level.items[level.cury].item
1176 self.returnvalue = None
1176 self.returnvalue = None
1177 api = ipapi.get()
1177 api = ipapi.get()
1178 api.set_next_input(str(value))
1178 api.set_next_input(str(value))
1179 return True
1179 return True
1180
1180
1181 def cmd_pickinputattr(self):
1181 def cmd_pickinputattr(self):
1182 """
1182 """
1183 Use the attribute under the cursor i.e. the row/column the cursor is on)
1183 Use the attribute under the cursor i.e. the row/column the cursor is on)
1184 as the next input line. This leaves the browser and puts the picked
1184 as the next input line. This leaves the browser and puts the picked
1185 object in the input.
1185 object in the input.
1186 """
1186 """
1187 level = self.levels[-1]
1187 level = self.levels[-1]
1188 attr = level.displayattr[1]
1188 attr = level.displayattr[1]
1189 if attr is ipipe.noitem:
1189 if attr is ipipe.noitem:
1190 curses.beep()
1190 curses.beep()
1191 self.report(CommandError("no column under cursor"))
1191 self.report(CommandError("no column under cursor"))
1192 return
1192 return
1193 value = attr.value(level.items[level.cury].item)
1193 value = attr.value(level.items[level.cury].item)
1194 if value is ipipe.noitem:
1194 if value is ipipe.noitem:
1195 curses.beep()
1195 curses.beep()
1196 self.report(AttributeError(attr.name()))
1196 self.report(AttributeError(attr.name()))
1197 self.returnvalue = None
1197 self.returnvalue = None
1198 api = ipapi.get()
1198 api = ipapi.get()
1199 api.set_next_input(str(value))
1199 api.set_next_input(str(value))
1200 return True
1200 return True
1201
1201
1202 def cmd_markrange(self):
1202 def cmd_markrange(self):
1203 """
1203 """
1204 Mark all objects from the last marked object before the current cursor
1204 Mark all objects from the last marked object before the current cursor
1205 position to the cursor position.
1205 position to the cursor position.
1206 """
1206 """
1207 level = self.levels[-1]
1207 level = self.levels[-1]
1208 self.report("markrange")
1208 self.report("markrange")
1209 start = None
1209 start = None
1210 if level.items:
1210 if level.items:
1211 for i in xrange(level.cury, -1, -1):
1211 for i in xrange(level.cury, -1, -1):
1212 if level.items[i].marked:
1212 if level.items[i].marked:
1213 start = i
1213 start = i
1214 break
1214 break
1215 if start is None:
1215 if start is None:
1216 self.report(CommandError("no mark before cursor"))
1216 self.report(CommandError("no mark before cursor"))
1217 curses.beep()
1217 curses.beep()
1218 else:
1218 else:
1219 for i in xrange(start, level.cury+1):
1219 for i in xrange(start, level.cury+1):
1220 cache = level.items[i]
1220 cache = level.items[i]
1221 if not cache.marked:
1221 if not cache.marked:
1222 cache.marked = True
1222 cache.marked = True
1223 level.marked += 1
1223 level.marked += 1
1224
1224
1225 def cmd_enter(self):
1225 def cmd_enter(self):
1226 """
1226 """
1227 Enter the object under the cursor. (what this mean depends on the object
1227 Enter the object under the cursor. (what this mean depends on the object
1228 itself (i.e. how it implements iteration). This opens a new browser 'level'.
1228 itself (i.e. how it implements iteration). This opens a new browser 'level'.
1229 """
1229 """
1230 level = self.levels[-1]
1230 level = self.levels[-1]
1231 try:
1231 try:
1232 item = level.items[level.cury].item
1232 item = level.items[level.cury].item
1233 except IndexError:
1233 except IndexError:
1234 self.report(CommandError("No object"))
1234 self.report(CommandError("No object"))
1235 curses.beep()
1235 curses.beep()
1236 else:
1236 else:
1237 self.report("entering object...")
1237 self.report("entering object...")
1238 self.enter(item)
1238 self.enter(item)
1239
1239
1240 def cmd_leave(self):
1240 def cmd_leave(self):
1241 """
1241 """
1242 Leave the current browser level and go back to the previous one.
1242 Leave the current browser level and go back to the previous one.
1243 """
1243 """
1244 self.report("leave")
1244 self.report("leave")
1245 if len(self.levels) > 1:
1245 if len(self.levels) > 1:
1246 self._calcheaderlines(len(self.levels)-1)
1246 self._calcheaderlines(len(self.levels)-1)
1247 self.levels.pop(-1)
1247 self.levels.pop(-1)
1248 else:
1248 else:
1249 self.report(CommandError("This is the last level"))
1249 self.report(CommandError("This is the last level"))
1250 curses.beep()
1250 curses.beep()
1251
1251
1252 def cmd_enterattr(self):
1252 def cmd_enterattr(self):
1253 """
1253 """
1254 Enter the attribute under the cursor.
1254 Enter the attribute under the cursor.
1255 """
1255 """
1256 level = self.levels[-1]
1256 level = self.levels[-1]
1257 attr = level.displayattr[1]
1257 attr = level.displayattr[1]
1258 if attr is ipipe.noitem:
1258 if attr is ipipe.noitem:
1259 curses.beep()
1259 curses.beep()
1260 self.report(CommandError("no column under cursor"))
1260 self.report(CommandError("no column under cursor"))
1261 return
1261 return
1262 try:
1262 try:
1263 item = level.items[level.cury].item
1263 item = level.items[level.cury].item
1264 except IndexError:
1264 except IndexError:
1265 self.report(CommandError("No object"))
1265 self.report(CommandError("No object"))
1266 curses.beep()
1266 curses.beep()
1267 else:
1267 else:
1268 value = attr.value(item)
1268 value = attr.value(item)
1269 name = attr.name()
1269 name = attr.name()
1270 if value is ipipe.noitem:
1270 if value is ipipe.noitem:
1271 self.report(AttributeError(name))
1271 self.report(AttributeError(name))
1272 else:
1272 else:
1273 self.report("entering object attribute %s..." % name)
1273 self.report("entering object attribute %s..." % name)
1274 self.enter(value)
1274 self.enter(value)
1275
1275
1276 def cmd_detail(self):
1276 def cmd_detail(self):
1277 """
1277 """
1278 Show a detail view of the object under the cursor. This shows the
1278 Show a detail view of the object under the cursor. This shows the
1279 name, type, doc string and value of the object attributes (and it
1279 name, type, doc string and value of the object attributes (and it
1280 might show more attributes than in the list view, depending on
1280 might show more attributes than in the list view, depending on
1281 the object).
1281 the object).
1282 """
1282 """
1283 level = self.levels[-1]
1283 level = self.levels[-1]
1284 try:
1284 try:
1285 item = level.items[level.cury].item
1285 item = level.items[level.cury].item
1286 except IndexError:
1286 except IndexError:
1287 self.report(CommandError("No object"))
1287 self.report(CommandError("No object"))
1288 curses.beep()
1288 curses.beep()
1289 else:
1289 else:
1290 self.report("entering detail view for object...")
1290 self.report("entering detail view for object...")
1291 attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
1291 attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
1292 self.enter(attrs)
1292 self.enter(attrs)
1293
1293
1294 def cmd_detailattr(self):
1294 def cmd_detailattr(self):
1295 """
1295 """
1296 Show a detail view of the attribute under the cursor.
1296 Show a detail view of the attribute under the cursor.
1297 """
1297 """
1298 level = self.levels[-1]
1298 level = self.levels[-1]
1299 attr = level.displayattr[1]
1299 attr = level.displayattr[1]
1300 if attr is ipipe.noitem:
1300 if attr is ipipe.noitem:
1301 curses.beep()
1301 curses.beep()
1302 self.report(CommandError("no attribute"))
1302 self.report(CommandError("no attribute"))
1303 return
1303 return
1304 try:
1304 try:
1305 item = level.items[level.cury].item
1305 item = level.items[level.cury].item
1306 except IndexError:
1306 except IndexError:
1307 self.report(CommandError("No object"))
1307 self.report(CommandError("No object"))
1308 curses.beep()
1308 curses.beep()
1309 else:
1309 else:
1310 try:
1310 try:
1311 item = attr.value(item)
1311 item = attr.value(item)
1312 except (KeyboardInterrupt, SystemExit):
1312 except (KeyboardInterrupt, SystemExit):
1313 raise
1313 raise
1314 except Exception, exc:
1314 except Exception as exc:
1315 self.report(exc)
1315 self.report(exc)
1316 else:
1316 else:
1317 self.report("entering detail view for attribute %s..." % attr.name())
1317 self.report("entering detail view for attribute %s..." % attr.name())
1318 attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
1318 attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
1319 self.enter(attrs)
1319 self.enter(attrs)
1320
1320
1321 def cmd_tooglemark(self):
1321 def cmd_tooglemark(self):
1322 """
1322 """
1323 Mark/unmark the object under the cursor. Marked objects have a '!'
1323 Mark/unmark the object under the cursor. Marked objects have a '!'
1324 after the row number).
1324 after the row number).
1325 """
1325 """
1326 level = self.levels[-1]
1326 level = self.levels[-1]
1327 self.report("toggle mark")
1327 self.report("toggle mark")
1328 try:
1328 try:
1329 item = level.items[level.cury]
1329 item = level.items[level.cury]
1330 except IndexError: # no items?
1330 except IndexError: # no items?
1331 pass
1331 pass
1332 else:
1332 else:
1333 if item.marked:
1333 if item.marked:
1334 item.marked = False
1334 item.marked = False
1335 level.marked -= 1
1335 level.marked -= 1
1336 else:
1336 else:
1337 item.marked = True
1337 item.marked = True
1338 level.marked += 1
1338 level.marked += 1
1339
1339
1340 def cmd_sortattrasc(self):
1340 def cmd_sortattrasc(self):
1341 """
1341 """
1342 Sort the objects (in ascending order) using the attribute under
1342 Sort the objects (in ascending order) using the attribute under
1343 the cursor as the sort key.
1343 the cursor as the sort key.
1344 """
1344 """
1345 level = self.levels[-1]
1345 level = self.levels[-1]
1346 attr = level.displayattr[1]
1346 attr = level.displayattr[1]
1347 if attr is ipipe.noitem:
1347 if attr is ipipe.noitem:
1348 curses.beep()
1348 curses.beep()
1349 self.report(CommandError("no column under cursor"))
1349 self.report(CommandError("no column under cursor"))
1350 return
1350 return
1351 self.report("sort by %s (ascending)" % attr.name())
1351 self.report("sort by %s (ascending)" % attr.name())
1352 def key(item):
1352 def key(item):
1353 try:
1353 try:
1354 return attr.value(item)
1354 return attr.value(item)
1355 except (KeyboardInterrupt, SystemExit):
1355 except (KeyboardInterrupt, SystemExit):
1356 raise
1356 raise
1357 except Exception:
1357 except Exception:
1358 return None
1358 return None
1359 level.sort(key)
1359 level.sort(key)
1360
1360
1361 def cmd_sortattrdesc(self):
1361 def cmd_sortattrdesc(self):
1362 """
1362 """
1363 Sort the objects (in descending order) using the attribute under
1363 Sort the objects (in descending order) using the attribute under
1364 the cursor as the sort key.
1364 the cursor as the sort key.
1365 """
1365 """
1366 level = self.levels[-1]
1366 level = self.levels[-1]
1367 attr = level.displayattr[1]
1367 attr = level.displayattr[1]
1368 if attr is ipipe.noitem:
1368 if attr is ipipe.noitem:
1369 curses.beep()
1369 curses.beep()
1370 self.report(CommandError("no column under cursor"))
1370 self.report(CommandError("no column under cursor"))
1371 return
1371 return
1372 self.report("sort by %s (descending)" % attr.name())
1372 self.report("sort by %s (descending)" % attr.name())
1373 def key(item):
1373 def key(item):
1374 try:
1374 try:
1375 return attr.value(item)
1375 return attr.value(item)
1376 except (KeyboardInterrupt, SystemExit):
1376 except (KeyboardInterrupt, SystemExit):
1377 raise
1377 raise
1378 except Exception:
1378 except Exception:
1379 return None
1379 return None
1380 level.sort(key, reverse=True)
1380 level.sort(key, reverse=True)
1381
1381
1382 def cmd_hideattr(self):
1382 def cmd_hideattr(self):
1383 """
1383 """
1384 Hide the attribute under the cursor.
1384 Hide the attribute under the cursor.
1385 """
1385 """
1386 level = self.levels[-1]
1386 level = self.levels[-1]
1387 if level.displayattr[0] is None:
1387 if level.displayattr[0] is None:
1388 self.beep()
1388 self.beep()
1389 else:
1389 else:
1390 self.report("hideattr")
1390 self.report("hideattr")
1391 level.hiddenattrs.add(level.displayattr[1])
1391 level.hiddenattrs.add(level.displayattr[1])
1392 level.moveto(level.curx, level.cury, refresh=True)
1392 level.moveto(level.curx, level.cury, refresh=True)
1393
1393
1394 def cmd_unhideattrs(self):
1394 def cmd_unhideattrs(self):
1395 """
1395 """
1396 Make all attributes visible again.
1396 Make all attributes visible again.
1397 """
1397 """
1398 level = self.levels[-1]
1398 level = self.levels[-1]
1399 self.report("unhideattrs")
1399 self.report("unhideattrs")
1400 level.hiddenattrs.clear()
1400 level.hiddenattrs.clear()
1401 level.moveto(level.curx, level.cury, refresh=True)
1401 level.moveto(level.curx, level.cury, refresh=True)
1402
1402
1403 def cmd_goto(self):
1403 def cmd_goto(self):
1404 """
1404 """
1405 Jump to a row. The row number can be entered at the
1405 Jump to a row. The row number can be entered at the
1406 bottom of the screen.
1406 bottom of the screen.
1407 """
1407 """
1408 self.startkeyboardinput("goto")
1408 self.startkeyboardinput("goto")
1409
1409
1410 def cmd_find(self):
1410 def cmd_find(self):
1411 """
1411 """
1412 Search forward for a row. The search condition can be entered at the
1412 Search forward for a row. The search condition can be entered at the
1413 bottom of the screen.
1413 bottom of the screen.
1414 """
1414 """
1415 self.startkeyboardinput("find")
1415 self.startkeyboardinput("find")
1416
1416
1417 def cmd_findbackwards(self):
1417 def cmd_findbackwards(self):
1418 """
1418 """
1419 Search backward for a row. The search condition can be entered at the
1419 Search backward for a row. The search condition can be entered at the
1420 bottom of the screen.
1420 bottom of the screen.
1421 """
1421 """
1422 self.startkeyboardinput("findbackwards")
1422 self.startkeyboardinput("findbackwards")
1423
1423
1424 def cmd_refresh(self):
1424 def cmd_refresh(self):
1425 """
1425 """
1426 Refreshes the display by restarting the iterator.
1426 Refreshes the display by restarting the iterator.
1427 """
1427 """
1428 level = self.levels[-1]
1428 level = self.levels[-1]
1429 self.report("refresh")
1429 self.report("refresh")
1430 level.refresh()
1430 level.refresh()
1431
1431
1432 def cmd_refreshfind(self):
1432 def cmd_refreshfind(self):
1433 """
1433 """
1434 Refreshes the display by restarting the iterator and goes back to the
1434 Refreshes the display by restarting the iterator and goes back to the
1435 same object the cursor was on before restarting (if this object can't be
1435 same object the cursor was on before restarting (if this object can't be
1436 found the cursor jumps back to the first object).
1436 found the cursor jumps back to the first object).
1437 """
1437 """
1438 level = self.levels[-1]
1438 level = self.levels[-1]
1439 self.report("refreshfind")
1439 self.report("refreshfind")
1440 level.refreshfind()
1440 level.refreshfind()
1441
1441
1442 def cmd_help(self):
1442 def cmd_help(self):
1443 """
1443 """
1444 Opens the help screen as a new browser level, describing keyboard
1444 Opens the help screen as a new browser level, describing keyboard
1445 shortcuts.
1445 shortcuts.
1446 """
1446 """
1447 for level in self.levels:
1447 for level in self.levels:
1448 if isinstance(level.input, _BrowserHelp):
1448 if isinstance(level.input, _BrowserHelp):
1449 curses.beep()
1449 curses.beep()
1450 self.report(CommandError("help already active"))
1450 self.report(CommandError("help already active"))
1451 return
1451 return
1452
1452
1453 self.enter(_BrowserHelp(self))
1453 self.enter(_BrowserHelp(self))
1454
1454
1455 def cmd_quit(self):
1455 def cmd_quit(self):
1456 """
1456 """
1457 Quit the browser and return to the IPython prompt.
1457 Quit the browser and return to the IPython prompt.
1458 """
1458 """
1459 self.returnvalue = None
1459 self.returnvalue = None
1460 return True
1460 return True
1461
1461
1462 def sigwinchhandler(self, signal, frame):
1462 def sigwinchhandler(self, signal, frame):
1463 self.resized = True
1463 self.resized = True
1464
1464
1465 def _dodisplay(self, scr):
1465 def _dodisplay(self, scr):
1466 """
1466 """
1467 This method is the workhorse of the browser. It handles screen
1467 This method is the workhorse of the browser. It handles screen
1468 drawing and the keyboard.
1468 drawing and the keyboard.
1469 """
1469 """
1470 self.scr = scr
1470 self.scr = scr
1471 curses.halfdelay(1)
1471 curses.halfdelay(1)
1472 footery = 2
1472 footery = 2
1473
1473
1474 keys = []
1474 keys = []
1475 for cmd in ("quit", "help"):
1475 for cmd in ("quit", "help"):
1476 key = self.keymap.findkey(cmd, None)
1476 key = self.keymap.findkey(cmd, None)
1477 if key is not None:
1477 if key is not None:
1478 keys.append("%s=%s" % (self.keylabel(key), cmd))
1478 keys.append("%s=%s" % (self.keylabel(key), cmd))
1479 helpmsg = " | %s" % " ".join(keys)
1479 helpmsg = " | %s" % " ".join(keys)
1480
1480
1481 scr.clear()
1481 scr.clear()
1482 msg = "Fetching first batch of objects..."
1482 msg = "Fetching first batch of objects..."
1483 (self.scrsizey, self.scrsizex) = scr.getmaxyx()
1483 (self.scrsizey, self.scrsizex) = scr.getmaxyx()
1484 scr.addstr(self.scrsizey//2, (self.scrsizex-len(msg))//2, msg)
1484 scr.addstr(self.scrsizey//2, (self.scrsizex-len(msg))//2, msg)
1485 scr.refresh()
1485 scr.refresh()
1486
1486
1487 lastc = -1
1487 lastc = -1
1488
1488
1489 self.levels = []
1489 self.levels = []
1490 # enter the first level
1490 # enter the first level
1491 self.enter(self.input, *self.attrs)
1491 self.enter(self.input, *self.attrs)
1492
1492
1493 self._calcheaderlines(None)
1493 self._calcheaderlines(None)
1494
1494
1495 while True:
1495 while True:
1496 level = self.levels[-1]
1496 level = self.levels[-1]
1497 (self.scrsizey, self.scrsizex) = scr.getmaxyx()
1497 (self.scrsizey, self.scrsizex) = scr.getmaxyx()
1498 level.mainsizey = self.scrsizey-1-self._headerlines-footery
1498 level.mainsizey = self.scrsizey-1-self._headerlines-footery
1499
1499
1500 # Paint object header
1500 # Paint object header
1501 for i in xrange(self._firstheaderline, self._firstheaderline+self._headerlines):
1501 for i in xrange(self._firstheaderline, self._firstheaderline+self._headerlines):
1502 lv = self.levels[i]
1502 lv = self.levels[i]
1503 posx = 0
1503 posx = 0
1504 posy = i-self._firstheaderline
1504 posy = i-self._firstheaderline
1505 endx = self.scrsizex
1505 endx = self.scrsizex
1506 if i: # not the first level
1506 if i: # not the first level
1507 msg = " (%d/%d" % (self.levels[i-1].cury, len(self.levels[i-1].items))
1507 msg = " (%d/%d" % (self.levels[i-1].cury, len(self.levels[i-1].items))
1508 if not self.levels[i-1].exhausted:
1508 if not self.levels[i-1].exhausted:
1509 msg += "+"
1509 msg += "+"
1510 msg += ") "
1510 msg += ") "
1511 endx -= len(msg)+1
1511 endx -= len(msg)+1
1512 posx += self.addstr(posy, posx, 0, endx, " ibrowse #%d: " % i, self.style_objheadertext)
1512 posx += self.addstr(posy, posx, 0, endx, " ibrowse #%d: " % i, self.style_objheadertext)
1513 for (style, text) in lv.header:
1513 for (style, text) in lv.header:
1514 posx += self.addstr(posy, posx, 0, endx, text, self.style_objheaderobject)
1514 posx += self.addstr(posy, posx, 0, endx, text, self.style_objheaderobject)
1515 if posx >= endx:
1515 if posx >= endx:
1516 break
1516 break
1517 if i:
1517 if i:
1518 posx += self.addstr(posy, posx, 0, self.scrsizex, msg, self.style_objheadernumber)
1518 posx += self.addstr(posy, posx, 0, self.scrsizex, msg, self.style_objheadernumber)
1519 posx += self.addchr(posy, posx, 0, self.scrsizex, " ", self.scrsizex-posx, self.style_objheadernumber)
1519 posx += self.addchr(posy, posx, 0, self.scrsizex, " ", self.scrsizex-posx, self.style_objheadernumber)
1520
1520
1521 if not level.items:
1521 if not level.items:
1522 self.addchr(self._headerlines, 0, 0, self.scrsizex, " ", self.scrsizex, self.style_colheader)
1522 self.addchr(self._headerlines, 0, 0, self.scrsizex, " ", self.scrsizex, self.style_colheader)
1523 self.addstr(self._headerlines+1, 0, 0, self.scrsizex, " <empty>", astyle.style_error)
1523 self.addstr(self._headerlines+1, 0, 0, self.scrsizex, " <empty>", astyle.style_error)
1524 scr.clrtobot()
1524 scr.clrtobot()
1525 else:
1525 else:
1526 # Paint column headers
1526 # Paint column headers
1527 scr.move(self._headerlines, 0)
1527 scr.move(self._headerlines, 0)
1528 scr.addstr(" %*s " % (level.numbersizex, "#"), self.getstyle(self.style_colheader))
1528 scr.addstr(" %*s " % (level.numbersizex, "#"), self.getstyle(self.style_colheader))
1529 scr.addstr(self.headersepchar, self.getstyle(self.style_colheadersep))
1529 scr.addstr(self.headersepchar, self.getstyle(self.style_colheadersep))
1530 begx = level.numbersizex+3
1530 begx = level.numbersizex+3
1531 posx = begx-level.datastartx
1531 posx = begx-level.datastartx
1532 for attr in level.displayattrs:
1532 for attr in level.displayattrs:
1533 attrname = attr.name()
1533 attrname = attr.name()
1534 cwidth = level.colwidths[attr]
1534 cwidth = level.colwidths[attr]
1535 header = attrname.ljust(cwidth)
1535 header = attrname.ljust(cwidth)
1536 if attr is level.displayattr[1]:
1536 if attr is level.displayattr[1]:
1537 style = self.style_colheaderhere
1537 style = self.style_colheaderhere
1538 else:
1538 else:
1539 style = self.style_colheader
1539 style = self.style_colheader
1540 posx += self.addstr(self._headerlines, posx, begx, self.scrsizex, header, style)
1540 posx += self.addstr(self._headerlines, posx, begx, self.scrsizex, header, style)
1541 posx += self.addstr(self._headerlines, posx, begx, self.scrsizex, self.headersepchar, self.style_colheadersep)
1541 posx += self.addstr(self._headerlines, posx, begx, self.scrsizex, self.headersepchar, self.style_colheadersep)
1542 if posx >= self.scrsizex:
1542 if posx >= self.scrsizex:
1543 break
1543 break
1544 else:
1544 else:
1545 scr.addstr(" "*(self.scrsizex-posx), self.getstyle(self.style_colheader))
1545 scr.addstr(" "*(self.scrsizex-posx), self.getstyle(self.style_colheader))
1546
1546
1547 # Paint rows
1547 # Paint rows
1548 posy = self._headerlines+1+level.datastarty
1548 posy = self._headerlines+1+level.datastarty
1549 for i in xrange(level.datastarty, min(level.datastarty+level.mainsizey, len(level.items))):
1549 for i in xrange(level.datastarty, min(level.datastarty+level.mainsizey, len(level.items))):
1550 cache = level.items[i]
1550 cache = level.items[i]
1551 if i == level.cury:
1551 if i == level.cury:
1552 style = self.style_numberhere
1552 style = self.style_numberhere
1553 else:
1553 else:
1554 style = self.style_number
1554 style = self.style_number
1555
1555
1556 posy = self._headerlines+1+i-level.datastarty
1556 posy = self._headerlines+1+i-level.datastarty
1557 posx = begx-level.datastartx
1557 posx = begx-level.datastartx
1558
1558
1559 scr.move(posy, 0)
1559 scr.move(posy, 0)
1560 scr.addstr(" %*d%s" % (level.numbersizex, i, " !"[cache.marked]), self.getstyle(style))
1560 scr.addstr(" %*d%s" % (level.numbersizex, i, " !"[cache.marked]), self.getstyle(style))
1561 scr.addstr(self.headersepchar, self.getstyle(self.style_sep))
1561 scr.addstr(self.headersepchar, self.getstyle(self.style_sep))
1562
1562
1563 for attrname in level.displayattrs:
1563 for attrname in level.displayattrs:
1564 cwidth = level.colwidths[attrname]
1564 cwidth = level.colwidths[attrname]
1565 try:
1565 try:
1566 (align, length, parts) = level.displayrows[i-level.datastarty][attrname]
1566 (align, length, parts) = level.displayrows[i-level.datastarty][attrname]
1567 except KeyError:
1567 except KeyError:
1568 align = 2
1568 align = 2
1569 style = astyle.style_nodata
1569 style = astyle.style_nodata
1570 if i == level.cury:
1570 if i == level.cury:
1571 style = self.getstylehere(style)
1571 style = self.getstylehere(style)
1572 padstyle = self.style_datapad
1572 padstyle = self.style_datapad
1573 sepstyle = self.style_sep
1573 sepstyle = self.style_sep
1574 if i == level.cury:
1574 if i == level.cury:
1575 padstyle = self.getstylehere(padstyle)
1575 padstyle = self.getstylehere(padstyle)
1576 sepstyle = self.getstylehere(sepstyle)
1576 sepstyle = self.getstylehere(sepstyle)
1577 if align == 2:
1577 if align == 2:
1578 posx += self.addchr(posy, posx, begx, self.scrsizex, self.nodatachar, cwidth, style)
1578 posx += self.addchr(posy, posx, begx, self.scrsizex, self.nodatachar, cwidth, style)
1579 else:
1579 else:
1580 if align == 1:
1580 if align == 1:
1581 posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, cwidth-length, padstyle)
1581 posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, cwidth-length, padstyle)
1582 elif align == 0:
1582 elif align == 0:
1583 pad1 = (cwidth-length)//2
1583 pad1 = (cwidth-length)//2
1584 pad2 = cwidth-length-len(pad1)
1584 pad2 = cwidth-length-len(pad1)
1585 posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, pad1, padstyle)
1585 posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, pad1, padstyle)
1586 for (style, text) in parts:
1586 for (style, text) in parts:
1587 if i == level.cury:
1587 if i == level.cury:
1588 style = self.getstylehere(style)
1588 style = self.getstylehere(style)
1589 posx += self.addstr(posy, posx, begx, self.scrsizex, text, style)
1589 posx += self.addstr(posy, posx, begx, self.scrsizex, text, style)
1590 if posx >= self.scrsizex:
1590 if posx >= self.scrsizex:
1591 break
1591 break
1592 if align == -1:
1592 if align == -1:
1593 posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, cwidth-length, padstyle)
1593 posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, cwidth-length, padstyle)
1594 elif align == 0:
1594 elif align == 0:
1595 posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, pad2, padstyle)
1595 posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, pad2, padstyle)
1596 posx += self.addstr(posy, posx, begx, self.scrsizex, self.datasepchar, sepstyle)
1596 posx += self.addstr(posy, posx, begx, self.scrsizex, self.datasepchar, sepstyle)
1597 else:
1597 else:
1598 scr.clrtoeol()
1598 scr.clrtoeol()
1599
1599
1600 # Add blank row headers for the rest of the screen
1600 # Add blank row headers for the rest of the screen
1601 for posy in xrange(posy+1, self.scrsizey-2):
1601 for posy in xrange(posy+1, self.scrsizey-2):
1602 scr.addstr(posy, 0, " " * (level.numbersizex+2), self.getstyle(self.style_colheader))
1602 scr.addstr(posy, 0, " " * (level.numbersizex+2), self.getstyle(self.style_colheader))
1603 scr.clrtoeol()
1603 scr.clrtoeol()
1604
1604
1605 posy = self.scrsizey-footery
1605 posy = self.scrsizey-footery
1606 # Display footer
1606 # Display footer
1607 scr.addstr(posy, 0, " "*self.scrsizex, self.getstyle(self.style_footer))
1607 scr.addstr(posy, 0, " "*self.scrsizex, self.getstyle(self.style_footer))
1608
1608
1609 if level.exhausted:
1609 if level.exhausted:
1610 flag = ""
1610 flag = ""
1611 else:
1611 else:
1612 flag = "+"
1612 flag = "+"
1613
1613
1614 endx = self.scrsizex-len(helpmsg)-1
1614 endx = self.scrsizex-len(helpmsg)-1
1615 scr.addstr(posy, endx, helpmsg, self.getstyle(self.style_footer))
1615 scr.addstr(posy, endx, helpmsg, self.getstyle(self.style_footer))
1616
1616
1617 posx = 0
1617 posx = 0
1618 msg = " %d%s objects (%d marked): " % (len(level.items), flag, level.marked)
1618 msg = " %d%s objects (%d marked): " % (len(level.items), flag, level.marked)
1619 posx += self.addstr(posy, posx, 0, endx, msg, self.style_footer)
1619 posx += self.addstr(posy, posx, 0, endx, msg, self.style_footer)
1620 try:
1620 try:
1621 item = level.items[level.cury].item
1621 item = level.items[level.cury].item
1622 except IndexError: # empty
1622 except IndexError: # empty
1623 pass
1623 pass
1624 else:
1624 else:
1625 for (nostyle, text) in ipipe.xrepr(item, "footer"):
1625 for (nostyle, text) in ipipe.xrepr(item, "footer"):
1626 if not isinstance(nostyle, int):
1626 if not isinstance(nostyle, int):
1627 posx += self.addstr(posy, posx, 0, endx, text, self.style_footer)
1627 posx += self.addstr(posy, posx, 0, endx, text, self.style_footer)
1628 if posx >= endx:
1628 if posx >= endx:
1629 break
1629 break
1630
1630
1631 attrstyle = [(astyle.style_default, "no attribute")]
1631 attrstyle = [(astyle.style_default, "no attribute")]
1632 attr = level.displayattr[1]
1632 attr = level.displayattr[1]
1633 if attr is not ipipe.noitem and not isinstance(attr, ipipe.SelfDescriptor):
1633 if attr is not ipipe.noitem and not isinstance(attr, ipipe.SelfDescriptor):
1634 posx += self.addstr(posy, posx, 0, endx, " | ", self.style_footer)
1634 posx += self.addstr(posy, posx, 0, endx, " | ", self.style_footer)
1635 posx += self.addstr(posy, posx, 0, endx, attr.name(), self.style_footer)
1635 posx += self.addstr(posy, posx, 0, endx, attr.name(), self.style_footer)
1636 posx += self.addstr(posy, posx, 0, endx, ": ", self.style_footer)
1636 posx += self.addstr(posy, posx, 0, endx, ": ", self.style_footer)
1637 try:
1637 try:
1638 value = attr.value(item)
1638 value = attr.value(item)
1639 except (SystemExit, KeyboardInterrupt):
1639 except (SystemExit, KeyboardInterrupt):
1640 raise
1640 raise
1641 except Exception, exc:
1641 except Exception as exc:
1642 value = exc
1642 value = exc
1643 if value is not ipipe.noitem:
1643 if value is not ipipe.noitem:
1644 attrstyle = ipipe.xrepr(value, "footer")
1644 attrstyle = ipipe.xrepr(value, "footer")
1645 for (nostyle, text) in attrstyle:
1645 for (nostyle, text) in attrstyle:
1646 if not isinstance(nostyle, int):
1646 if not isinstance(nostyle, int):
1647 posx += self.addstr(posy, posx, 0, endx, text, self.style_footer)
1647 posx += self.addstr(posy, posx, 0, endx, text, self.style_footer)
1648 if posx >= endx:
1648 if posx >= endx:
1649 break
1649 break
1650
1650
1651 try:
1651 try:
1652 # Display input prompt
1652 # Display input prompt
1653 if self.mode in self.prompts:
1653 if self.mode in self.prompts:
1654 history = self.prompts[self.mode]
1654 history = self.prompts[self.mode]
1655 posx = 0
1655 posx = 0
1656 posy = self.scrsizey-1
1656 posy = self.scrsizey-1
1657 posx += self.addstr(posy, posx, 0, endx, history.prompt, astyle.style_default)
1657 posx += self.addstr(posy, posx, 0, endx, history.prompt, astyle.style_default)
1658 posx += self.addstr(posy, posx, 0, endx, " [", astyle.style_default)
1658 posx += self.addstr(posy, posx, 0, endx, " [", astyle.style_default)
1659 if history.cury==-1:
1659 if history.cury==-1:
1660 text = "new"
1660 text = "new"
1661 else:
1661 else:
1662 text = str(history.cury+1)
1662 text = str(history.cury+1)
1663 posx += self.addstr(posy, posx, 0, endx, text, astyle.style_type_number)
1663 posx += self.addstr(posy, posx, 0, endx, text, astyle.style_type_number)
1664 if history.history:
1664 if history.history:
1665 posx += self.addstr(posy, posx, 0, endx, "/", astyle.style_default)
1665 posx += self.addstr(posy, posx, 0, endx, "/", astyle.style_default)
1666 posx += self.addstr(posy, posx, 0, endx, str(len(history.history)), astyle.style_type_number)
1666 posx += self.addstr(posy, posx, 0, endx, str(len(history.history)), astyle.style_type_number)
1667 posx += self.addstr(posy, posx, 0, endx, "]: ", astyle.style_default)
1667 posx += self.addstr(posy, posx, 0, endx, "]: ", astyle.style_default)
1668 inputstartx = posx
1668 inputstartx = posx
1669 posx += self.addstr(posy, posx, 0, endx, history.input, astyle.style_default)
1669 posx += self.addstr(posy, posx, 0, endx, history.input, astyle.style_default)
1670 # Display report
1670 # Display report
1671 else:
1671 else:
1672 if self._report is not None:
1672 if self._report is not None:
1673 if isinstance(self._report, Exception):
1673 if isinstance(self._report, Exception):
1674 style = self.getstyle(astyle.style_error)
1674 style = self.getstyle(astyle.style_error)
1675 if self._report.__class__.__module__ == "exceptions":
1675 if self._report.__class__.__module__ == "exceptions":
1676 msg = "%s: %s" % \
1676 msg = "%s: %s" % \
1677 (self._report.__class__.__name__, self._report)
1677 (self._report.__class__.__name__, self._report)
1678 else:
1678 else:
1679 msg = "%s.%s: %s" % \
1679 msg = "%s.%s: %s" % \
1680 (self._report.__class__.__module__,
1680 (self._report.__class__.__module__,
1681 self._report.__class__.__name__, self._report)
1681 self._report.__class__.__name__, self._report)
1682 else:
1682 else:
1683 style = self.getstyle(self.style_report)
1683 style = self.getstyle(self.style_report)
1684 msg = self._report
1684 msg = self._report
1685 scr.addstr(self.scrsizey-1, 0, msg[:self.scrsizex], style)
1685 scr.addstr(self.scrsizey-1, 0, msg[:self.scrsizex], style)
1686 self._report = None
1686 self._report = None
1687 else:
1687 else:
1688 scr.move(self.scrsizey-1, 0)
1688 scr.move(self.scrsizey-1, 0)
1689 except curses.error:
1689 except curses.error:
1690 # Protect against errors from writing to the last line
1690 # Protect against errors from writing to the last line
1691 pass
1691 pass
1692 scr.clrtoeol()
1692 scr.clrtoeol()
1693
1693
1694 # Position cursor
1694 # Position cursor
1695 if self.mode in self.prompts:
1695 if self.mode in self.prompts:
1696 history = self.prompts[self.mode]
1696 history = self.prompts[self.mode]
1697 scr.move(self.scrsizey-1, inputstartx+history.curx)
1697 scr.move(self.scrsizey-1, inputstartx+history.curx)
1698 else:
1698 else:
1699 scr.move(
1699 scr.move(
1700 1+self._headerlines+level.cury-level.datastarty,
1700 1+self._headerlines+level.cury-level.datastarty,
1701 level.numbersizex+3+level.curx-level.datastartx
1701 level.numbersizex+3+level.curx-level.datastartx
1702 )
1702 )
1703 scr.refresh()
1703 scr.refresh()
1704
1704
1705 # Check keyboard
1705 # Check keyboard
1706 while True:
1706 while True:
1707 c = scr.getch()
1707 c = scr.getch()
1708 if self.resized:
1708 if self.resized:
1709 size = fcntl.ioctl(0, tty.TIOCGWINSZ, "12345678")
1709 size = fcntl.ioctl(0, tty.TIOCGWINSZ, "12345678")
1710 size = struct.unpack("4H", size)
1710 size = struct.unpack("4H", size)
1711 oldsize = scr.getmaxyx()
1711 oldsize = scr.getmaxyx()
1712 scr.erase()
1712 scr.erase()
1713 curses.resize_term(size[0], size[1])
1713 curses.resize_term(size[0], size[1])
1714 newsize = scr.getmaxyx()
1714 newsize = scr.getmaxyx()
1715 scr.erase()
1715 scr.erase()
1716 for l in self.levels:
1716 for l in self.levels:
1717 l.mainsizey += newsize[0]-oldsize[0]
1717 l.mainsizey += newsize[0]-oldsize[0]
1718 l.moveto(l.curx, l.cury, refresh=True)
1718 l.moveto(l.curx, l.cury, refresh=True)
1719 scr.refresh()
1719 scr.refresh()
1720 self.resized = False
1720 self.resized = False
1721 break # Redisplay
1721 break # Redisplay
1722 if self.mode in self.prompts:
1722 if self.mode in self.prompts:
1723 if self.prompts[self.mode].handlekey(self, c):
1723 if self.prompts[self.mode].handlekey(self, c):
1724 break # Redisplay
1724 break # Redisplay
1725 else:
1725 else:
1726 # if no key is pressed slow down and beep again
1726 # if no key is pressed slow down and beep again
1727 if c == -1:
1727 if c == -1:
1728 self.stepx = 1.
1728 self.stepx = 1.
1729 self.stepy = 1.
1729 self.stepy = 1.
1730 self._dobeep = True
1730 self._dobeep = True
1731 else:
1731 else:
1732 # if a different key was pressed slow down and beep too
1732 # if a different key was pressed slow down and beep too
1733 if c != lastc:
1733 if c != lastc:
1734 lastc = c
1734 lastc = c
1735 self.stepx = 1.
1735 self.stepx = 1.
1736 self.stepy = 1.
1736 self.stepy = 1.
1737 self._dobeep = True
1737 self._dobeep = True
1738 cmdname = self.keymap.get(c, None)
1738 cmdname = self.keymap.get(c, None)
1739 if cmdname is None:
1739 if cmdname is None:
1740 self.report(
1740 self.report(
1741 UnassignedKeyError("Unassigned key %s" %
1741 UnassignedKeyError("Unassigned key %s" %
1742 self.keylabel(c)))
1742 self.keylabel(c)))
1743 else:
1743 else:
1744 cmdfunc = getattr(self, "cmd_%s" % cmdname, None)
1744 cmdfunc = getattr(self, "cmd_%s" % cmdname, None)
1745 if cmdfunc is None:
1745 if cmdfunc is None:
1746 self.report(
1746 self.report(
1747 UnknownCommandError("Unknown command %r" %
1747 UnknownCommandError("Unknown command %r" %
1748 (cmdname,)))
1748 (cmdname,)))
1749 elif cmdfunc():
1749 elif cmdfunc():
1750 returnvalue = self.returnvalue
1750 returnvalue = self.returnvalue
1751 self.returnvalue = None
1751 self.returnvalue = None
1752 return returnvalue
1752 return returnvalue
1753 self.stepx = self.nextstepx(self.stepx)
1753 self.stepx = self.nextstepx(self.stepx)
1754 self.stepy = self.nextstepy(self.stepy)
1754 self.stepy = self.nextstepy(self.stepy)
1755 curses.flushinp() # get rid of type ahead
1755 curses.flushinp() # get rid of type ahead
1756 break # Redisplay
1756 break # Redisplay
1757 self.scr = None
1757 self.scr = None
1758
1758
1759 def display(self):
1759 def display(self):
1760 if hasattr(curses, "resize_term") and hasattr(signal, 'SIGWINCH'):
1760 if hasattr(curses, "resize_term") and hasattr(signal, 'SIGWINCH'):
1761 oldhandler = signal.signal(signal.SIGWINCH, self.sigwinchhandler)
1761 oldhandler = signal.signal(signal.SIGWINCH, self.sigwinchhandler)
1762 try:
1762 try:
1763 return curses.wrapper(self._dodisplay)
1763 return curses.wrapper(self._dodisplay)
1764 finally:
1764 finally:
1765 signal.signal(signal.SIGWINCH, oldhandler)
1765 signal.signal(signal.SIGWINCH, oldhandler)
1766 else:
1766 else:
1767 return curses.wrapper(self._dodisplay)
1767 return curses.wrapper(self._dodisplay)
@@ -1,1126 +1,1126 b''
1 # -*- coding: iso-8859-1 -*-
1 # -*- coding: iso-8859-1 -*-
2
2
3 import ipipe, os, webbrowser, urllib
3 import ipipe, os, webbrowser, urllib
4 from IPython.core import ipapi
4 from IPython.core import ipapi
5 import wx
5 import wx
6 import wx.grid, wx.html
6 import wx.grid, wx.html
7
7
8 try:
8 try:
9 sorted
9 sorted
10 except NameError:
10 except NameError:
11 from ipipe import sorted
11 from ipipe import sorted
12 try:
12 try:
13 set
13 set
14 except:
14 except:
15 from sets import Set as set
15 from sets import Set as set
16
16
17
17
18 __all__ = ["igrid"]
18 __all__ = ["igrid"]
19
19
20
20
21 help = """
21 help = """
22 <?xml version='1.0' encoding='iso-8859-1'?>
22 <?xml version='1.0' encoding='iso-8859-1'?>
23 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
23 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
24 <html>
24 <html>
25 <head>
25 <head>
26 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
26 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
27 <link rel="stylesheet" href="igrid_help.css" type="text/css" />
27 <link rel="stylesheet" href="igrid_help.css" type="text/css" />
28 <title>igrid help</title>
28 <title>igrid help</title>
29 </head>
29 </head>
30 <body>
30 <body>
31 <h1>igrid help</h1>
31 <h1>igrid help</h1>
32
32
33
33
34 <h2>Commands</h2>
34 <h2>Commands</h2>
35
35
36
36
37 <h3>pick (P)</h3>
37 <h3>pick (P)</h3>
38 <p>Pick the whole row (object is available as "_")</p>
38 <p>Pick the whole row (object is available as "_")</p>
39
39
40 <h3>pickattr (Shift-P)</h3>
40 <h3>pickattr (Shift-P)</h3>
41 <p>Pick the attribute under the cursor</p>
41 <p>Pick the attribute under the cursor</p>
42
42
43 <h3>pickallattrs (Shift-C)</h3>
43 <h3>pickallattrs (Shift-C)</h3>
44 <p>Pick the complete column under the cursor (i.e. the attribute under the
44 <p>Pick the complete column under the cursor (i.e. the attribute under the
45 cursor) from all currently fetched objects. These attributes will be returned
45 cursor) from all currently fetched objects. These attributes will be returned
46 as a list.</p>
46 as a list.</p>
47
47
48 <h3>pickinput (I)</h3>
48 <h3>pickinput (I)</h3>
49 <p>Pick the current row as next input line in IPython. Additionally the row is stored as "_"</p>
49 <p>Pick the current row as next input line in IPython. Additionally the row is stored as "_"</p>
50
50
51 <h3>pickinputattr (Shift-I)</h3>
51 <h3>pickinputattr (Shift-I)</h3>
52 <p>Pick the attribute under the cursor as next input line in IPython. Additionally the row is stored as "_"</p>
52 <p>Pick the attribute under the cursor as next input line in IPython. Additionally the row is stored as "_"</p>
53
53
54 <h3>enter (E)</h3>
54 <h3>enter (E)</h3>
55 <p>Enter the object under the cursor. (what this mean depends on the object
55 <p>Enter the object under the cursor. (what this mean depends on the object
56 itself, i.e. how it implements iteration). This opens a new browser 'level'.</p>
56 itself, i.e. how it implements iteration). This opens a new browser 'level'.</p>
57
57
58 <h3>enterattr (Shift-E)</h3>
58 <h3>enterattr (Shift-E)</h3>
59 <p>Enter the attribute under the cursor.</p>
59 <p>Enter the attribute under the cursor.</p>
60
60
61 <h3>detail (D)</h3>
61 <h3>detail (D)</h3>
62 <p>Show a detail view of the object under the cursor. This shows the name,
62 <p>Show a detail view of the object under the cursor. This shows the name,
63 type, doc string and value of the object attributes (and it might show more
63 type, doc string and value of the object attributes (and it might show more
64 attributes than in the list view, depending on the object).</p>
64 attributes than in the list view, depending on the object).</p>
65
65
66 <h3>detailattr (Shift-D)</h3>
66 <h3>detailattr (Shift-D)</h3>
67 <p>Show a detail view of the attribute under the cursor.</p>
67 <p>Show a detail view of the attribute under the cursor.</p>
68
68
69 <h3>pickrows (M)</h3>
69 <h3>pickrows (M)</h3>
70 <p>Pick multiple selected rows (M)</p>
70 <p>Pick multiple selected rows (M)</p>
71
71
72 <h3>pickrowsattr (CTRL-M)</h3>
72 <h3>pickrowsattr (CTRL-M)</h3>
73 <p>From multiple selected rows pick the cells matching the attribute the cursor is in (CTRL-M)</p>
73 <p>From multiple selected rows pick the cells matching the attribute the cursor is in (CTRL-M)</p>
74
74
75 <h3>find (CTRL-F)</h3>
75 <h3>find (CTRL-F)</h3>
76 <p>Find text</p>
76 <p>Find text</p>
77
77
78 <h3>find_expression (CTRL-Shift-F)</h3>
78 <h3>find_expression (CTRL-Shift-F)</h3>
79 <p>Find entries matching an expression</p>
79 <p>Find entries matching an expression</p>
80
80
81 <h3>find_next (F3)</h3>
81 <h3>find_next (F3)</h3>
82 <p>Find next occurrence</p>
82 <p>Find next occurrence</p>
83
83
84 <h3>find_previous (Shift-F3)</h3>
84 <h3>find_previous (Shift-F3)</h3>
85 <p>Find previous occurrence</p>
85 <p>Find previous occurrence</p>
86
86
87 <h3>sortattrasc (V)</h3>
87 <h3>sortattrasc (V)</h3>
88 <p>Sort the objects (in ascending order) using the attribute under the cursor as the sort key.</p>
88 <p>Sort the objects (in ascending order) using the attribute under the cursor as the sort key.</p>
89
89
90 <h3>sortattrdesc (Shift-V)</h3>
90 <h3>sortattrdesc (Shift-V)</h3>
91 <p>Sort the objects (in descending order) using the attribute under the cursor as the sort key.</p>
91 <p>Sort the objects (in descending order) using the attribute under the cursor as the sort key.</p>
92
92
93 <h3>refresh_once (R, F5)</h3>
93 <h3>refresh_once (R, F5)</h3>
94 <p>Refreshes the display by restarting the iterator</p>
94 <p>Refreshes the display by restarting the iterator</p>
95
95
96 <h3>refresh_every_second</h3>
96 <h3>refresh_every_second</h3>
97 <p>Refreshes the display by restarting the iterator every second until stopped by stop_refresh.</p>
97 <p>Refreshes the display by restarting the iterator every second until stopped by stop_refresh.</p>
98
98
99 <h3>refresh_interval</h3>
99 <h3>refresh_interval</h3>
100 <p>Refreshes the display by restarting the iterator every X ms (X is a custom interval set by the user) until stopped by stop_refresh.</p>
100 <p>Refreshes the display by restarting the iterator every X ms (X is a custom interval set by the user) until stopped by stop_refresh.</p>
101
101
102 <h3>stop_refresh</h3>
102 <h3>stop_refresh</h3>
103 <p>Stops all refresh timers.</p>
103 <p>Stops all refresh timers.</p>
104
104
105 <h3>leave (Backspace, DEL, X)</h3>
105 <h3>leave (Backspace, DEL, X)</h3>
106 <p>Close current tab (and all the tabs to the right of the current one).</h3>
106 <p>Close current tab (and all the tabs to the right of the current one).</h3>
107
107
108 <h3>quit (ESC,Q)</h3>
108 <h3>quit (ESC,Q)</h3>
109 <p>Quit igrid and return to the IPython prompt.</p>
109 <p>Quit igrid and return to the IPython prompt.</p>
110
110
111
111
112 <h2>Navigation</h2>
112 <h2>Navigation</h2>
113
113
114
114
115 <h3>Jump to the last column of the current row (END, CTRL-E, CTRL-Right)</h3>
115 <h3>Jump to the last column of the current row (END, CTRL-E, CTRL-Right)</h3>
116
116
117 <h3>Jump to the first column of the current row (HOME, CTRL-A, CTRL-Left)</h3>
117 <h3>Jump to the first column of the current row (HOME, CTRL-A, CTRL-Left)</h3>
118
118
119 <h3>Move the cursor one column to the left (&lt;)</h3>
119 <h3>Move the cursor one column to the left (&lt;)</h3>
120
120
121 <h3>Move the cursor one column to the right (&gt;)</h3>
121 <h3>Move the cursor one column to the right (&gt;)</h3>
122
122
123 <h3>Jump to the first row in the current column (CTRL-Up)</h3>
123 <h3>Jump to the first row in the current column (CTRL-Up)</h3>
124
124
125 <h3>Jump to the last row in the current column (CTRL-Down)</h3>
125 <h3>Jump to the last row in the current column (CTRL-Down)</h3>
126
126
127 </body>
127 </body>
128 </html>
128 </html>
129
129
130 """
130 """
131
131
132
132
133 class IGridRenderer(wx.grid.PyGridCellRenderer):
133 class IGridRenderer(wx.grid.PyGridCellRenderer):
134 """
134 """
135 This is a custom renderer for our IGridGrid
135 This is a custom renderer for our IGridGrid
136 """
136 """
137 def __init__(self, table):
137 def __init__(self, table):
138 self.maxchars = 200
138 self.maxchars = 200
139 self.table = table
139 self.table = table
140 self.colormap = (
140 self.colormap = (
141 ( 0, 0, 0),
141 ( 0, 0, 0),
142 (174, 0, 0),
142 (174, 0, 0),
143 ( 0, 174, 0),
143 ( 0, 174, 0),
144 (174, 174, 0),
144 (174, 174, 0),
145 ( 0, 0, 174),
145 ( 0, 0, 174),
146 (174, 0, 174),
146 (174, 0, 174),
147 ( 0, 174, 174),
147 ( 0, 174, 174),
148 ( 64, 64, 64)
148 ( 64, 64, 64)
149 )
149 )
150
150
151 wx.grid.PyGridCellRenderer.__init__(self)
151 wx.grid.PyGridCellRenderer.__init__(self)
152
152
153 def _getvalue(self, row, col):
153 def _getvalue(self, row, col):
154 try:
154 try:
155 value = self.table._displayattrs[col].value(self.table.items[row])
155 value = self.table._displayattrs[col].value(self.table.items[row])
156 (align, width, text) = ipipe.xformat(value, "cell", self.maxchars)
156 (align, width, text) = ipipe.xformat(value, "cell", self.maxchars)
157 except Exception, exc:
157 except Exception as exc:
158 (align, width, text) = ipipe.xformat(exc, "cell", self.maxchars)
158 (align, width, text) = ipipe.xformat(exc, "cell", self.maxchars)
159 return (align, text)
159 return (align, text)
160
160
161 def GetBestSize(self, grid, attr, dc, row, col):
161 def GetBestSize(self, grid, attr, dc, row, col):
162 text = grid.GetCellValue(row, col)
162 text = grid.GetCellValue(row, col)
163 (align, text) = self._getvalue(row, col)
163 (align, text) = self._getvalue(row, col)
164 dc.SetFont(attr.GetFont())
164 dc.SetFont(attr.GetFont())
165 (w, h) = dc.GetTextExtent(str(text))
165 (w, h) = dc.GetTextExtent(str(text))
166 return wx.Size(min(w+2, 600), h+2) # add border
166 return wx.Size(min(w+2, 600), h+2) # add border
167
167
168 def Draw(self, grid, attr, dc, rect, row, col, isSelected):
168 def Draw(self, grid, attr, dc, rect, row, col, isSelected):
169 """
169 """
170 Takes care of drawing everything in the cell; aligns the text
170 Takes care of drawing everything in the cell; aligns the text
171 """
171 """
172 text = grid.GetCellValue(row, col)
172 text = grid.GetCellValue(row, col)
173 (align, text) = self._getvalue(row, col)
173 (align, text) = self._getvalue(row, col)
174 if isSelected:
174 if isSelected:
175 bg = grid.GetSelectionBackground()
175 bg = grid.GetSelectionBackground()
176 else:
176 else:
177 bg = ["white", (240, 240, 240)][row%2]
177 bg = ["white", (240, 240, 240)][row%2]
178 dc.SetTextBackground(bg)
178 dc.SetTextBackground(bg)
179 dc.SetBrush(wx.Brush(bg, wx.SOLID))
179 dc.SetBrush(wx.Brush(bg, wx.SOLID))
180 dc.SetPen(wx.TRANSPARENT_PEN)
180 dc.SetPen(wx.TRANSPARENT_PEN)
181 dc.SetFont(attr.GetFont())
181 dc.SetFont(attr.GetFont())
182 dc.DrawRectangleRect(rect)
182 dc.DrawRectangleRect(rect)
183 dc.SetClippingRect(rect)
183 dc.SetClippingRect(rect)
184 # Format the text
184 # Format the text
185 if align == -1: # left alignment
185 if align == -1: # left alignment
186 (width, height) = dc.GetTextExtent(str(text))
186 (width, height) = dc.GetTextExtent(str(text))
187 x = rect[0]+1
187 x = rect[0]+1
188 y = rect[1]+0.5*(rect[3]-height)
188 y = rect[1]+0.5*(rect[3]-height)
189
189
190 for (style, part) in text:
190 for (style, part) in text:
191 if isSelected:
191 if isSelected:
192 fg = grid.GetSelectionForeground()
192 fg = grid.GetSelectionForeground()
193 else:
193 else:
194 fg = self.colormap[style.fg]
194 fg = self.colormap[style.fg]
195 dc.SetTextForeground(fg)
195 dc.SetTextForeground(fg)
196 (w, h) = dc.GetTextExtent(part)
196 (w, h) = dc.GetTextExtent(part)
197 dc.DrawText(part, x, y)
197 dc.DrawText(part, x, y)
198 x += w
198 x += w
199 elif align == 0: # center alignment
199 elif align == 0: # center alignment
200 (width, height) = dc.GetTextExtent(str(text))
200 (width, height) = dc.GetTextExtent(str(text))
201 x = rect[0]+0.5*(rect[2]-width)
201 x = rect[0]+0.5*(rect[2]-width)
202 y = rect[1]+0.5*(rect[3]-height)
202 y = rect[1]+0.5*(rect[3]-height)
203 for (style, part) in text:
203 for (style, part) in text:
204 if isSelected:
204 if isSelected:
205 fg = grid.GetSelectionForeground()
205 fg = grid.GetSelectionForeground()
206 else:
206 else:
207 fg = self.colormap[style.fg]
207 fg = self.colormap[style.fg]
208 dc.SetTextForeground(fg)
208 dc.SetTextForeground(fg)
209 (w, h) = dc.GetTextExtent(part)
209 (w, h) = dc.GetTextExtent(part)
210 dc.DrawText(part, x, y)
210 dc.DrawText(part, x, y)
211 x += w
211 x += w
212 else: # right alignment
212 else: # right alignment
213 (width, height) = dc.GetTextExtent(str(text))
213 (width, height) = dc.GetTextExtent(str(text))
214 x = rect[0]+rect[2]-1
214 x = rect[0]+rect[2]-1
215 y = rect[1]+0.5*(rect[3]-height)
215 y = rect[1]+0.5*(rect[3]-height)
216 for (style, part) in reversed(text):
216 for (style, part) in reversed(text):
217 (w, h) = dc.GetTextExtent(part)
217 (w, h) = dc.GetTextExtent(part)
218 x -= w
218 x -= w
219 if isSelected:
219 if isSelected:
220 fg = grid.GetSelectionForeground()
220 fg = grid.GetSelectionForeground()
221 else:
221 else:
222 fg = self.colormap[style.fg]
222 fg = self.colormap[style.fg]
223 dc.SetTextForeground(fg)
223 dc.SetTextForeground(fg)
224 dc.DrawText(part, x, y)
224 dc.DrawText(part, x, y)
225 dc.DestroyClippingRegion()
225 dc.DestroyClippingRegion()
226
226
227 def Clone(self):
227 def Clone(self):
228 return IGridRenderer(self.table)
228 return IGridRenderer(self.table)
229
229
230
230
231 class IGridTable(wx.grid.PyGridTableBase):
231 class IGridTable(wx.grid.PyGridTableBase):
232 # The data table for the ``IGridGrid``. Some dirty tricks were used here:
232 # The data table for the ``IGridGrid``. Some dirty tricks were used here:
233 # ``GetValue()`` does not get any values (or at least it does not return
233 # ``GetValue()`` does not get any values (or at least it does not return
234 # anything, accessing the values is done by the renderer)
234 # anything, accessing the values is done by the renderer)
235 # but rather tries to fetch the objects which were requested into the table.
235 # but rather tries to fetch the objects which were requested into the table.
236 # General behaviour is: Fetch the first X objects. If the user scrolls down
236 # General behaviour is: Fetch the first X objects. If the user scrolls down
237 # to the last object another bunch of X objects is fetched (if possible)
237 # to the last object another bunch of X objects is fetched (if possible)
238 def __init__(self, input, fontsize, *attrs):
238 def __init__(self, input, fontsize, *attrs):
239 wx.grid.PyGridTableBase.__init__(self)
239 wx.grid.PyGridTableBase.__init__(self)
240 self.input = input
240 self.input = input
241 self.iterator = ipipe.xiter(input)
241 self.iterator = ipipe.xiter(input)
242 self.items = []
242 self.items = []
243 self.attrs = [ipipe.upgradexattr(attr) for attr in attrs]
243 self.attrs = [ipipe.upgradexattr(attr) for attr in attrs]
244 self._displayattrs = self.attrs[:]
244 self._displayattrs = self.attrs[:]
245 self._displayattrset = set(self.attrs)
245 self._displayattrset = set(self.attrs)
246 self.fontsize = fontsize
246 self.fontsize = fontsize
247 self._fetch(1)
247 self._fetch(1)
248 self.timer = wx.Timer()
248 self.timer = wx.Timer()
249 self.timer.Bind(wx.EVT_TIMER, self.refresh_content)
249 self.timer.Bind(wx.EVT_TIMER, self.refresh_content)
250
250
251 def GetAttr(self, *args):
251 def GetAttr(self, *args):
252 attr = wx.grid.GridCellAttr()
252 attr = wx.grid.GridCellAttr()
253 attr.SetFont(wx.Font(self.fontsize, wx.TELETYPE, wx.NORMAL, wx.NORMAL))
253 attr.SetFont(wx.Font(self.fontsize, wx.TELETYPE, wx.NORMAL, wx.NORMAL))
254 return attr
254 return attr
255
255
256 def GetNumberRows(self):
256 def GetNumberRows(self):
257 return len(self.items)
257 return len(self.items)
258
258
259 def GetNumberCols(self):
259 def GetNumberCols(self):
260 return len(self._displayattrs)
260 return len(self._displayattrs)
261
261
262 def GetColLabelValue(self, col):
262 def GetColLabelValue(self, col):
263 if col < len(self._displayattrs):
263 if col < len(self._displayattrs):
264 return self._displayattrs[col].name()
264 return self._displayattrs[col].name()
265 else:
265 else:
266 return ""
266 return ""
267
267
268 def GetRowLabelValue(self, row):
268 def GetRowLabelValue(self, row):
269 return str(row)
269 return str(row)
270
270
271 def IsEmptyCell(self, row, col):
271 def IsEmptyCell(self, row, col):
272 return False
272 return False
273
273
274 def _append(self, item):
274 def _append(self, item):
275 self.items.append(item)
275 self.items.append(item)
276 # Nothing to do if the set of attributes has been fixed by the user
276 # Nothing to do if the set of attributes has been fixed by the user
277 if not self.attrs:
277 if not self.attrs:
278 for attr in ipipe.xattrs(item):
278 for attr in ipipe.xattrs(item):
279 attr = ipipe.upgradexattr(attr)
279 attr = ipipe.upgradexattr(attr)
280 if attr not in self._displayattrset:
280 if attr not in self._displayattrset:
281 self._displayattrs.append(attr)
281 self._displayattrs.append(attr)
282 self._displayattrset.add(attr)
282 self._displayattrset.add(attr)
283
283
284 def _fetch(self, count):
284 def _fetch(self, count):
285 # Try to fill ``self.items`` with at least ``count`` objects.
285 # Try to fill ``self.items`` with at least ``count`` objects.
286 have = len(self.items)
286 have = len(self.items)
287 while self.iterator is not None and have < count:
287 while self.iterator is not None and have < count:
288 try:
288 try:
289 item = self.iterator.next()
289 item = self.iterator.next()
290 except StopIteration:
290 except StopIteration:
291 self.iterator = None
291 self.iterator = None
292 break
292 break
293 except (KeyboardInterrupt, SystemExit):
293 except (KeyboardInterrupt, SystemExit):
294 raise
294 raise
295 except Exception, exc:
295 except Exception as exc:
296 have += 1
296 have += 1
297 self._append(exc)
297 self._append(exc)
298 self.iterator = None
298 self.iterator = None
299 break
299 break
300 else:
300 else:
301 have += 1
301 have += 1
302 self._append(item)
302 self._append(item)
303
303
304 def GetValue(self, row, col):
304 def GetValue(self, row, col):
305 # some kind of dummy-function: does not return anything but "";
305 # some kind of dummy-function: does not return anything but "";
306 # (The value isn't use anyway)
306 # (The value isn't use anyway)
307 # its main task is to trigger the fetch of new objects
307 # its main task is to trigger the fetch of new objects
308 sizing_needed = False
308 sizing_needed = False
309 had_cols = len(self._displayattrs)
309 had_cols = len(self._displayattrs)
310 had_rows = len(self.items)
310 had_rows = len(self.items)
311 if row == had_rows - 1 and self.iterator is not None:
311 if row == had_rows - 1 and self.iterator is not None:
312 self._fetch(row + 20)
312 self._fetch(row + 20)
313 sizing_needed = True
313 sizing_needed = True
314 have_rows = len(self.items)
314 have_rows = len(self.items)
315 have_cols = len(self._displayattrs)
315 have_cols = len(self._displayattrs)
316 if have_rows > had_rows:
316 if have_rows > had_rows:
317 msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED, have_rows - had_rows)
317 msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED, have_rows - had_rows)
318 self.GetView().ProcessTableMessage(msg)
318 self.GetView().ProcessTableMessage(msg)
319 sizing_needed = True
319 sizing_needed = True
320 if row >= have_rows:
320 if row >= have_rows:
321 return ""
321 return ""
322 if have_cols != had_cols:
322 if have_cols != had_cols:
323 msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED, have_cols - had_cols)
323 msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED, have_cols - had_cols)
324 self.GetView().ProcessTableMessage(msg)
324 self.GetView().ProcessTableMessage(msg)
325 sizing_needed = True
325 sizing_needed = True
326 if sizing_needed:
326 if sizing_needed:
327 self.GetView().AutoSizeColumns(False)
327 self.GetView().AutoSizeColumns(False)
328 return ""
328 return ""
329
329
330 def SetValue(self, row, col, value):
330 def SetValue(self, row, col, value):
331 pass
331 pass
332
332
333 def refresh_content(self, event):
333 def refresh_content(self, event):
334 msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, 0, self.GetNumberRows())
334 msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, 0, self.GetNumberRows())
335 self.GetView().ProcessTableMessage(msg)
335 self.GetView().ProcessTableMessage(msg)
336 self.iterator = ipipe.xiter(self.input)
336 self.iterator = ipipe.xiter(self.input)
337 self.items = []
337 self.items = []
338 self.attrs = [] # _append will calculate new displayattrs
338 self.attrs = [] # _append will calculate new displayattrs
339 self._fetch(1) # fetch one...
339 self._fetch(1) # fetch one...
340 if self.items:
340 if self.items:
341 msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED, 1)
341 msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED, 1)
342 self.GetView().ProcessTableMessage(msg)
342 self.GetView().ProcessTableMessage(msg)
343 self.GetValue(0, 0) # and trigger "fetch next 20"
343 self.GetValue(0, 0) # and trigger "fetch next 20"
344 item = self.items[0]
344 item = self.items[0]
345 self.GetView().AutoSizeColumns(False)
345 self.GetView().AutoSizeColumns(False)
346 panel = self.GetView().GetParent()
346 panel = self.GetView().GetParent()
347 nb = panel.GetParent()
347 nb = panel.GetParent()
348 current = nb.GetSelection()
348 current = nb.GetSelection()
349 if nb.GetPage(current) == panel:
349 if nb.GetPage(current) == panel:
350 self.GetView().set_footer(item)
350 self.GetView().set_footer(item)
351
351
352 class IGridGrid(wx.grid.Grid):
352 class IGridGrid(wx.grid.Grid):
353 # The actual grid
353 # The actual grid
354 # all methods for selecting/sorting/picking/... data are implemented here
354 # all methods for selecting/sorting/picking/... data are implemented here
355 def __init__(self, panel, input, *attrs):
355 def __init__(self, panel, input, *attrs):
356 wx.grid.Grid.__init__(self, panel)
356 wx.grid.Grid.__init__(self, panel)
357 fontsize = 9
357 fontsize = 9
358 self.input = input
358 self.input = input
359 self.table = IGridTable(self.input, fontsize, *attrs)
359 self.table = IGridTable(self.input, fontsize, *attrs)
360 self.SetTable(self.table, True)
360 self.SetTable(self.table, True)
361 self.SetSelectionMode(wx.grid.Grid.wxGridSelectRows)
361 self.SetSelectionMode(wx.grid.Grid.wxGridSelectRows)
362 self.SetDefaultRenderer(IGridRenderer(self.table))
362 self.SetDefaultRenderer(IGridRenderer(self.table))
363 self.EnableEditing(False)
363 self.EnableEditing(False)
364 self.Bind(wx.EVT_KEY_DOWN, self.key_pressed)
364 self.Bind(wx.EVT_KEY_DOWN, self.key_pressed)
365 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.cell_doubleclicked)
365 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.cell_doubleclicked)
366 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.cell_leftclicked)
366 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.cell_leftclicked)
367 self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_DCLICK, self.label_doubleclicked)
367 self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_DCLICK, self.label_doubleclicked)
368 self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.on_label_leftclick)
368 self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.on_label_leftclick)
369 self.Bind(wx.grid.EVT_GRID_RANGE_SELECT, self._on_selected_range)
369 self.Bind(wx.grid.EVT_GRID_RANGE_SELECT, self._on_selected_range)
370 self.Bind(wx.grid.EVT_GRID_SELECT_CELL, self._on_selected_cell)
370 self.Bind(wx.grid.EVT_GRID_SELECT_CELL, self._on_selected_cell)
371 self.current_selection = set()
371 self.current_selection = set()
372 self.maxchars = 200
372 self.maxchars = 200
373
373
374 def on_label_leftclick(self, event):
374 def on_label_leftclick(self, event):
375 event.Skip()
375 event.Skip()
376
376
377 def error_output(self, text):
377 def error_output(self, text):
378 wx.Bell()
378 wx.Bell()
379 frame = self.GetParent().GetParent().GetParent()
379 frame = self.GetParent().GetParent().GetParent()
380 frame.SetStatusText(str(text))
380 frame.SetStatusText(str(text))
381
381
382 def _on_selected_range(self, event):
382 def _on_selected_range(self, event):
383 # Internal update to the selection tracking lists
383 # Internal update to the selection tracking lists
384 if event.Selecting():
384 if event.Selecting():
385 # adding to the list...
385 # adding to the list...
386 self.current_selection.update(xrange(event.GetTopRow(), event.GetBottomRow()+1))
386 self.current_selection.update(xrange(event.GetTopRow(), event.GetBottomRow()+1))
387 else:
387 else:
388 # removal from list
388 # removal from list
389 for index in xrange(event.GetTopRow(), event.GetBottomRow()+1):
389 for index in xrange(event.GetTopRow(), event.GetBottomRow()+1):
390 self.current_selection.discard(index)
390 self.current_selection.discard(index)
391 event.Skip()
391 event.Skip()
392
392
393 def _on_selected_cell(self, event):
393 def _on_selected_cell(self, event):
394 # Internal update to the selection tracking list
394 # Internal update to the selection tracking list
395 self.current_selection = set([event.GetRow()])
395 self.current_selection = set([event.GetRow()])
396 event.Skip()
396 event.Skip()
397
397
398 def sort(self, key, reverse=False):
398 def sort(self, key, reverse=False):
399 """
399 """
400 Sort the current list of items using the key function ``key``. If
400 Sort the current list of items using the key function ``key``. If
401 ``reverse`` is true the sort order is reversed.
401 ``reverse`` is true the sort order is reversed.
402 """
402 """
403 row = self.GetGridCursorRow()
403 row = self.GetGridCursorRow()
404 col = self.GetGridCursorCol()
404 col = self.GetGridCursorCol()
405 curitem = self.table.items[row] # Remember where the cursor is now
405 curitem = self.table.items[row] # Remember where the cursor is now
406 # Sort items
406 # Sort items
407 def realkey(item):
407 def realkey(item):
408 try:
408 try:
409 return key(item)
409 return key(item)
410 except (KeyboardInterrupt, SystemExit):
410 except (KeyboardInterrupt, SystemExit):
411 raise
411 raise
412 except Exception:
412 except Exception:
413 return None
413 return None
414 try:
414 try:
415 self.table.items = ipipe.deque(sorted(self.table.items, key=realkey, reverse=reverse))
415 self.table.items = ipipe.deque(sorted(self.table.items, key=realkey, reverse=reverse))
416 except TypeError, exc:
416 except TypeError as exc:
417 self.error_output("Exception encountered: %s" % exc)
417 self.error_output("Exception encountered: %s" % exc)
418 return
418 return
419 # Find out where the object under the cursor went
419 # Find out where the object under the cursor went
420 for (i, item) in enumerate(self.table.items):
420 for (i, item) in enumerate(self.table.items):
421 if item is curitem:
421 if item is curitem:
422 self.SetGridCursor(i,col)
422 self.SetGridCursor(i,col)
423 self.MakeCellVisible(i,col)
423 self.MakeCellVisible(i,col)
424 self.Refresh()
424 self.Refresh()
425
425
426 def sortattrasc(self):
426 def sortattrasc(self):
427 """
427 """
428 Sort in ascending order; sorting criteria is the current attribute
428 Sort in ascending order; sorting criteria is the current attribute
429 """
429 """
430 col = self.GetGridCursorCol()
430 col = self.GetGridCursorCol()
431 attr = self.table._displayattrs[col]
431 attr = self.table._displayattrs[col]
432 frame = self.GetParent().GetParent().GetParent()
432 frame = self.GetParent().GetParent().GetParent()
433 if attr is ipipe.noitem:
433 if attr is ipipe.noitem:
434 self.error_output("no column under cursor")
434 self.error_output("no column under cursor")
435 return
435 return
436 frame.SetStatusText("sort by %s (ascending)" % attr.name())
436 frame.SetStatusText("sort by %s (ascending)" % attr.name())
437 def key(item):
437 def key(item):
438 try:
438 try:
439 return attr.value(item)
439 return attr.value(item)
440 except (KeyboardInterrupt, SystemExit):
440 except (KeyboardInterrupt, SystemExit):
441 raise
441 raise
442 except Exception:
442 except Exception:
443 return None
443 return None
444 self.sort(key)
444 self.sort(key)
445
445
446 def sortattrdesc(self):
446 def sortattrdesc(self):
447 """
447 """
448 Sort in descending order; sorting criteria is the current attribute
448 Sort in descending order; sorting criteria is the current attribute
449 """
449 """
450 col = self.GetGridCursorCol()
450 col = self.GetGridCursorCol()
451 attr = self.table._displayattrs[col]
451 attr = self.table._displayattrs[col]
452 frame = self.GetParent().GetParent().GetParent()
452 frame = self.GetParent().GetParent().GetParent()
453 if attr is ipipe.noitem:
453 if attr is ipipe.noitem:
454 self.error_output("no column under cursor")
454 self.error_output("no column under cursor")
455 return
455 return
456 frame.SetStatusText("sort by %s (descending)" % attr.name())
456 frame.SetStatusText("sort by %s (descending)" % attr.name())
457 def key(item):
457 def key(item):
458 try:
458 try:
459 return attr.value(item)
459 return attr.value(item)
460 except (KeyboardInterrupt, SystemExit):
460 except (KeyboardInterrupt, SystemExit):
461 raise
461 raise
462 except Exception:
462 except Exception:
463 return None
463 return None
464 self.sort(key, reverse=True)
464 self.sort(key, reverse=True)
465
465
466 def label_doubleclicked(self, event):
466 def label_doubleclicked(self, event):
467 row = event.GetRow()
467 row = event.GetRow()
468 col = event.GetCol()
468 col = event.GetCol()
469 if col == -1:
469 if col == -1:
470 self.enter(row)
470 self.enter(row)
471
471
472 def _getvalue(self, row, col):
472 def _getvalue(self, row, col):
473 """
473 """
474 Gets the text which is displayed at ``(row, col)``
474 Gets the text which is displayed at ``(row, col)``
475 """
475 """
476 try:
476 try:
477 value = self.table._displayattrs[col].value(self.table.items[row])
477 value = self.table._displayattrs[col].value(self.table.items[row])
478 (align, width, text) = ipipe.xformat(value, "cell", self.maxchars)
478 (align, width, text) = ipipe.xformat(value, "cell", self.maxchars)
479 except IndexError:
479 except IndexError:
480 raise IndexError
480 raise IndexError
481 except Exception, exc:
481 except Exception as exc:
482 (align, width, text) = ipipe.xformat(exc, "cell", self.maxchars)
482 (align, width, text) = ipipe.xformat(exc, "cell", self.maxchars)
483 return text
483 return text
484
484
485 def searchexpression(self, searchexp, startrow=None, search_forward=True ):
485 def searchexpression(self, searchexp, startrow=None, search_forward=True ):
486 """
486 """
487 Find by expression
487 Find by expression
488 """
488 """
489 frame = self.GetParent().GetParent().GetParent()
489 frame = self.GetParent().GetParent().GetParent()
490 if searchexp:
490 if searchexp:
491 if search_forward:
491 if search_forward:
492 if not startrow:
492 if not startrow:
493 row = self.GetGridCursorRow()+1
493 row = self.GetGridCursorRow()+1
494 else:
494 else:
495 row = startrow + 1
495 row = startrow + 1
496 while True:
496 while True:
497 try:
497 try:
498 foo = self.table.GetValue(row, 0)
498 foo = self.table.GetValue(row, 0)
499 item = self.table.items[row]
499 item = self.table.items[row]
500 try:
500 try:
501 globals = ipipe.getglobals(None)
501 globals = ipipe.getglobals(None)
502 if eval(searchexp, globals, ipipe.AttrNamespace(item)):
502 if eval(searchexp, globals, ipipe.AttrNamespace(item)):
503 self.SetGridCursor(row, 0) # found something
503 self.SetGridCursor(row, 0) # found something
504 self.MakeCellVisible(row, 0)
504 self.MakeCellVisible(row, 0)
505 break
505 break
506 except (KeyboardInterrupt, SystemExit):
506 except (KeyboardInterrupt, SystemExit):
507 raise
507 raise
508 except Exception, exc:
508 except Exception as exc:
509 frame.SetStatusText(str(exc))
509 frame.SetStatusText(str(exc))
510 wx.Bell()
510 wx.Bell()
511 break # break on error
511 break # break on error
512 except IndexError:
512 except IndexError:
513 return
513 return
514 row += 1
514 row += 1
515 else:
515 else:
516 if not startrow:
516 if not startrow:
517 row = self.GetGridCursorRow() - 1
517 row = self.GetGridCursorRow() - 1
518 else:
518 else:
519 row = startrow - 1
519 row = startrow - 1
520 while True:
520 while True:
521 try:
521 try:
522 foo = self.table.GetValue(row, 0)
522 foo = self.table.GetValue(row, 0)
523 item = self.table.items[row]
523 item = self.table.items[row]
524 try:
524 try:
525 globals = ipipe.getglobals(None)
525 globals = ipipe.getglobals(None)
526 if eval(searchexp, globals, ipipe.AttrNamespace(item)):
526 if eval(searchexp, globals, ipipe.AttrNamespace(item)):
527 self.SetGridCursor(row, 0) # found something
527 self.SetGridCursor(row, 0) # found something
528 self.MakeCellVisible(row, 0)
528 self.MakeCellVisible(row, 0)
529 break
529 break
530 except (KeyboardInterrupt, SystemExit):
530 except (KeyboardInterrupt, SystemExit):
531 raise
531 raise
532 except Exception, exc:
532 except Exception as exc:
533 frame.SetStatusText(str(exc))
533 frame.SetStatusText(str(exc))
534 wx.Bell()
534 wx.Bell()
535 break # break on error
535 break # break on error
536 except IndexError:
536 except IndexError:
537 return
537 return
538 row -= 1
538 row -= 1
539
539
540
540
541 def search(self, searchtext, startrow=None, startcol=None, search_forward=True):
541 def search(self, searchtext, startrow=None, startcol=None, search_forward=True):
542 """
542 """
543 search for ``searchtext``, starting in ``(startrow, startcol)``;
543 search for ``searchtext``, starting in ``(startrow, startcol)``;
544 if ``search_forward`` is true the direction is "forward"
544 if ``search_forward`` is true the direction is "forward"
545 """
545 """
546 searchtext = searchtext.lower()
546 searchtext = searchtext.lower()
547 if search_forward:
547 if search_forward:
548 if startrow is not None and startcol is not None:
548 if startrow is not None and startcol is not None:
549 row = startrow
549 row = startrow
550 else:
550 else:
551 startcol = self.GetGridCursorCol() + 1
551 startcol = self.GetGridCursorCol() + 1
552 row = self.GetGridCursorRow()
552 row = self.GetGridCursorRow()
553 if startcol >= self.GetNumberCols():
553 if startcol >= self.GetNumberCols():
554 startcol = 0
554 startcol = 0
555 row += 1
555 row += 1
556 while True:
556 while True:
557 for col in xrange(startcol, self.table.GetNumberCols()):
557 for col in xrange(startcol, self.table.GetNumberCols()):
558 try:
558 try:
559 foo = self.table.GetValue(row, col)
559 foo = self.table.GetValue(row, col)
560 text = self._getvalue(row, col)
560 text = self._getvalue(row, col)
561 if searchtext in text.string().lower():
561 if searchtext in text.string().lower():
562 self.SetGridCursor(row, col)
562 self.SetGridCursor(row, col)
563 self.MakeCellVisible(row, col)
563 self.MakeCellVisible(row, col)
564 return
564 return
565 except IndexError:
565 except IndexError:
566 return
566 return
567 startcol = 0
567 startcol = 0
568 row += 1
568 row += 1
569 else:
569 else:
570 if startrow is not None and startcol is not None:
570 if startrow is not None and startcol is not None:
571 row = startrow
571 row = startrow
572 else:
572 else:
573 startcol = self.GetGridCursorCol() - 1
573 startcol = self.GetGridCursorCol() - 1
574 row = self.GetGridCursorRow()
574 row = self.GetGridCursorRow()
575 if startcol < 0:
575 if startcol < 0:
576 startcol = self.GetNumberCols() - 1
576 startcol = self.GetNumberCols() - 1
577 row -= 1
577 row -= 1
578 while True:
578 while True:
579 for col in xrange(startcol, -1, -1):
579 for col in xrange(startcol, -1, -1):
580 try:
580 try:
581 foo = self.table.GetValue(row, col)
581 foo = self.table.GetValue(row, col)
582 text = self._getvalue(row, col)
582 text = self._getvalue(row, col)
583 if searchtext in text.string().lower():
583 if searchtext in text.string().lower():
584 self.SetGridCursor(row, col)
584 self.SetGridCursor(row, col)
585 self.MakeCellVisible(row, col)
585 self.MakeCellVisible(row, col)
586 return
586 return
587 except IndexError:
587 except IndexError:
588 return
588 return
589 startcol = self.table.GetNumberCols()-1
589 startcol = self.table.GetNumberCols()-1
590 row -= 1
590 row -= 1
591
591
592 def key_pressed(self, event):
592 def key_pressed(self, event):
593 """
593 """
594 Maps pressed keys to functions
594 Maps pressed keys to functions
595 """
595 """
596 frame = self.GetParent().GetParent().GetParent()
596 frame = self.GetParent().GetParent().GetParent()
597 frame.SetStatusText("")
597 frame.SetStatusText("")
598 sh = event.ShiftDown()
598 sh = event.ShiftDown()
599 ctrl = event.ControlDown()
599 ctrl = event.ControlDown()
600
600
601 keycode = event.GetKeyCode()
601 keycode = event.GetKeyCode()
602 if keycode == ord("P"):
602 if keycode == ord("P"):
603 row = self.GetGridCursorRow()
603 row = self.GetGridCursorRow()
604 if sh:
604 if sh:
605 col = self.GetGridCursorCol()
605 col = self.GetGridCursorCol()
606 self.pickattr(row, col)
606 self.pickattr(row, col)
607 else:
607 else:
608 self.pick(row)
608 self.pick(row)
609 elif keycode == ord("M"):
609 elif keycode == ord("M"):
610 if ctrl:
610 if ctrl:
611 col = self.GetGridCursorCol()
611 col = self.GetGridCursorCol()
612 self.pickrowsattr(sorted(self.current_selection), col)
612 self.pickrowsattr(sorted(self.current_selection), col)
613 else:
613 else:
614 self.pickrows(sorted(self.current_selection))
614 self.pickrows(sorted(self.current_selection))
615 elif keycode in (wx.WXK_BACK, wx.WXK_DELETE, ord("X")) and not (ctrl or sh):
615 elif keycode in (wx.WXK_BACK, wx.WXK_DELETE, ord("X")) and not (ctrl or sh):
616 self.delete_current_notebook()
616 self.delete_current_notebook()
617 elif keycode in (ord("E"), ord("\r")):
617 elif keycode in (ord("E"), ord("\r")):
618 row = self.GetGridCursorRow()
618 row = self.GetGridCursorRow()
619 if sh:
619 if sh:
620 col = self.GetGridCursorCol()
620 col = self.GetGridCursorCol()
621 self.enterattr(row, col)
621 self.enterattr(row, col)
622 else:
622 else:
623 self.enter(row)
623 self.enter(row)
624 elif keycode == ord("E") and ctrl:
624 elif keycode == ord("E") and ctrl:
625 row = self.GetGridCursorRow()
625 row = self.GetGridCursorRow()
626 self.SetGridCursor(row, self.GetNumberCols()-1)
626 self.SetGridCursor(row, self.GetNumberCols()-1)
627 elif keycode == wx.WXK_HOME or (keycode == ord("A") and ctrl):
627 elif keycode == wx.WXK_HOME or (keycode == ord("A") and ctrl):
628 row = self.GetGridCursorRow()
628 row = self.GetGridCursorRow()
629 self.SetGridCursor(row, 0)
629 self.SetGridCursor(row, 0)
630 elif keycode == ord("C") and sh:
630 elif keycode == ord("C") and sh:
631 col = self.GetGridCursorCol()
631 col = self.GetGridCursorCol()
632 attr = self.table._displayattrs[col]
632 attr = self.table._displayattrs[col]
633 result = []
633 result = []
634 for i in xrange(self.GetNumberRows()):
634 for i in xrange(self.GetNumberRows()):
635 result.append(self.table._displayattrs[col].value(self.table.items[i]))
635 result.append(self.table._displayattrs[col].value(self.table.items[i]))
636 self.quit(result)
636 self.quit(result)
637 elif keycode in (wx.WXK_ESCAPE, ord("Q")) and not (ctrl or sh):
637 elif keycode in (wx.WXK_ESCAPE, ord("Q")) and not (ctrl or sh):
638 self.quit()
638 self.quit()
639 elif keycode == ord("<"):
639 elif keycode == ord("<"):
640 row = self.GetGridCursorRow()
640 row = self.GetGridCursorRow()
641 col = self.GetGridCursorCol()
641 col = self.GetGridCursorCol()
642 if not event.ShiftDown():
642 if not event.ShiftDown():
643 newcol = col - 1
643 newcol = col - 1
644 if newcol >= 0:
644 if newcol >= 0:
645 self.SetGridCursor(row, col - 1)
645 self.SetGridCursor(row, col - 1)
646 else:
646 else:
647 newcol = col + 1
647 newcol = col + 1
648 if newcol < self.GetNumberCols():
648 if newcol < self.GetNumberCols():
649 self.SetGridCursor(row, col + 1)
649 self.SetGridCursor(row, col + 1)
650 elif keycode == ord("D"):
650 elif keycode == ord("D"):
651 col = self.GetGridCursorCol()
651 col = self.GetGridCursorCol()
652 row = self.GetGridCursorRow()
652 row = self.GetGridCursorRow()
653 if not sh:
653 if not sh:
654 self.detail(row, col)
654 self.detail(row, col)
655 else:
655 else:
656 self.detail_attr(row, col)
656 self.detail_attr(row, col)
657 elif keycode == ord("F") and ctrl:
657 elif keycode == ord("F") and ctrl:
658 if sh:
658 if sh:
659 frame.enter_searchexpression(event)
659 frame.enter_searchexpression(event)
660 else:
660 else:
661 frame.enter_searchtext(event)
661 frame.enter_searchtext(event)
662 elif keycode == wx.WXK_F3:
662 elif keycode == wx.WXK_F3:
663 if sh:
663 if sh:
664 frame.find_previous(event)
664 frame.find_previous(event)
665 else:
665 else:
666 frame.find_next(event)
666 frame.find_next(event)
667 elif keycode == ord("V"):
667 elif keycode == ord("V"):
668 if sh:
668 if sh:
669 self.sortattrdesc()
669 self.sortattrdesc()
670 else:
670 else:
671 self.sortattrasc()
671 self.sortattrasc()
672 elif keycode == wx.WXK_DOWN:
672 elif keycode == wx.WXK_DOWN:
673 row = self.GetGridCursorRow()
673 row = self.GetGridCursorRow()
674 try:
674 try:
675 item = self.table.items[row+1]
675 item = self.table.items[row+1]
676 except IndexError:
676 except IndexError:
677 item = self.table.items[row]
677 item = self.table.items[row]
678 self.set_footer(item)
678 self.set_footer(item)
679 event.Skip()
679 event.Skip()
680 elif keycode == wx.WXK_UP:
680 elif keycode == wx.WXK_UP:
681 row = self.GetGridCursorRow()
681 row = self.GetGridCursorRow()
682 if row >= 1:
682 if row >= 1:
683 item = self.table.items[row-1]
683 item = self.table.items[row-1]
684 else:
684 else:
685 item = self.table.items[row]
685 item = self.table.items[row]
686 self.set_footer(item)
686 self.set_footer(item)
687 event.Skip()
687 event.Skip()
688 elif keycode == wx.WXK_RIGHT:
688 elif keycode == wx.WXK_RIGHT:
689 row = self.GetGridCursorRow()
689 row = self.GetGridCursorRow()
690 item = self.table.items[row]
690 item = self.table.items[row]
691 self.set_footer(item)
691 self.set_footer(item)
692 event.Skip()
692 event.Skip()
693 elif keycode == wx.WXK_LEFT:
693 elif keycode == wx.WXK_LEFT:
694 row = self.GetGridCursorRow()
694 row = self.GetGridCursorRow()
695 item = self.table.items[row]
695 item = self.table.items[row]
696 self.set_footer(item)
696 self.set_footer(item)
697 event.Skip()
697 event.Skip()
698 elif keycode == ord("R") or keycode == wx.WXK_F5:
698 elif keycode == ord("R") or keycode == wx.WXK_F5:
699 self.table.refresh_content(event)
699 self.table.refresh_content(event)
700 elif keycode == ord("I"):
700 elif keycode == ord("I"):
701 row = self.GetGridCursorRow()
701 row = self.GetGridCursorRow()
702 if not sh:
702 if not sh:
703 self.pickinput(row)
703 self.pickinput(row)
704 else:
704 else:
705 col = self.GetGridCursorCol()
705 col = self.GetGridCursorCol()
706 self.pickinputattr(row, col)
706 self.pickinputattr(row, col)
707 else:
707 else:
708 event.Skip()
708 event.Skip()
709
709
710 def delete_current_notebook(self):
710 def delete_current_notebook(self):
711 """
711 """
712 deletes the current notebook tab
712 deletes the current notebook tab
713 """
713 """
714 panel = self.GetParent()
714 panel = self.GetParent()
715 nb = panel.GetParent()
715 nb = panel.GetParent()
716 current = nb.GetSelection()
716 current = nb.GetSelection()
717 count = nb.GetPageCount()
717 count = nb.GetPageCount()
718 if count > 1:
718 if count > 1:
719 for i in xrange(count-1, current-1, -1):
719 for i in xrange(count-1, current-1, -1):
720 nb.DeletePage(i)
720 nb.DeletePage(i)
721 nb.GetCurrentPage().grid.SetFocus()
721 nb.GetCurrentPage().grid.SetFocus()
722 else:
722 else:
723 frame = nb.GetParent()
723 frame = nb.GetParent()
724 frame.SetStatusText("This is the last level!")
724 frame.SetStatusText("This is the last level!")
725
725
726 def _doenter(self, value, *attrs):
726 def _doenter(self, value, *attrs):
727 """
727 """
728 "enter" a special item resulting in a new notebook tab
728 "enter" a special item resulting in a new notebook tab
729 """
729 """
730 panel = self.GetParent()
730 panel = self.GetParent()
731 nb = panel.GetParent()
731 nb = panel.GetParent()
732 frame = nb.GetParent()
732 frame = nb.GetParent()
733 current = nb.GetSelection()
733 current = nb.GetSelection()
734 count = nb.GetPageCount()
734 count = nb.GetPageCount()
735 try: # if we want to enter something non-iterable, e.g. a function
735 try: # if we want to enter something non-iterable, e.g. a function
736 if current + 1 == count and value is not self.input: # we have an event in the last tab
736 if current + 1 == count and value is not self.input: # we have an event in the last tab
737 frame._add_notebook(value, *attrs)
737 frame._add_notebook(value, *attrs)
738 elif value != self.input: # we have to delete all tabs newer than [panel] first
738 elif value != self.input: # we have to delete all tabs newer than [panel] first
739 for i in xrange(count-1, current, -1): # some tabs don't close if we don't close in *reverse* order
739 for i in xrange(count-1, current, -1): # some tabs don't close if we don't close in *reverse* order
740 nb.DeletePage(i)
740 nb.DeletePage(i)
741 frame._add_notebook(value)
741 frame._add_notebook(value)
742 except TypeError, exc:
742 except TypeError as exc:
743 if exc.__class__.__module__ == "exceptions":
743 if exc.__class__.__module__ == "exceptions":
744 msg = "%s: %s" % (exc.__class__.__name__, exc)
744 msg = "%s: %s" % (exc.__class__.__name__, exc)
745 else:
745 else:
746 msg = "%s.%s: %s" % (exc.__class__.__module__, exc.__class__.__name__, exc)
746 msg = "%s.%s: %s" % (exc.__class__.__module__, exc.__class__.__name__, exc)
747 frame.SetStatusText(msg)
747 frame.SetStatusText(msg)
748
748
749 def enterattr(self, row, col):
749 def enterattr(self, row, col):
750 try:
750 try:
751 attr = self.table._displayattrs[col]
751 attr = self.table._displayattrs[col]
752 value = attr.value(self.table.items[row])
752 value = attr.value(self.table.items[row])
753 except Exception, exc:
753 except Exception as exc:
754 self.error_output(str(exc))
754 self.error_output(str(exc))
755 else:
755 else:
756 self._doenter(value)
756 self._doenter(value)
757
757
758 def set_footer(self, item):
758 def set_footer(self, item):
759 frame = self.GetParent().GetParent().GetParent()
759 frame = self.GetParent().GetParent().GetParent()
760 frame.SetStatusText(" ".join([str(text) for (style, text) in ipipe.xformat(item, "footer", 20)[2]]), 0)
760 frame.SetStatusText(" ".join([str(text) for (style, text) in ipipe.xformat(item, "footer", 20)[2]]), 0)
761
761
762 def enter(self, row):
762 def enter(self, row):
763 try:
763 try:
764 value = self.table.items[row]
764 value = self.table.items[row]
765 except Exception, exc:
765 except Exception as exc:
766 self.error_output(str(exc))
766 self.error_output(str(exc))
767 else:
767 else:
768 self._doenter(value)
768 self._doenter(value)
769
769
770 def detail(self, row, col):
770 def detail(self, row, col):
771 """
771 """
772 shows a detail-view of the current cell
772 shows a detail-view of the current cell
773 """
773 """
774 try:
774 try:
775 attr = self.table._displayattrs[col]
775 attr = self.table._displayattrs[col]
776 item = self.table.items[row]
776 item = self.table.items[row]
777 except Exception, exc:
777 except Exception as exc:
778 self.error_output(str(exc))
778 self.error_output(str(exc))
779 else:
779 else:
780 attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
780 attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
781 self._doenter(attrs)
781 self._doenter(attrs)
782
782
783 def detail_attr(self, row, col):
783 def detail_attr(self, row, col):
784 try:
784 try:
785 attr = self.table._displayattrs[col]
785 attr = self.table._displayattrs[col]
786 item = attr.value(self.table.items[row])
786 item = attr.value(self.table.items[row])
787 except Exception, exc:
787 except Exception as exc:
788 self.error_output(str(exc))
788 self.error_output(str(exc))
789 else:
789 else:
790 attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
790 attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
791 self._doenter(attrs)
791 self._doenter(attrs)
792
792
793 def quit(self, result=None):
793 def quit(self, result=None):
794 """
794 """
795 quit
795 quit
796 """
796 """
797 frame = self.GetParent().GetParent().GetParent()
797 frame = self.GetParent().GetParent().GetParent()
798 if frame.helpdialog:
798 if frame.helpdialog:
799 frame.helpdialog.Destroy()
799 frame.helpdialog.Destroy()
800 app = frame.parent
800 app = frame.parent
801 if app is not None:
801 if app is not None:
802 app.result = result
802 app.result = result
803 frame.Close()
803 frame.Close()
804 frame.Destroy()
804 frame.Destroy()
805
805
806 def cell_doubleclicked(self, event):
806 def cell_doubleclicked(self, event):
807 self.enterattr(event.GetRow(), event.GetCol())
807 self.enterattr(event.GetRow(), event.GetCol())
808 event.Skip()
808 event.Skip()
809
809
810 def cell_leftclicked(self, event):
810 def cell_leftclicked(self, event):
811 row = event.GetRow()
811 row = event.GetRow()
812 item = self.table.items[row]
812 item = self.table.items[row]
813 self.set_footer(item)
813 self.set_footer(item)
814 event.Skip()
814 event.Skip()
815
815
816 def pick(self, row):
816 def pick(self, row):
817 """
817 """
818 pick a single row and return to the IPython prompt
818 pick a single row and return to the IPython prompt
819 """
819 """
820 try:
820 try:
821 value = self.table.items[row]
821 value = self.table.items[row]
822 except Exception, exc:
822 except Exception as exc:
823 self.error_output(str(exc))
823 self.error_output(str(exc))
824 else:
824 else:
825 self.quit(value)
825 self.quit(value)
826
826
827 def pickinput(self, row):
827 def pickinput(self, row):
828 try:
828 try:
829 value = self.table.items[row]
829 value = self.table.items[row]
830 except Exception, exc:
830 except Exception as exc:
831 self.error_output(str(exc))
831 self.error_output(str(exc))
832 else:
832 else:
833 api = ipapi.get()
833 api = ipapi.get()
834 api.set_next_input(str(value))
834 api.set_next_input(str(value))
835 self.quit(value)
835 self.quit(value)
836
836
837 def pickinputattr(self, row, col):
837 def pickinputattr(self, row, col):
838 try:
838 try:
839 attr = self.table._displayattrs[col]
839 attr = self.table._displayattrs[col]
840 value = attr.value(self.table.items[row])
840 value = attr.value(self.table.items[row])
841 except Exception, exc:
841 except Exception as exc:
842 self.error_output(str(exc))
842 self.error_output(str(exc))
843 else:
843 else:
844 api = ipapi.get()
844 api = ipapi.get()
845 api.set_next_input(str(value))
845 api.set_next_input(str(value))
846 self.quit(value)
846 self.quit(value)
847
847
848 def pickrows(self, rows):
848 def pickrows(self, rows):
849 """
849 """
850 pick multiple rows and return to the IPython prompt
850 pick multiple rows and return to the IPython prompt
851 """
851 """
852 try:
852 try:
853 value = [self.table.items[row] for row in rows]
853 value = [self.table.items[row] for row in rows]
854 except Exception, exc:
854 except Exception as exc:
855 self.error_output(str(exc))
855 self.error_output(str(exc))
856 else:
856 else:
857 self.quit(value)
857 self.quit(value)
858
858
859 def pickrowsattr(self, rows, col):
859 def pickrowsattr(self, rows, col):
860 """"
860 """"
861 pick one column from multiple rows
861 pick one column from multiple rows
862 """
862 """
863 values = []
863 values = []
864 try:
864 try:
865 attr = self.table._displayattrs[col]
865 attr = self.table._displayattrs[col]
866 for row in rows:
866 for row in rows:
867 try:
867 try:
868 values.append(attr.value(self.table.items[row]))
868 values.append(attr.value(self.table.items[row]))
869 except (SystemExit, KeyboardInterrupt):
869 except (SystemExit, KeyboardInterrupt):
870 raise
870 raise
871 except Exception:
871 except Exception:
872 raise #pass
872 raise #pass
873 except Exception, exc:
873 except Exception as exc:
874 self.error_output(str(exc))
874 self.error_output(str(exc))
875 else:
875 else:
876 self.quit(values)
876 self.quit(values)
877
877
878 def pickattr(self, row, col):
878 def pickattr(self, row, col):
879 try:
879 try:
880 attr = self.table._displayattrs[col]
880 attr = self.table._displayattrs[col]
881 value = attr.value(self.table.items[row])
881 value = attr.value(self.table.items[row])
882 except Exception, exc:
882 except Exception as exc:
883 self.error_output(str(exc))
883 self.error_output(str(exc))
884 else:
884 else:
885 self.quit(value)
885 self.quit(value)
886
886
887
887
888 class IGridPanel(wx.Panel):
888 class IGridPanel(wx.Panel):
889 # Each IGridPanel contains an IGridGrid
889 # Each IGridPanel contains an IGridGrid
890 def __init__(self, parent, input, *attrs):
890 def __init__(self, parent, input, *attrs):
891 wx.Panel.__init__(self, parent, -1)
891 wx.Panel.__init__(self, parent, -1)
892 self.grid = IGridGrid(self, input, *attrs)
892 self.grid = IGridGrid(self, input, *attrs)
893 self.grid.FitInside()
893 self.grid.FitInside()
894 sizer = wx.BoxSizer(wx.VERTICAL)
894 sizer = wx.BoxSizer(wx.VERTICAL)
895 sizer.Add(self.grid, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
895 sizer.Add(self.grid, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
896 self.SetSizer(sizer)
896 self.SetSizer(sizer)
897 sizer.Fit(self)
897 sizer.Fit(self)
898 sizer.SetSizeHints(self)
898 sizer.SetSizeHints(self)
899
899
900
900
901 class IGridHTMLHelp(wx.Frame):
901 class IGridHTMLHelp(wx.Frame):
902 def __init__(self, parent, title, size):
902 def __init__(self, parent, title, size):
903 wx.Frame.__init__(self, parent, -1, title, size=size)
903 wx.Frame.__init__(self, parent, -1, title, size=size)
904 html = wx.html.HtmlWindow(self)
904 html = wx.html.HtmlWindow(self)
905 if "gtk2" in wx.PlatformInfo:
905 if "gtk2" in wx.PlatformInfo:
906 html.SetStandardFonts()
906 html.SetStandardFonts()
907 html.SetPage(help)
907 html.SetPage(help)
908
908
909
909
910 class IGridFrame(wx.Frame):
910 class IGridFrame(wx.Frame):
911 maxtitlelen = 30
911 maxtitlelen = 30
912
912
913 def __init__(self, parent, input):
913 def __init__(self, parent, input):
914 title = " ".join([str(text) for (style, text) in ipipe.xformat(input, "header", 20)[2]])
914 title = " ".join([str(text) for (style, text) in ipipe.xformat(input, "header", 20)[2]])
915 wx.Frame.__init__(self, None, title=title, size=(640, 480))
915 wx.Frame.__init__(self, None, title=title, size=(640, 480))
916 self.menubar = wx.MenuBar()
916 self.menubar = wx.MenuBar()
917 self.menucounter = 100
917 self.menucounter = 100
918 self.m_help = wx.Menu()
918 self.m_help = wx.Menu()
919 self.m_search = wx.Menu()
919 self.m_search = wx.Menu()
920 self.m_sort = wx.Menu()
920 self.m_sort = wx.Menu()
921 self.m_refresh = wx.Menu()
921 self.m_refresh = wx.Menu()
922 self.notebook = wx.Notebook(self, -1, style=0)
922 self.notebook = wx.Notebook(self, -1, style=0)
923 self.statusbar = self.CreateStatusBar(1, wx.ST_SIZEGRIP)
923 self.statusbar = self.CreateStatusBar(1, wx.ST_SIZEGRIP)
924 self.statusbar.SetFieldsCount(2)
924 self.statusbar.SetFieldsCount(2)
925 self.SetStatusWidths([-1, 200])
925 self.SetStatusWidths([-1, 200])
926 self.parent = parent
926 self.parent = parent
927 self._add_notebook(input)
927 self._add_notebook(input)
928 self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
928 self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
929 self.makemenu(self.m_sort, "&Sort (asc)\tV", "Sort ascending", self.sortasc)
929 self.makemenu(self.m_sort, "&Sort (asc)\tV", "Sort ascending", self.sortasc)
930 self.makemenu(self.m_sort, "Sort (&desc)\tShift-V", "Sort descending", self.sortdesc)
930 self.makemenu(self.m_sort, "Sort (&desc)\tShift-V", "Sort descending", self.sortdesc)
931 self.makemenu(self.m_help, "&Help\tF1", "Help", self.display_help)
931 self.makemenu(self.m_help, "&Help\tF1", "Help", self.display_help)
932 # self.makemenu(self.m_help, "&Show help in browser", "Show help in browser", self.display_help_in_browser)
932 # self.makemenu(self.m_help, "&Show help in browser", "Show help in browser", self.display_help_in_browser)
933 self.makemenu(self.m_search, "&Find text\tCTRL-F", "Find text", self.enter_searchtext)
933 self.makemenu(self.m_search, "&Find text\tCTRL-F", "Find text", self.enter_searchtext)
934 self.makemenu(self.m_search, "Find by &expression\tCTRL-Shift-F", "Find by expression", self.enter_searchexpression)
934 self.makemenu(self.m_search, "Find by &expression\tCTRL-Shift-F", "Find by expression", self.enter_searchexpression)
935 self.makemenu(self.m_search, "Find &next\tF3", "Find next", self.find_next)
935 self.makemenu(self.m_search, "Find &next\tF3", "Find next", self.find_next)
936 self.makemenu(self.m_search, "Find &previous\tShift-F3", "Find previous", self.find_previous)
936 self.makemenu(self.m_search, "Find &previous\tShift-F3", "Find previous", self.find_previous)
937 self.makemenu(self.m_refresh, "&Refresh once \tF5", "Refresh once", self.refresh_once)
937 self.makemenu(self.m_refresh, "&Refresh once \tF5", "Refresh once", self.refresh_once)
938 self.makemenu(self.m_refresh, "Refresh every &1s", "Refresh every second", self.refresh_every_second)
938 self.makemenu(self.m_refresh, "Refresh every &1s", "Refresh every second", self.refresh_every_second)
939 self.makemenu(self.m_refresh, "Refresh every &X seconds", "Refresh every X seconds", self.refresh_interval)
939 self.makemenu(self.m_refresh, "Refresh every &X seconds", "Refresh every X seconds", self.refresh_interval)
940 self.makemenu(self.m_refresh, "&Stop all refresh timers", "Stop refresh timers", self.stop_refresh)
940 self.makemenu(self.m_refresh, "&Stop all refresh timers", "Stop refresh timers", self.stop_refresh)
941 self.menubar.Append(self.m_search, "&Find")
941 self.menubar.Append(self.m_search, "&Find")
942 self.menubar.Append(self.m_sort, "&Sort")
942 self.menubar.Append(self.m_sort, "&Sort")
943 self.menubar.Append(self.m_refresh, "&Refresh")
943 self.menubar.Append(self.m_refresh, "&Refresh")
944 self.menubar.Append(self.m_help, "&Help")
944 self.menubar.Append(self.m_help, "&Help")
945 self.SetMenuBar(self.menubar)
945 self.SetMenuBar(self.menubar)
946 self.searchtext = ""
946 self.searchtext = ""
947 self.searchexpression = ""
947 self.searchexpression = ""
948 self.helpdialog = None
948 self.helpdialog = None
949 self.refresh_interval = 1000
949 self.refresh_interval = 1000
950 self.SetStatusText("Refreshing inactive", 1)
950 self.SetStatusText("Refreshing inactive", 1)
951
951
952 def refresh_once(self, event):
952 def refresh_once(self, event):
953 table = self.notebook.GetPage(self.notebook.GetSelection()).grid.table
953 table = self.notebook.GetPage(self.notebook.GetSelection()).grid.table
954 table.refresh_content(event)
954 table.refresh_content(event)
955
955
956 def refresh_interval(self, event):
956 def refresh_interval(self, event):
957 table = self.notebook.GetPage(self.notebook.GetSelection()).grid.table
957 table = self.notebook.GetPage(self.notebook.GetSelection()).grid.table
958 dlg = wx.TextEntryDialog(self, "Enter refresh interval (milliseconds):", "Refresh timer:", defaultValue=str(self.refresh_interval))
958 dlg = wx.TextEntryDialog(self, "Enter refresh interval (milliseconds):", "Refresh timer:", defaultValue=str(self.refresh_interval))
959 if dlg.ShowModal() == wx.ID_OK:
959 if dlg.ShowModal() == wx.ID_OK:
960 try:
960 try:
961 milliseconds = int(dlg.GetValue())
961 milliseconds = int(dlg.GetValue())
962 except ValueError, exc:
962 except ValueError as exc:
963 self.SetStatusText(str(exc))
963 self.SetStatusText(str(exc))
964 else:
964 else:
965 table.timer.Start(milliseconds=milliseconds, oneShot=False)
965 table.timer.Start(milliseconds=milliseconds, oneShot=False)
966 self.SetStatusText("Refresh timer set to %s ms" % milliseconds)
966 self.SetStatusText("Refresh timer set to %s ms" % milliseconds)
967 self.SetStatusText("Refresh interval: %s ms" % milliseconds, 1)
967 self.SetStatusText("Refresh interval: %s ms" % milliseconds, 1)
968 self.refresh_interval = milliseconds
968 self.refresh_interval = milliseconds
969 dlg.Destroy()
969 dlg.Destroy()
970
970
971 def stop_refresh(self, event):
971 def stop_refresh(self, event):
972 for i in xrange(self.notebook.GetPageCount()):
972 for i in xrange(self.notebook.GetPageCount()):
973 nb = self.notebook.GetPage(i)
973 nb = self.notebook.GetPage(i)
974 nb.grid.table.timer.Stop()
974 nb.grid.table.timer.Stop()
975 self.SetStatusText("Refreshing inactive", 1)
975 self.SetStatusText("Refreshing inactive", 1)
976
976
977 def refresh_every_second(self, event):
977 def refresh_every_second(self, event):
978 table = self.notebook.GetPage(self.notebook.GetSelection()).grid.table
978 table = self.notebook.GetPage(self.notebook.GetSelection()).grid.table
979 table.timer.Start(milliseconds=1000, oneShot=False)
979 table.timer.Start(milliseconds=1000, oneShot=False)
980 self.SetStatusText("Refresh interval: 1000 ms", 1)
980 self.SetStatusText("Refresh interval: 1000 ms", 1)
981
981
982 def sortasc(self, event):
982 def sortasc(self, event):
983 grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
983 grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
984 grid.sortattrasc()
984 grid.sortattrasc()
985
985
986 def sortdesc(self, event):
986 def sortdesc(self, event):
987 grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
987 grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
988 grid.sortattrdesc()
988 grid.sortattrdesc()
989
989
990 def find_previous(self, event):
990 def find_previous(self, event):
991 """
991 """
992 find previous occurrences
992 find previous occurrences
993 """
993 """
994 grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
994 grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
995 if self.searchtext:
995 if self.searchtext:
996 row = grid.GetGridCursorRow()
996 row = grid.GetGridCursorRow()
997 col = grid.GetGridCursorCol()
997 col = grid.GetGridCursorCol()
998 self.SetStatusText('Search mode: text; looking for %s' % self.searchtext)
998 self.SetStatusText('Search mode: text; looking for %s' % self.searchtext)
999 if col-1 >= 0:
999 if col-1 >= 0:
1000 grid.search(self.searchtext, row, col-1, False)
1000 grid.search(self.searchtext, row, col-1, False)
1001 else:
1001 else:
1002 grid.search(self.searchtext, row-1, grid.table.GetNumberCols()-1, False)
1002 grid.search(self.searchtext, row-1, grid.table.GetNumberCols()-1, False)
1003 elif self.searchexpression:
1003 elif self.searchexpression:
1004 self.SetStatusText("Search mode: expression; looking for %s" % repr(self.searchexpression)[2:-1])
1004 self.SetStatusText("Search mode: expression; looking for %s" % repr(self.searchexpression)[2:-1])
1005 grid.searchexpression(searchexp=self.searchexpression, search_forward=False)
1005 grid.searchexpression(searchexp=self.searchexpression, search_forward=False)
1006 else:
1006 else:
1007 self.SetStatusText("No search yet: please enter search-text or -expression")
1007 self.SetStatusText("No search yet: please enter search-text or -expression")
1008
1008
1009 def find_next(self, event):
1009 def find_next(self, event):
1010 """
1010 """
1011 find the next occurrence
1011 find the next occurrence
1012 """
1012 """
1013 grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
1013 grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
1014 if self.searchtext != "":
1014 if self.searchtext != "":
1015 row = grid.GetGridCursorRow()
1015 row = grid.GetGridCursorRow()
1016 col = grid.GetGridCursorCol()
1016 col = grid.GetGridCursorCol()
1017 self.SetStatusText('Search mode: text; looking for %s' % self.searchtext)
1017 self.SetStatusText('Search mode: text; looking for %s' % self.searchtext)
1018 if col+1 < grid.table.GetNumberCols():
1018 if col+1 < grid.table.GetNumberCols():
1019 grid.search(self.searchtext, row, col+1)
1019 grid.search(self.searchtext, row, col+1)
1020 else:
1020 else:
1021 grid.search(self.searchtext, row+1, 0)
1021 grid.search(self.searchtext, row+1, 0)
1022 elif self.searchexpression != "":
1022 elif self.searchexpression != "":
1023 self.SetStatusText('Search mode: expression; looking for %s' % repr(self.searchexpression)[2:-1])
1023 self.SetStatusText('Search mode: expression; looking for %s' % repr(self.searchexpression)[2:-1])
1024 grid.searchexpression(searchexp=self.searchexpression)
1024 grid.searchexpression(searchexp=self.searchexpression)
1025 else:
1025 else:
1026 self.SetStatusText("No search yet: please enter search-text or -expression")
1026 self.SetStatusText("No search yet: please enter search-text or -expression")
1027
1027
1028 def display_help(self, event):
1028 def display_help(self, event):
1029 """
1029 """
1030 Display a help dialog
1030 Display a help dialog
1031 """
1031 """
1032 if self.helpdialog:
1032 if self.helpdialog:
1033 self.helpdialog.Destroy()
1033 self.helpdialog.Destroy()
1034 self.helpdialog = IGridHTMLHelp(None, title="Help", size=wx.Size(600,400))
1034 self.helpdialog = IGridHTMLHelp(None, title="Help", size=wx.Size(600,400))
1035 self.helpdialog.Show()
1035 self.helpdialog.Show()
1036
1036
1037 def display_help_in_browser(self, event):
1037 def display_help_in_browser(self, event):
1038 """
1038 """
1039 Show the help-HTML in a browser (as a ``HtmlWindow`` does not understand
1039 Show the help-HTML in a browser (as a ``HtmlWindow`` does not understand
1040 CSS this looks better)
1040 CSS this looks better)
1041 """
1041 """
1042 filename = urllib.pathname2url(os.path.abspath(os.path.join(os.path.dirname(__file__), "igrid_help.html")))
1042 filename = urllib.pathname2url(os.path.abspath(os.path.join(os.path.dirname(__file__), "igrid_help.html")))
1043 if not filename.startswith("file"):
1043 if not filename.startswith("file"):
1044 filename = "file:" + filename
1044 filename = "file:" + filename
1045 webbrowser.open(filename, new=1, autoraise=True)
1045 webbrowser.open(filename, new=1, autoraise=True)
1046
1046
1047 def enter_searchexpression(self, event):
1047 def enter_searchexpression(self, event):
1048 dlg = wx.TextEntryDialog(self, "Find:", "Find matching expression:", defaultValue=self.searchexpression)
1048 dlg = wx.TextEntryDialog(self, "Find:", "Find matching expression:", defaultValue=self.searchexpression)
1049 if dlg.ShowModal() == wx.ID_OK:
1049 if dlg.ShowModal() == wx.ID_OK:
1050 self.searchexpression = dlg.GetValue()
1050 self.searchexpression = dlg.GetValue()
1051 self.searchtext = ""
1051 self.searchtext = ""
1052 self.SetStatusText('Search mode: expression; looking for %s' % repr(self.searchexpression)[2:-1])
1052 self.SetStatusText('Search mode: expression; looking for %s' % repr(self.searchexpression)[2:-1])
1053 self.notebook.GetPage(self.notebook.GetSelection()).grid.searchexpression(self.searchexpression)
1053 self.notebook.GetPage(self.notebook.GetSelection()).grid.searchexpression(self.searchexpression)
1054 dlg.Destroy()
1054 dlg.Destroy()
1055
1055
1056 def makemenu(self, menu, label, help, cmd):
1056 def makemenu(self, menu, label, help, cmd):
1057 menu.Append(self.menucounter, label, help)
1057 menu.Append(self.menucounter, label, help)
1058 self.Bind(wx.EVT_MENU, cmd, id=self.menucounter)
1058 self.Bind(wx.EVT_MENU, cmd, id=self.menucounter)
1059 self.menucounter += 1
1059 self.menucounter += 1
1060
1060
1061 def _add_notebook(self, input, *attrs):
1061 def _add_notebook(self, input, *attrs):
1062 # Adds another notebook which has the starting object ``input``
1062 # Adds another notebook which has the starting object ``input``
1063 panel = IGridPanel(self.notebook, input, *attrs)
1063 panel = IGridPanel(self.notebook, input, *attrs)
1064 text = str(ipipe.xformat(input, "header", self.maxtitlelen)[2])
1064 text = str(ipipe.xformat(input, "header", self.maxtitlelen)[2])
1065 if len(text) >= self.maxtitlelen:
1065 if len(text) >= self.maxtitlelen:
1066 text = text[:self.maxtitlelen].rstrip(".") + "..."
1066 text = text[:self.maxtitlelen].rstrip(".") + "..."
1067 self.notebook.AddPage(panel, text, True)
1067 self.notebook.AddPage(panel, text, True)
1068 panel.grid.SetFocus()
1068 panel.grid.SetFocus()
1069 self.Layout()
1069 self.Layout()
1070
1070
1071 def OnCloseWindow(self, event):
1071 def OnCloseWindow(self, event):
1072 self.Destroy()
1072 self.Destroy()
1073
1073
1074 def enter_searchtext(self, event):
1074 def enter_searchtext(self, event):
1075 # Displays a dialog asking for the searchtext
1075 # Displays a dialog asking for the searchtext
1076 dlg = wx.TextEntryDialog(self, "Find:", "Find in list", defaultValue=self.searchtext)
1076 dlg = wx.TextEntryDialog(self, "Find:", "Find in list", defaultValue=self.searchtext)
1077 if dlg.ShowModal() == wx.ID_OK:
1077 if dlg.ShowModal() == wx.ID_OK:
1078 self.searchtext = dlg.GetValue()
1078 self.searchtext = dlg.GetValue()
1079 self.searchexpression = ""
1079 self.searchexpression = ""
1080 self.SetStatusText('Search mode: text; looking for %s' % self.searchtext)
1080 self.SetStatusText('Search mode: text; looking for %s' % self.searchtext)
1081 self.notebook.GetPage(self.notebook.GetSelection()).grid.search(self.searchtext)
1081 self.notebook.GetPage(self.notebook.GetSelection()).grid.search(self.searchtext)
1082 dlg.Destroy()
1082 dlg.Destroy()
1083
1083
1084
1084
1085 class App(wx.App):
1085 class App(wx.App):
1086 def __init__(self, input):
1086 def __init__(self, input):
1087 self.input = input
1087 self.input = input
1088 self.result = None # Result to be returned to IPython. Set by quit().
1088 self.result = None # Result to be returned to IPython. Set by quit().
1089 wx.App.__init__(self)
1089 wx.App.__init__(self)
1090
1090
1091 def OnInit(self):
1091 def OnInit(self):
1092 frame = IGridFrame(self, self.input)
1092 frame = IGridFrame(self, self.input)
1093 frame.Show()
1093 frame.Show()
1094 self.SetTopWindow(frame)
1094 self.SetTopWindow(frame)
1095 frame.Raise()
1095 frame.Raise()
1096 return True
1096 return True
1097
1097
1098
1098
1099 class igrid(ipipe.Display):
1099 class igrid(ipipe.Display):
1100 """
1100 """
1101 This is a wx-based display object that can be used instead of ``ibrowse``
1101 This is a wx-based display object that can be used instead of ``ibrowse``
1102 (which is curses-based) or ``idump`` (which simply does a print).
1102 (which is curses-based) or ``idump`` (which simply does a print).
1103 """
1103 """
1104
1104
1105 if wx.VERSION < (2, 7):
1105 if wx.VERSION < (2, 7):
1106 def display(self):
1106 def display(self):
1107 try:
1107 try:
1108 # Try to create a "standalone" frame. If this works we're probably
1108 # Try to create a "standalone" frame. If this works we're probably
1109 # running with -wthread.
1109 # running with -wthread.
1110 # Note that this sets the parent of the frame to None, but we can't
1110 # Note that this sets the parent of the frame to None, but we can't
1111 # pass a result object back to the shell anyway.
1111 # pass a result object back to the shell anyway.
1112 frame = IGridFrame(None, self.input)
1112 frame = IGridFrame(None, self.input)
1113 frame.Show()
1113 frame.Show()
1114 frame.Raise()
1114 frame.Raise()
1115 except wx.PyNoAppError:
1115 except wx.PyNoAppError:
1116 # There's no wx application yet => create one.
1116 # There's no wx application yet => create one.
1117 app = App(self.input)
1117 app = App(self.input)
1118 app.MainLoop()
1118 app.MainLoop()
1119 return app.result
1119 return app.result
1120 else:
1120 else:
1121 # With wx 2.7 it gets simpler.
1121 # With wx 2.7 it gets simpler.
1122 def display(self):
1122 def display(self):
1123 app = App(self.input)
1123 app = App(self.input)
1124 app.MainLoop()
1124 app.MainLoop()
1125 return app.result
1125 return app.result
1126
1126
@@ -1,2328 +1,2328 b''
1 # -*- coding: iso-8859-1 -*-
1 # -*- coding: iso-8859-1 -*-
2
2
3 """
3 """
4 ``ipipe`` provides classes to be used in an interactive Python session. Doing a
4 ``ipipe`` provides classes to be used in an interactive Python session. Doing a
5 ``from ipipe import *`` is the preferred way to do this. The name of all
5 ``from ipipe import *`` is the preferred way to do this. The name of all
6 objects imported this way starts with ``i`` to minimize collisions.
6 objects imported this way starts with ``i`` to minimize collisions.
7
7
8 ``ipipe`` supports "pipeline expressions", which is something resembling Unix
8 ``ipipe`` supports "pipeline expressions", which is something resembling Unix
9 pipes. An example is::
9 pipes. An example is::
10
10
11 >>> ienv | isort("key.lower()")
11 >>> ienv | isort("key.lower()")
12
12
13 This gives a listing of all environment variables sorted by name.
13 This gives a listing of all environment variables sorted by name.
14
14
15
15
16 There are three types of objects in a pipeline expression:
16 There are three types of objects in a pipeline expression:
17
17
18 * ``Table``s: These objects produce items. Examples are ``ils`` (listing the
18 * ``Table``s: These objects produce items. Examples are ``ils`` (listing the
19 current directory, ``ienv`` (listing environment variables), ``ipwd`` (listing
19 current directory, ``ienv`` (listing environment variables), ``ipwd`` (listing
20 user accounts) and ``igrp`` (listing user groups). A ``Table`` must be the
20 user accounts) and ``igrp`` (listing user groups). A ``Table`` must be the
21 first object in a pipe expression.
21 first object in a pipe expression.
22
22
23 * ``Pipe``s: These objects sit in the middle of a pipe expression. They
23 * ``Pipe``s: These objects sit in the middle of a pipe expression. They
24 transform the input in some way (e.g. filtering or sorting it). Examples are:
24 transform the input in some way (e.g. filtering or sorting it). Examples are:
25 ``ifilter`` (which filters the input pipe), ``isort`` (which sorts the input
25 ``ifilter`` (which filters the input pipe), ``isort`` (which sorts the input
26 pipe) and ``ieval`` (which evaluates a function or expression for each object
26 pipe) and ``ieval`` (which evaluates a function or expression for each object
27 in the input pipe).
27 in the input pipe).
28
28
29 * ``Display``s: These objects can be put as the last object in a pipeline
29 * ``Display``s: These objects can be put as the last object in a pipeline
30 expression. There are responsible for displaying the result of the pipeline
30 expression. There are responsible for displaying the result of the pipeline
31 expression. If a pipeline expression doesn't end in a display object a default
31 expression. If a pipeline expression doesn't end in a display object a default
32 display objects will be used. One example is ``ibrowse`` which is a ``curses``
32 display objects will be used. One example is ``ibrowse`` which is a ``curses``
33 based browser.
33 based browser.
34
34
35
35
36 Adding support for pipeline expressions to your own objects can be done through
36 Adding support for pipeline expressions to your own objects can be done through
37 three extensions points (all of them optional):
37 three extensions points (all of them optional):
38
38
39 * An object that will be displayed as a row by a ``Display`` object should
39 * An object that will be displayed as a row by a ``Display`` object should
40 implement the method ``__xattrs__(self, mode)`` method or register an
40 implement the method ``__xattrs__(self, mode)`` method or register an
41 implementation of the generic function ``xattrs``. For more info see ``xattrs``.
41 implementation of the generic function ``xattrs``. For more info see ``xattrs``.
42
42
43 * When an object ``foo`` is displayed by a ``Display`` object, the generic
43 * When an object ``foo`` is displayed by a ``Display`` object, the generic
44 function ``xrepr`` is used.
44 function ``xrepr`` is used.
45
45
46 * Objects that can be iterated by ``Pipe``s must iterable. For special cases,
46 * Objects that can be iterated by ``Pipe``s must iterable. For special cases,
47 where iteration for display is different than the normal iteration a special
47 where iteration for display is different than the normal iteration a special
48 implementation can be registered with the generic function ``xiter``. This
48 implementation can be registered with the generic function ``xiter``. This
49 makes it possible to use dictionaries and modules in pipeline expressions,
49 makes it possible to use dictionaries and modules in pipeline expressions,
50 for example::
50 for example::
51
51
52 >>> import sys
52 >>> import sys
53 >>> sys | ifilter("isinstance(value, int)") | idump
53 >>> sys | ifilter("isinstance(value, int)") | idump
54 key |value
54 key |value
55 api_version| 1012
55 api_version| 1012
56 dllhandle | 503316480
56 dllhandle | 503316480
57 hexversion | 33817328
57 hexversion | 33817328
58 maxint |2147483647
58 maxint |2147483647
59 maxunicode | 65535
59 maxunicode | 65535
60 >>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()")
60 >>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()")
61 ...
61 ...
62
62
63 Note: The expression strings passed to ``ifilter()`` and ``isort()`` can
63 Note: The expression strings passed to ``ifilter()`` and ``isort()`` can
64 refer to the object to be filtered or sorted via the variable ``_`` and to any
64 refer to the object to be filtered or sorted via the variable ``_`` and to any
65 of the attributes of the object, i.e.::
65 of the attributes of the object, i.e.::
66
66
67 >>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()")
67 >>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()")
68
68
69 does the same as::
69 does the same as::
70
70
71 >>> sys.modules | ifilter("value is not None") | isort("key.lower()")
71 >>> sys.modules | ifilter("value is not None") | isort("key.lower()")
72
72
73 In addition to expression strings, it's possible to pass callables (taking
73 In addition to expression strings, it's possible to pass callables (taking
74 the object as an argument) to ``ifilter()``, ``isort()`` and ``ieval()``::
74 the object as an argument) to ``ifilter()``, ``isort()`` and ``ieval()``::
75
75
76 >>> sys | ifilter(lambda _:isinstance(_.value, int)) \
76 >>> sys | ifilter(lambda _:isinstance(_.value, int)) \
77 ... | ieval(lambda _: (_.key, hex(_.value))) | idump
77 ... | ieval(lambda _: (_.key, hex(_.value))) | idump
78 0 |1
78 0 |1
79 api_version|0x3f4
79 api_version|0x3f4
80 dllhandle |0x1e000000
80 dllhandle |0x1e000000
81 hexversion |0x20402f0
81 hexversion |0x20402f0
82 maxint |0x7fffffff
82 maxint |0x7fffffff
83 maxunicode |0xffff
83 maxunicode |0xffff
84 """
84 """
85
85
86 skip_doctest = True # ignore top-level docstring as a doctest.
86 skip_doctest = True # ignore top-level docstring as a doctest.
87
87
88 import sys, os, os.path, stat, glob, new, csv, datetime, types
88 import sys, os, os.path, stat, glob, new, csv, datetime, types
89 import itertools, mimetypes, StringIO
89 import itertools, mimetypes, StringIO
90
90
91 try: # Python 2.3 compatibility
91 try: # Python 2.3 compatibility
92 import collections
92 import collections
93 except ImportError:
93 except ImportError:
94 deque = list
94 deque = list
95 else:
95 else:
96 deque = collections.deque
96 deque = collections.deque
97
97
98 try: # Python 2.3 compatibility
98 try: # Python 2.3 compatibility
99 set
99 set
100 except NameError:
100 except NameError:
101 import sets
101 import sets
102 set = sets.Set
102 set = sets.Set
103
103
104 try: # Python 2.3 compatibility
104 try: # Python 2.3 compatibility
105 sorted
105 sorted
106 except NameError:
106 except NameError:
107 def sorted(iterator, key=None, reverse=False):
107 def sorted(iterator, key=None, reverse=False):
108 items = list(iterator)
108 items = list(iterator)
109 if key is not None:
109 if key is not None:
110 items.sort(lambda i1, i2: cmp(key(i1), key(i2)))
110 items.sort(lambda i1, i2: cmp(key(i1), key(i2)))
111 else:
111 else:
112 items.sort()
112 items.sort()
113 if reverse:
113 if reverse:
114 items.reverse()
114 items.reverse()
115 return items
115 return items
116
116
117 try: # Python 2.4 compatibility
117 try: # Python 2.4 compatibility
118 GeneratorExit
118 GeneratorExit
119 except NameError:
119 except NameError:
120 GeneratorExit = SystemExit
120 GeneratorExit = SystemExit
121
121
122 try:
122 try:
123 import pwd
123 import pwd
124 except ImportError:
124 except ImportError:
125 pwd = None
125 pwd = None
126
126
127 try:
127 try:
128 import grp
128 import grp
129 except ImportError:
129 except ImportError:
130 grp = None
130 grp = None
131
131
132 from IPython.external import simplegeneric
132 from IPython.external import simplegeneric
133 from IPython.external import path
133 from IPython.external import path
134
134
135 try:
135 try:
136 import IPython.utils.io
136 import IPython.utils.io
137 from IPython.utils import generics
137 from IPython.utils import generics
138 except ImportError:
138 except ImportError:
139 Term = None
139 Term = None
140 generics = None
140 generics = None
141
141
142 from IPython.core import ipapi
142 from IPython.core import ipapi
143
143
144
144
145 __all__ = [
145 __all__ = [
146 "ifile", "ils", "iglob", "iwalk", "ipwdentry", "ipwd", "igrpentry", "igrp",
146 "ifile", "ils", "iglob", "iwalk", "ipwdentry", "ipwd", "igrpentry", "igrp",
147 "icsv", "ix", "ichain", "isort", "ifilter", "ieval", "ienum",
147 "icsv", "ix", "ichain", "isort", "ifilter", "ieval", "ienum",
148 "ienv", "ihist", "ialias", "icap", "idump", "iless"
148 "ienv", "ihist", "ialias", "icap", "idump", "iless"
149 ]
149 ]
150
150
151
151
152 os.stat_float_times(True) # enable microseconds
152 os.stat_float_times(True) # enable microseconds
153
153
154
154
155 class AttrNamespace(object):
155 class AttrNamespace(object):
156 """
156 """
157 Helper class that is used for providing a namespace for evaluating
157 Helper class that is used for providing a namespace for evaluating
158 expressions containing attribute names of an object.
158 expressions containing attribute names of an object.
159 """
159 """
160 def __init__(self, wrapped):
160 def __init__(self, wrapped):
161 self.wrapped = wrapped
161 self.wrapped = wrapped
162
162
163 def __getitem__(self, name):
163 def __getitem__(self, name):
164 if name == "_":
164 if name == "_":
165 return self.wrapped
165 return self.wrapped
166 try:
166 try:
167 return getattr(self.wrapped, name)
167 return getattr(self.wrapped, name)
168 except AttributeError:
168 except AttributeError:
169 raise KeyError(name)
169 raise KeyError(name)
170
170
171 # Python 2.3 compatibility
171 # Python 2.3 compatibility
172 # use eval workaround to find out which names are used in the
172 # use eval workaround to find out which names are used in the
173 # eval string and put them into the locals. This works for most
173 # eval string and put them into the locals. This works for most
174 # normal uses case, bizarre ones like accessing the locals()
174 # normal uses case, bizarre ones like accessing the locals()
175 # will fail
175 # will fail
176 try:
176 try:
177 eval("_", None, AttrNamespace(None))
177 eval("_", None, AttrNamespace(None))
178 except TypeError:
178 except TypeError:
179 real_eval = eval
179 real_eval = eval
180 def eval(codestring, _globals, _locals):
180 def eval(codestring, _globals, _locals):
181 """
181 """
182 eval(source[, globals[, locals]]) -> value
182 eval(source[, globals[, locals]]) -> value
183
183
184 Evaluate the source in the context of globals and locals.
184 Evaluate the source in the context of globals and locals.
185 The source may be a string representing a Python expression
185 The source may be a string representing a Python expression
186 or a code object as returned by compile().
186 or a code object as returned by compile().
187 The globals must be a dictionary and locals can be any mappping.
187 The globals must be a dictionary and locals can be any mappping.
188
188
189 This function is a workaround for the shortcomings of
189 This function is a workaround for the shortcomings of
190 Python 2.3's eval.
190 Python 2.3's eval.
191 """
191 """
192
192
193 if isinstance(codestring, basestring):
193 if isinstance(codestring, basestring):
194 code = compile(codestring, "_eval", "eval")
194 code = compile(codestring, "_eval", "eval")
195 else:
195 else:
196 code = codestring
196 code = codestring
197 newlocals = {}
197 newlocals = {}
198 for name in code.co_names:
198 for name in code.co_names:
199 try:
199 try:
200 newlocals[name] = _locals[name]
200 newlocals[name] = _locals[name]
201 except KeyError:
201 except KeyError:
202 pass
202 pass
203 return real_eval(code, _globals, newlocals)
203 return real_eval(code, _globals, newlocals)
204
204
205
205
206 noitem = object()
206 noitem = object()
207
207
208
208
209 def item(iterator, index, default=noitem):
209 def item(iterator, index, default=noitem):
210 """
210 """
211 Return the ``index``th item from the iterator ``iterator``.
211 Return the ``index``th item from the iterator ``iterator``.
212 ``index`` must be an integer (negative integers are relative to the
212 ``index`` must be an integer (negative integers are relative to the
213 end (i.e. the last items produced by the iterator)).
213 end (i.e. the last items produced by the iterator)).
214
214
215 If ``default`` is given, this will be the default value when
215 If ``default`` is given, this will be the default value when
216 the iterator doesn't contain an item at this position. Otherwise an
216 the iterator doesn't contain an item at this position. Otherwise an
217 ``IndexError`` will be raised.
217 ``IndexError`` will be raised.
218
218
219 Note that using this function will partially or totally exhaust the
219 Note that using this function will partially or totally exhaust the
220 iterator.
220 iterator.
221 """
221 """
222 i = index
222 i = index
223 if i>=0:
223 if i>=0:
224 for item in iterator:
224 for item in iterator:
225 if not i:
225 if not i:
226 return item
226 return item
227 i -= 1
227 i -= 1
228 else:
228 else:
229 i = -index
229 i = -index
230 cache = deque()
230 cache = deque()
231 for item in iterator:
231 for item in iterator:
232 cache.append(item)
232 cache.append(item)
233 if len(cache)>i:
233 if len(cache)>i:
234 cache.popleft()
234 cache.popleft()
235 if len(cache)==i:
235 if len(cache)==i:
236 return cache.popleft()
236 return cache.popleft()
237 if default is noitem:
237 if default is noitem:
238 raise IndexError(index)
238 raise IndexError(index)
239 else:
239 else:
240 return default
240 return default
241
241
242
242
243 def getglobals(g):
243 def getglobals(g):
244 """
244 """
245 Return the global namespace that is used for expression strings in
245 Return the global namespace that is used for expression strings in
246 ``ifilter`` and others. This is ``g`` or (if ``g`` is ``None``) IPython's
246 ``ifilter`` and others. This is ``g`` or (if ``g`` is ``None``) IPython's
247 user namespace.
247 user namespace.
248 """
248 """
249 if g is None:
249 if g is None:
250 if ipapi is not None:
250 if ipapi is not None:
251 api = ipapi.get()
251 api = ipapi.get()
252 if api is not None:
252 if api is not None:
253 return api.user_ns
253 return api.user_ns
254 return globals()
254 return globals()
255 return g
255 return g
256
256
257
257
258 class Descriptor(object):
258 class Descriptor(object):
259 """
259 """
260 A ``Descriptor`` object is used for describing the attributes of objects.
260 A ``Descriptor`` object is used for describing the attributes of objects.
261 """
261 """
262 def __hash__(self):
262 def __hash__(self):
263 return hash(self.__class__) ^ hash(self.key())
263 return hash(self.__class__) ^ hash(self.key())
264
264
265 def __eq__(self, other):
265 def __eq__(self, other):
266 return self.__class__ is other.__class__ and self.key() == other.key()
266 return self.__class__ is other.__class__ and self.key() == other.key()
267
267
268 def __ne__(self, other):
268 def __ne__(self, other):
269 return self.__class__ is not other.__class__ or self.key() != other.key()
269 return self.__class__ is not other.__class__ or self.key() != other.key()
270
270
271 def key(self):
271 def key(self):
272 pass
272 pass
273
273
274 def name(self):
274 def name(self):
275 """
275 """
276 Return the name of this attribute for display by a ``Display`` object
276 Return the name of this attribute for display by a ``Display`` object
277 (e.g. as a column title).
277 (e.g. as a column title).
278 """
278 """
279 key = self.key()
279 key = self.key()
280 if key is None:
280 if key is None:
281 return "_"
281 return "_"
282 return str(key)
282 return str(key)
283
283
284 def attrtype(self, obj):
284 def attrtype(self, obj):
285 """
285 """
286 Return the type of this attribute (i.e. something like "attribute" or
286 Return the type of this attribute (i.e. something like "attribute" or
287 "method").
287 "method").
288 """
288 """
289
289
290 def valuetype(self, obj):
290 def valuetype(self, obj):
291 """
291 """
292 Return the type of this attribute value of the object ``obj``.
292 Return the type of this attribute value of the object ``obj``.
293 """
293 """
294
294
295 def value(self, obj):
295 def value(self, obj):
296 """
296 """
297 Return the value of this attribute of the object ``obj``.
297 Return the value of this attribute of the object ``obj``.
298 """
298 """
299
299
300 def doc(self, obj):
300 def doc(self, obj):
301 """
301 """
302 Return the documentation for this attribute.
302 Return the documentation for this attribute.
303 """
303 """
304
304
305 def shortdoc(self, obj):
305 def shortdoc(self, obj):
306 """
306 """
307 Return a short documentation for this attribute (defaulting to the
307 Return a short documentation for this attribute (defaulting to the
308 first line).
308 first line).
309 """
309 """
310 doc = self.doc(obj)
310 doc = self.doc(obj)
311 if doc is not None:
311 if doc is not None:
312 doc = doc.strip().splitlines()[0].strip()
312 doc = doc.strip().splitlines()[0].strip()
313 return doc
313 return doc
314
314
315 def iter(self, obj):
315 def iter(self, obj):
316 """
316 """
317 Return an iterator for this attribute of the object ``obj``.
317 Return an iterator for this attribute of the object ``obj``.
318 """
318 """
319 return xiter(self.value(obj))
319 return xiter(self.value(obj))
320
320
321
321
322 class SelfDescriptor(Descriptor):
322 class SelfDescriptor(Descriptor):
323 """
323 """
324 A ``SelfDescriptor`` describes the object itself.
324 A ``SelfDescriptor`` describes the object itself.
325 """
325 """
326 def key(self):
326 def key(self):
327 return None
327 return None
328
328
329 def attrtype(self, obj):
329 def attrtype(self, obj):
330 return "self"
330 return "self"
331
331
332 def valuetype(self, obj):
332 def valuetype(self, obj):
333 return type(obj)
333 return type(obj)
334
334
335 def value(self, obj):
335 def value(self, obj):
336 return obj
336 return obj
337
337
338 def __repr__(self):
338 def __repr__(self):
339 return "Self"
339 return "Self"
340
340
341 selfdescriptor = SelfDescriptor() # there's no need for more than one
341 selfdescriptor = SelfDescriptor() # there's no need for more than one
342
342
343
343
344 class AttributeDescriptor(Descriptor):
344 class AttributeDescriptor(Descriptor):
345 """
345 """
346 An ``AttributeDescriptor`` describes a simple attribute of an object.
346 An ``AttributeDescriptor`` describes a simple attribute of an object.
347 """
347 """
348 __slots__ = ("_name", "_doc")
348 __slots__ = ("_name", "_doc")
349
349
350 def __init__(self, name, doc=None):
350 def __init__(self, name, doc=None):
351 self._name = name
351 self._name = name
352 self._doc = doc
352 self._doc = doc
353
353
354 def key(self):
354 def key(self):
355 return self._name
355 return self._name
356
356
357 def doc(self, obj):
357 def doc(self, obj):
358 return self._doc
358 return self._doc
359
359
360 def attrtype(self, obj):
360 def attrtype(self, obj):
361 return "attr"
361 return "attr"
362
362
363 def valuetype(self, obj):
363 def valuetype(self, obj):
364 return type(getattr(obj, self._name))
364 return type(getattr(obj, self._name))
365
365
366 def value(self, obj):
366 def value(self, obj):
367 return getattr(obj, self._name)
367 return getattr(obj, self._name)
368
368
369 def __repr__(self):
369 def __repr__(self):
370 if self._doc is None:
370 if self._doc is None:
371 return "Attribute(%r)" % self._name
371 return "Attribute(%r)" % self._name
372 else:
372 else:
373 return "Attribute(%r, %r)" % (self._name, self._doc)
373 return "Attribute(%r, %r)" % (self._name, self._doc)
374
374
375
375
376 class IndexDescriptor(Descriptor):
376 class IndexDescriptor(Descriptor):
377 """
377 """
378 An ``IndexDescriptor`` describes an "attribute" of an object that is fetched
378 An ``IndexDescriptor`` describes an "attribute" of an object that is fetched
379 via ``__getitem__``.
379 via ``__getitem__``.
380 """
380 """
381 __slots__ = ("_index",)
381 __slots__ = ("_index",)
382
382
383 def __init__(self, index):
383 def __init__(self, index):
384 self._index = index
384 self._index = index
385
385
386 def key(self):
386 def key(self):
387 return self._index
387 return self._index
388
388
389 def attrtype(self, obj):
389 def attrtype(self, obj):
390 return "item"
390 return "item"
391
391
392 def valuetype(self, obj):
392 def valuetype(self, obj):
393 return type(obj[self._index])
393 return type(obj[self._index])
394
394
395 def value(self, obj):
395 def value(self, obj):
396 return obj[self._index]
396 return obj[self._index]
397
397
398 def __repr__(self):
398 def __repr__(self):
399 return "Index(%r)" % self._index
399 return "Index(%r)" % self._index
400
400
401
401
402 class MethodDescriptor(Descriptor):
402 class MethodDescriptor(Descriptor):
403 """
403 """
404 A ``MethodDescriptor`` describes a method of an object that can be called
404 A ``MethodDescriptor`` describes a method of an object that can be called
405 without argument. Note that this method shouldn't change the object.
405 without argument. Note that this method shouldn't change the object.
406 """
406 """
407 __slots__ = ("_name", "_doc")
407 __slots__ = ("_name", "_doc")
408
408
409 def __init__(self, name, doc=None):
409 def __init__(self, name, doc=None):
410 self._name = name
410 self._name = name
411 self._doc = doc
411 self._doc = doc
412
412
413 def key(self):
413 def key(self):
414 return self._name
414 return self._name
415
415
416 def doc(self, obj):
416 def doc(self, obj):
417 if self._doc is None:
417 if self._doc is None:
418 return getattr(obj, self._name).__doc__
418 return getattr(obj, self._name).__doc__
419 return self._doc
419 return self._doc
420
420
421 def attrtype(self, obj):
421 def attrtype(self, obj):
422 return "method"
422 return "method"
423
423
424 def valuetype(self, obj):
424 def valuetype(self, obj):
425 return type(self.value(obj))
425 return type(self.value(obj))
426
426
427 def value(self, obj):
427 def value(self, obj):
428 return getattr(obj, self._name)()
428 return getattr(obj, self._name)()
429
429
430 def __repr__(self):
430 def __repr__(self):
431 if self._doc is None:
431 if self._doc is None:
432 return "Method(%r)" % self._name
432 return "Method(%r)" % self._name
433 else:
433 else:
434 return "Method(%r, %r)" % (self._name, self._doc)
434 return "Method(%r, %r)" % (self._name, self._doc)
435
435
436
436
437 class IterAttributeDescriptor(Descriptor):
437 class IterAttributeDescriptor(Descriptor):
438 """
438 """
439 An ``IterAttributeDescriptor`` works like an ``AttributeDescriptor`` but
439 An ``IterAttributeDescriptor`` works like an ``AttributeDescriptor`` but
440 doesn't return an attribute values (because this value might be e.g. a large
440 doesn't return an attribute values (because this value might be e.g. a large
441 list).
441 list).
442 """
442 """
443 __slots__ = ("_name", "_doc")
443 __slots__ = ("_name", "_doc")
444
444
445 def __init__(self, name, doc=None):
445 def __init__(self, name, doc=None):
446 self._name = name
446 self._name = name
447 self._doc = doc
447 self._doc = doc
448
448
449 def key(self):
449 def key(self):
450 return self._name
450 return self._name
451
451
452 def doc(self, obj):
452 def doc(self, obj):
453 return self._doc
453 return self._doc
454
454
455 def attrtype(self, obj):
455 def attrtype(self, obj):
456 return "iter"
456 return "iter"
457
457
458 def valuetype(self, obj):
458 def valuetype(self, obj):
459 return noitem
459 return noitem
460
460
461 def value(self, obj):
461 def value(self, obj):
462 return noitem
462 return noitem
463
463
464 def iter(self, obj):
464 def iter(self, obj):
465 return xiter(getattr(obj, self._name))
465 return xiter(getattr(obj, self._name))
466
466
467 def __repr__(self):
467 def __repr__(self):
468 if self._doc is None:
468 if self._doc is None:
469 return "IterAttribute(%r)" % self._name
469 return "IterAttribute(%r)" % self._name
470 else:
470 else:
471 return "IterAttribute(%r, %r)" % (self._name, self._doc)
471 return "IterAttribute(%r, %r)" % (self._name, self._doc)
472
472
473
473
474 class IterMethodDescriptor(Descriptor):
474 class IterMethodDescriptor(Descriptor):
475 """
475 """
476 An ``IterMethodDescriptor`` works like an ``MethodDescriptor`` but doesn't
476 An ``IterMethodDescriptor`` works like an ``MethodDescriptor`` but doesn't
477 return an attribute values (because this value might be e.g. a large list).
477 return an attribute values (because this value might be e.g. a large list).
478 """
478 """
479 __slots__ = ("_name", "_doc")
479 __slots__ = ("_name", "_doc")
480
480
481 def __init__(self, name, doc=None):
481 def __init__(self, name, doc=None):
482 self._name = name
482 self._name = name
483 self._doc = doc
483 self._doc = doc
484
484
485 def key(self):
485 def key(self):
486 return self._name
486 return self._name
487
487
488 def doc(self, obj):
488 def doc(self, obj):
489 if self._doc is None:
489 if self._doc is None:
490 return getattr(obj, self._name).__doc__
490 return getattr(obj, self._name).__doc__
491 return self._doc
491 return self._doc
492
492
493 def attrtype(self, obj):
493 def attrtype(self, obj):
494 return "itermethod"
494 return "itermethod"
495
495
496 def valuetype(self, obj):
496 def valuetype(self, obj):
497 return noitem
497 return noitem
498
498
499 def value(self, obj):
499 def value(self, obj):
500 return noitem
500 return noitem
501
501
502 def iter(self, obj):
502 def iter(self, obj):
503 return xiter(getattr(obj, self._name)())
503 return xiter(getattr(obj, self._name)())
504
504
505 def __repr__(self):
505 def __repr__(self):
506 if self._doc is None:
506 if self._doc is None:
507 return "IterMethod(%r)" % self._name
507 return "IterMethod(%r)" % self._name
508 else:
508 else:
509 return "IterMethod(%r, %r)" % (self._name, self._doc)
509 return "IterMethod(%r, %r)" % (self._name, self._doc)
510
510
511
511
512 class FunctionDescriptor(Descriptor):
512 class FunctionDescriptor(Descriptor):
513 """
513 """
514 A ``FunctionDescriptor`` turns a function into a descriptor. The function
514 A ``FunctionDescriptor`` turns a function into a descriptor. The function
515 will be called with the object to get the type and value of the attribute.
515 will be called with the object to get the type and value of the attribute.
516 """
516 """
517 __slots__ = ("_function", "_name", "_doc")
517 __slots__ = ("_function", "_name", "_doc")
518
518
519 def __init__(self, function, name=None, doc=None):
519 def __init__(self, function, name=None, doc=None):
520 self._function = function
520 self._function = function
521 self._name = name
521 self._name = name
522 self._doc = doc
522 self._doc = doc
523
523
524 def key(self):
524 def key(self):
525 return self._function
525 return self._function
526
526
527 def name(self):
527 def name(self):
528 if self._name is not None:
528 if self._name is not None:
529 return self._name
529 return self._name
530 return getattr(self._function, "__xname__", self._function.__name__)
530 return getattr(self._function, "__xname__", self._function.__name__)
531
531
532 def doc(self, obj):
532 def doc(self, obj):
533 if self._doc is None:
533 if self._doc is None:
534 return self._function.__doc__
534 return self._function.__doc__
535 return self._doc
535 return self._doc
536
536
537 def attrtype(self, obj):
537 def attrtype(self, obj):
538 return "function"
538 return "function"
539
539
540 def valuetype(self, obj):
540 def valuetype(self, obj):
541 return type(self._function(obj))
541 return type(self._function(obj))
542
542
543 def value(self, obj):
543 def value(self, obj):
544 return self._function(obj)
544 return self._function(obj)
545
545
546 def __repr__(self):
546 def __repr__(self):
547 if self._doc is None:
547 if self._doc is None:
548 return "Function(%r)" % self._name
548 return "Function(%r)" % self._name
549 else:
549 else:
550 return "Function(%r, %r)" % (self._name, self._doc)
550 return "Function(%r, %r)" % (self._name, self._doc)
551
551
552
552
553 class Table(object):
553 class Table(object):
554 """
554 """
555 A ``Table`` is an object that produces items (just like a normal Python
555 A ``Table`` is an object that produces items (just like a normal Python
556 iterator/generator does) and can be used as the first object in a pipeline
556 iterator/generator does) and can be used as the first object in a pipeline
557 expression. The displayhook will open the default browser for such an object
557 expression. The displayhook will open the default browser for such an object
558 (instead of simply printing the ``repr()`` result).
558 (instead of simply printing the ``repr()`` result).
559 """
559 """
560
560
561 # We want to support ``foo`` and ``foo()`` in pipeline expression:
561 # We want to support ``foo`` and ``foo()`` in pipeline expression:
562 # So we implement the required operators (``|`` and ``+``) in the metaclass,
562 # So we implement the required operators (``|`` and ``+``) in the metaclass,
563 # instantiate the class and forward the operator to the instance
563 # instantiate the class and forward the operator to the instance
564 class __metaclass__(type):
564 class __metaclass__(type):
565 def __iter__(self):
565 def __iter__(self):
566 return iter(self())
566 return iter(self())
567
567
568 def __or__(self, other):
568 def __or__(self, other):
569 return self() | other
569 return self() | other
570
570
571 def __add__(self, other):
571 def __add__(self, other):
572 return self() + other
572 return self() + other
573
573
574 def __radd__(self, other):
574 def __radd__(self, other):
575 return other + self()
575 return other + self()
576
576
577 def __getitem__(self, index):
577 def __getitem__(self, index):
578 return self()[index]
578 return self()[index]
579
579
580 def __getitem__(self, index):
580 def __getitem__(self, index):
581 return item(self, index)
581 return item(self, index)
582
582
583 def __contains__(self, item):
583 def __contains__(self, item):
584 for haveitem in self:
584 for haveitem in self:
585 if item == haveitem:
585 if item == haveitem:
586 return True
586 return True
587 return False
587 return False
588
588
589 def __or__(self, other):
589 def __or__(self, other):
590 # autoinstantiate right hand side
590 # autoinstantiate right hand side
591 if isinstance(other, type) and issubclass(other, (Table, Display)):
591 if isinstance(other, type) and issubclass(other, (Table, Display)):
592 other = other()
592 other = other()
593 # treat simple strings and functions as ``ieval`` instances
593 # treat simple strings and functions as ``ieval`` instances
594 elif not isinstance(other, Display) and not isinstance(other, Table):
594 elif not isinstance(other, Display) and not isinstance(other, Table):
595 other = ieval(other)
595 other = ieval(other)
596 # forward operations to the right hand side
596 # forward operations to the right hand side
597 return other.__ror__(self)
597 return other.__ror__(self)
598
598
599 def __add__(self, other):
599 def __add__(self, other):
600 # autoinstantiate right hand side
600 # autoinstantiate right hand side
601 if isinstance(other, type) and issubclass(other, Table):
601 if isinstance(other, type) and issubclass(other, Table):
602 other = other()
602 other = other()
603 return ichain(self, other)
603 return ichain(self, other)
604
604
605 def __radd__(self, other):
605 def __radd__(self, other):
606 # autoinstantiate left hand side
606 # autoinstantiate left hand side
607 if isinstance(other, type) and issubclass(other, Table):
607 if isinstance(other, type) and issubclass(other, Table):
608 other = other()
608 other = other()
609 return ichain(other, self)
609 return ichain(other, self)
610
610
611
611
612 class Pipe(Table):
612 class Pipe(Table):
613 """
613 """
614 A ``Pipe`` is an object that can be used in a pipeline expression. It
614 A ``Pipe`` is an object that can be used in a pipeline expression. It
615 processes the objects it gets from its input ``Table``/``Pipe``. Note that
615 processes the objects it gets from its input ``Table``/``Pipe``. Note that
616 a ``Pipe`` object can't be used as the first object in a pipeline
616 a ``Pipe`` object can't be used as the first object in a pipeline
617 expression, as it doesn't produces items itself.
617 expression, as it doesn't produces items itself.
618 """
618 """
619 class __metaclass__(Table.__metaclass__):
619 class __metaclass__(Table.__metaclass__):
620 def __ror__(self, input):
620 def __ror__(self, input):
621 return input | self()
621 return input | self()
622
622
623 def __ror__(self, input):
623 def __ror__(self, input):
624 # autoinstantiate left hand side
624 # autoinstantiate left hand side
625 if isinstance(input, type) and issubclass(input, Table):
625 if isinstance(input, type) and issubclass(input, Table):
626 input = input()
626 input = input()
627 self.input = input
627 self.input = input
628 return self
628 return self
629
629
630
630
631 def xrepr(item, mode="default"):
631 def xrepr(item, mode="default"):
632 """
632 """
633 Generic function that adds color output and different display modes to ``repr``.
633 Generic function that adds color output and different display modes to ``repr``.
634
634
635 The result of an ``xrepr`` call is iterable and consists of ``(style, string)``
635 The result of an ``xrepr`` call is iterable and consists of ``(style, string)``
636 tuples. The ``style`` in this tuple must be a ``Style`` object from the
636 tuples. The ``style`` in this tuple must be a ``Style`` object from the
637 ``astring`` module. To reconfigure the output the first yielded tuple can be
637 ``astring`` module. To reconfigure the output the first yielded tuple can be
638 a ``(aligment, full)`` tuple instead of a ``(style, string)`` tuple.
638 a ``(aligment, full)`` tuple instead of a ``(style, string)`` tuple.
639 ``alignment`` can be -1 for left aligned, 0 for centered and 1 for right
639 ``alignment`` can be -1 for left aligned, 0 for centered and 1 for right
640 aligned (the default is left alignment). ``full`` is a boolean that specifies
640 aligned (the default is left alignment). ``full`` is a boolean that specifies
641 whether the complete output must be displayed or the ``Display`` object is
641 whether the complete output must be displayed or the ``Display`` object is
642 allowed to stop output after enough text has been produced (e.g. a syntax
642 allowed to stop output after enough text has been produced (e.g. a syntax
643 highlighted text line would use ``True``, but for a large data structure
643 highlighted text line would use ``True``, but for a large data structure
644 (i.e. a nested list, tuple or dictionary) ``False`` would be used).
644 (i.e. a nested list, tuple or dictionary) ``False`` would be used).
645 The default is full output.
645 The default is full output.
646
646
647 There are four different possible values for ``mode`` depending on where
647 There are four different possible values for ``mode`` depending on where
648 the ``Display`` object will display ``item``:
648 the ``Display`` object will display ``item``:
649
649
650 ``"header"``
650 ``"header"``
651 ``item`` will be displayed in a header line (this is used by ``ibrowse``).
651 ``item`` will be displayed in a header line (this is used by ``ibrowse``).
652
652
653 ``"footer"``
653 ``"footer"``
654 ``item`` will be displayed in a footer line (this is used by ``ibrowse``).
654 ``item`` will be displayed in a footer line (this is used by ``ibrowse``).
655
655
656 ``"cell"``
656 ``"cell"``
657 ``item`` will be displayed in a table cell/list.
657 ``item`` will be displayed in a table cell/list.
658
658
659 ``"default"``
659 ``"default"``
660 default mode. If an ``xrepr`` implementation recursively outputs objects,
660 default mode. If an ``xrepr`` implementation recursively outputs objects,
661 ``"default"`` must be passed in the recursive calls to ``xrepr``.
661 ``"default"`` must be passed in the recursive calls to ``xrepr``.
662
662
663 If no implementation is registered for ``item``, ``xrepr`` will try the
663 If no implementation is registered for ``item``, ``xrepr`` will try the
664 ``__xrepr__`` method on ``item``. If ``item`` doesn't have an ``__xrepr__``
664 ``__xrepr__`` method on ``item``. If ``item`` doesn't have an ``__xrepr__``
665 method it falls back to ``repr``/``__repr__`` for all modes.
665 method it falls back to ``repr``/``__repr__`` for all modes.
666 """
666 """
667 try:
667 try:
668 func = item.__xrepr__
668 func = item.__xrepr__
669 except AttributeError:
669 except AttributeError:
670 yield (astyle.style_default, repr(item))
670 yield (astyle.style_default, repr(item))
671 else:
671 else:
672 try:
672 try:
673 for x in func(mode):
673 for x in func(mode):
674 yield x
674 yield x
675 except (KeyboardInterrupt, SystemExit, GeneratorExit):
675 except (KeyboardInterrupt, SystemExit, GeneratorExit):
676 raise
676 raise
677 except Exception:
677 except Exception:
678 yield (astyle.style_default, repr(item))
678 yield (astyle.style_default, repr(item))
679 xrepr = simplegeneric.generic(xrepr)
679 xrepr = simplegeneric.generic(xrepr)
680
680
681
681
682 def xrepr_none(self, mode="default"):
682 def xrepr_none(self, mode="default"):
683 yield (astyle.style_type_none, repr(self))
683 yield (astyle.style_type_none, repr(self))
684 xrepr.when_object(None)(xrepr_none)
684 xrepr.when_object(None)(xrepr_none)
685
685
686
686
687 def xrepr_noitem(self, mode="default"):
687 def xrepr_noitem(self, mode="default"):
688 yield (2, True)
688 yield (2, True)
689 yield (astyle.style_nodata, "<?>")
689 yield (astyle.style_nodata, "<?>")
690 xrepr.when_object(noitem)(xrepr_noitem)
690 xrepr.when_object(noitem)(xrepr_noitem)
691
691
692
692
693 def xrepr_bool(self, mode="default"):
693 def xrepr_bool(self, mode="default"):
694 yield (astyle.style_type_bool, repr(self))
694 yield (astyle.style_type_bool, repr(self))
695 xrepr.when_type(bool)(xrepr_bool)
695 xrepr.when_type(bool)(xrepr_bool)
696
696
697
697
698 def xrepr_str(self, mode="default"):
698 def xrepr_str(self, mode="default"):
699 if mode == "cell":
699 if mode == "cell":
700 yield (astyle.style_default, repr(self.expandtabs(tab))[1:-1])
700 yield (astyle.style_default, repr(self.expandtabs(tab))[1:-1])
701 else:
701 else:
702 yield (astyle.style_default, repr(self))
702 yield (astyle.style_default, repr(self))
703 xrepr.when_type(str)(xrepr_str)
703 xrepr.when_type(str)(xrepr_str)
704
704
705
705
706 def xrepr_unicode(self, mode="default"):
706 def xrepr_unicode(self, mode="default"):
707 if mode == "cell":
707 if mode == "cell":
708 yield (astyle.style_default, repr(self.expandtabs(tab))[2:-1])
708 yield (astyle.style_default, repr(self.expandtabs(tab))[2:-1])
709 else:
709 else:
710 yield (astyle.style_default, repr(self))
710 yield (astyle.style_default, repr(self))
711 xrepr.when_type(unicode)(xrepr_unicode)
711 xrepr.when_type(unicode)(xrepr_unicode)
712
712
713
713
714 def xrepr_number(self, mode="default"):
714 def xrepr_number(self, mode="default"):
715 yield (1, True)
715 yield (1, True)
716 yield (astyle.style_type_number, repr(self))
716 yield (astyle.style_type_number, repr(self))
717 xrepr.when_type(int)(xrepr_number)
717 xrepr.when_type(int)(xrepr_number)
718 xrepr.when_type(long)(xrepr_number)
718 xrepr.when_type(long)(xrepr_number)
719 xrepr.when_type(float)(xrepr_number)
719 xrepr.when_type(float)(xrepr_number)
720
720
721
721
722 def xrepr_complex(self, mode="default"):
722 def xrepr_complex(self, mode="default"):
723 yield (astyle.style_type_number, repr(self))
723 yield (astyle.style_type_number, repr(self))
724 xrepr.when_type(complex)(xrepr_number)
724 xrepr.when_type(complex)(xrepr_number)
725
725
726
726
727 def xrepr_datetime(self, mode="default"):
727 def xrepr_datetime(self, mode="default"):
728 if mode == "cell":
728 if mode == "cell":
729 # Don't use strftime() here, as this requires year >= 1900
729 # Don't use strftime() here, as this requires year >= 1900
730 yield (astyle.style_type_datetime,
730 yield (astyle.style_type_datetime,
731 "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \
731 "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \
732 (self.year, self.month, self.day,
732 (self.year, self.month, self.day,
733 self.hour, self.minute, self.second,
733 self.hour, self.minute, self.second,
734 self.microsecond),
734 self.microsecond),
735 )
735 )
736 else:
736 else:
737 yield (astyle.style_type_datetime, repr(self))
737 yield (astyle.style_type_datetime, repr(self))
738 xrepr.when_type(datetime.datetime)(xrepr_datetime)
738 xrepr.when_type(datetime.datetime)(xrepr_datetime)
739
739
740
740
741 def xrepr_date(self, mode="default"):
741 def xrepr_date(self, mode="default"):
742 if mode == "cell":
742 if mode == "cell":
743 yield (astyle.style_type_datetime,
743 yield (astyle.style_type_datetime,
744 "%04d-%02d-%02d" % (self.year, self.month, self.day))
744 "%04d-%02d-%02d" % (self.year, self.month, self.day))
745 else:
745 else:
746 yield (astyle.style_type_datetime, repr(self))
746 yield (astyle.style_type_datetime, repr(self))
747 xrepr.when_type(datetime.date)(xrepr_date)
747 xrepr.when_type(datetime.date)(xrepr_date)
748
748
749
749
750 def xrepr_time(self, mode="default"):
750 def xrepr_time(self, mode="default"):
751 if mode == "cell":
751 if mode == "cell":
752 yield (astyle.style_type_datetime,
752 yield (astyle.style_type_datetime,
753 "%02d:%02d:%02d.%06d" % \
753 "%02d:%02d:%02d.%06d" % \
754 (self.hour, self.minute, self.second, self.microsecond))
754 (self.hour, self.minute, self.second, self.microsecond))
755 else:
755 else:
756 yield (astyle.style_type_datetime, repr(self))
756 yield (astyle.style_type_datetime, repr(self))
757 xrepr.when_type(datetime.time)(xrepr_time)
757 xrepr.when_type(datetime.time)(xrepr_time)
758
758
759
759
760 def xrepr_timedelta(self, mode="default"):
760 def xrepr_timedelta(self, mode="default"):
761 yield (astyle.style_type_datetime, repr(self))
761 yield (astyle.style_type_datetime, repr(self))
762 xrepr.when_type(datetime.timedelta)(xrepr_timedelta)
762 xrepr.when_type(datetime.timedelta)(xrepr_timedelta)
763
763
764
764
765 def xrepr_type(self, mode="default"):
765 def xrepr_type(self, mode="default"):
766 if self.__module__ == "__builtin__":
766 if self.__module__ == "__builtin__":
767 yield (astyle.style_type_type, self.__name__)
767 yield (astyle.style_type_type, self.__name__)
768 else:
768 else:
769 yield (astyle.style_type_type, "%s.%s" % (self.__module__, self.__name__))
769 yield (astyle.style_type_type, "%s.%s" % (self.__module__, self.__name__))
770 xrepr.when_type(type)(xrepr_type)
770 xrepr.when_type(type)(xrepr_type)
771
771
772
772
773 def xrepr_exception(self, mode="default"):
773 def xrepr_exception(self, mode="default"):
774 if self.__class__.__module__ == "exceptions":
774 if self.__class__.__module__ == "exceptions":
775 classname = self.__class__.__name__
775 classname = self.__class__.__name__
776 else:
776 else:
777 classname = "%s.%s" % \
777 classname = "%s.%s" % \
778 (self.__class__.__module__, self.__class__.__name__)
778 (self.__class__.__module__, self.__class__.__name__)
779 if mode == "header" or mode == "footer":
779 if mode == "header" or mode == "footer":
780 yield (astyle.style_error, "%s: %s" % (classname, self))
780 yield (astyle.style_error, "%s: %s" % (classname, self))
781 else:
781 else:
782 yield (astyle.style_error, classname)
782 yield (astyle.style_error, classname)
783 xrepr.when_type(Exception)(xrepr_exception)
783 xrepr.when_type(Exception)(xrepr_exception)
784
784
785
785
786 def xrepr_listtuple(self, mode="default"):
786 def xrepr_listtuple(self, mode="default"):
787 if mode == "header" or mode == "footer":
787 if mode == "header" or mode == "footer":
788 if self.__class__.__module__ == "__builtin__":
788 if self.__class__.__module__ == "__builtin__":
789 classname = self.__class__.__name__
789 classname = self.__class__.__name__
790 else:
790 else:
791 classname = "%s.%s" % \
791 classname = "%s.%s" % \
792 (self.__class__.__module__,self.__class__.__name__)
792 (self.__class__.__module__,self.__class__.__name__)
793 yield (astyle.style_default,
793 yield (astyle.style_default,
794 "<%s object with %d items at 0x%x>" % \
794 "<%s object with %d items at 0x%x>" % \
795 (classname, len(self), id(self)))
795 (classname, len(self), id(self)))
796 else:
796 else:
797 yield (-1, False)
797 yield (-1, False)
798 if isinstance(self, list):
798 if isinstance(self, list):
799 yield (astyle.style_default, "[")
799 yield (astyle.style_default, "[")
800 end = "]"
800 end = "]"
801 else:
801 else:
802 yield (astyle.style_default, "(")
802 yield (astyle.style_default, "(")
803 end = ")"
803 end = ")"
804 for (i, subself) in enumerate(self):
804 for (i, subself) in enumerate(self):
805 if i:
805 if i:
806 yield (astyle.style_default, ", ")
806 yield (astyle.style_default, ", ")
807 for part in xrepr(subself, "default"):
807 for part in xrepr(subself, "default"):
808 yield part
808 yield part
809 yield (astyle.style_default, end)
809 yield (astyle.style_default, end)
810 xrepr.when_type(list)(xrepr_listtuple)
810 xrepr.when_type(list)(xrepr_listtuple)
811 xrepr.when_type(tuple)(xrepr_listtuple)
811 xrepr.when_type(tuple)(xrepr_listtuple)
812
812
813
813
814 def xrepr_dict(self, mode="default"):
814 def xrepr_dict(self, mode="default"):
815 if mode == "header" or mode == "footer":
815 if mode == "header" or mode == "footer":
816 if self.__class__.__module__ == "__builtin__":
816 if self.__class__.__module__ == "__builtin__":
817 classname = self.__class__.__name__
817 classname = self.__class__.__name__
818 else:
818 else:
819 classname = "%s.%s" % \
819 classname = "%s.%s" % \
820 (self.__class__.__module__,self.__class__.__name__)
820 (self.__class__.__module__,self.__class__.__name__)
821 yield (astyle.style_default,
821 yield (astyle.style_default,
822 "<%s object with %d items at 0x%x>" % \
822 "<%s object with %d items at 0x%x>" % \
823 (classname, len(self), id(self)))
823 (classname, len(self), id(self)))
824 else:
824 else:
825 yield (-1, False)
825 yield (-1, False)
826 if isinstance(self, dict):
826 if isinstance(self, dict):
827 yield (astyle.style_default, "{")
827 yield (astyle.style_default, "{")
828 end = "}"
828 end = "}"
829 else:
829 else:
830 yield (astyle.style_default, "dictproxy((")
830 yield (astyle.style_default, "dictproxy((")
831 end = "})"
831 end = "})"
832 for (i, (key, value)) in enumerate(self.iteritems()):
832 for (i, (key, value)) in enumerate(self.iteritems()):
833 if i:
833 if i:
834 yield (astyle.style_default, ", ")
834 yield (astyle.style_default, ", ")
835 for part in xrepr(key, "default"):
835 for part in xrepr(key, "default"):
836 yield part
836 yield part
837 yield (astyle.style_default, ": ")
837 yield (astyle.style_default, ": ")
838 for part in xrepr(value, "default"):
838 for part in xrepr(value, "default"):
839 yield part
839 yield part
840 yield (astyle.style_default, end)
840 yield (astyle.style_default, end)
841 xrepr.when_type(dict)(xrepr_dict)
841 xrepr.when_type(dict)(xrepr_dict)
842 xrepr.when_type(types.DictProxyType)(xrepr_dict)
842 xrepr.when_type(types.DictProxyType)(xrepr_dict)
843
843
844
844
845 def upgradexattr(attr):
845 def upgradexattr(attr):
846 """
846 """
847 Convert an attribute descriptor string to a real descriptor object.
847 Convert an attribute descriptor string to a real descriptor object.
848
848
849 If attr already is a descriptor object return it unmodified. A
849 If attr already is a descriptor object return it unmodified. A
850 ``SelfDescriptor`` will be returned if ``attr`` is ``None``. ``"foo"``
850 ``SelfDescriptor`` will be returned if ``attr`` is ``None``. ``"foo"``
851 returns an ``AttributeDescriptor`` for the attribute named ``"foo"``.
851 returns an ``AttributeDescriptor`` for the attribute named ``"foo"``.
852 ``"foo()"`` returns a ``MethodDescriptor`` for the method named ``"foo"``.
852 ``"foo()"`` returns a ``MethodDescriptor`` for the method named ``"foo"``.
853 ``"-foo"`` will return an ``IterAttributeDescriptor`` for the attribute
853 ``"-foo"`` will return an ``IterAttributeDescriptor`` for the attribute
854 named ``"foo"`` and ``"-foo()"`` will return an ``IterMethodDescriptor``
854 named ``"foo"`` and ``"-foo()"`` will return an ``IterMethodDescriptor``
855 for the method named ``"foo"``. Furthermore integers will return the appropriate
855 for the method named ``"foo"``. Furthermore integers will return the appropriate
856 ``IndexDescriptor`` and callables will return a ``FunctionDescriptor``.
856 ``IndexDescriptor`` and callables will return a ``FunctionDescriptor``.
857 """
857 """
858 if attr is None:
858 if attr is None:
859 return selfdescriptor
859 return selfdescriptor
860 elif isinstance(attr, Descriptor):
860 elif isinstance(attr, Descriptor):
861 return attr
861 return attr
862 elif isinstance(attr, basestring):
862 elif isinstance(attr, basestring):
863 if attr.endswith("()"):
863 if attr.endswith("()"):
864 if attr.startswith("-"):
864 if attr.startswith("-"):
865 return IterMethodDescriptor(attr[1:-2])
865 return IterMethodDescriptor(attr[1:-2])
866 else:
866 else:
867 return MethodDescriptor(attr[:-2])
867 return MethodDescriptor(attr[:-2])
868 else:
868 else:
869 if attr.startswith("-"):
869 if attr.startswith("-"):
870 return IterAttributeDescriptor(attr[1:])
870 return IterAttributeDescriptor(attr[1:])
871 else:
871 else:
872 return AttributeDescriptor(attr)
872 return AttributeDescriptor(attr)
873 elif isinstance(attr, (int, long)):
873 elif isinstance(attr, (int, long)):
874 return IndexDescriptor(attr)
874 return IndexDescriptor(attr)
875 elif callable(attr):
875 elif callable(attr):
876 return FunctionDescriptor(attr)
876 return FunctionDescriptor(attr)
877 else:
877 else:
878 raise TypeError("can't handle descriptor %r" % attr)
878 raise TypeError("can't handle descriptor %r" % attr)
879
879
880
880
881 def xattrs(item, mode="default"):
881 def xattrs(item, mode="default"):
882 """
882 """
883 Generic function that returns an iterable of attribute descriptors
883 Generic function that returns an iterable of attribute descriptors
884 to be used for displaying the attributes ob the object ``item`` in display
884 to be used for displaying the attributes ob the object ``item`` in display
885 mode ``mode``.
885 mode ``mode``.
886
886
887 There are two possible modes:
887 There are two possible modes:
888
888
889 ``"detail"``
889 ``"detail"``
890 The ``Display`` object wants to display a detailed list of the object
890 The ``Display`` object wants to display a detailed list of the object
891 attributes.
891 attributes.
892
892
893 ``"default"``
893 ``"default"``
894 The ``Display`` object wants to display the object in a list view.
894 The ``Display`` object wants to display the object in a list view.
895
895
896 If no implementation is registered for the object ``item`` ``xattrs`` falls
896 If no implementation is registered for the object ``item`` ``xattrs`` falls
897 back to trying the ``__xattrs__`` method of the object. If this doesn't
897 back to trying the ``__xattrs__`` method of the object. If this doesn't
898 exist either, ``dir(item)`` is used for ``"detail"`` mode and ``(None,)``
898 exist either, ``dir(item)`` is used for ``"detail"`` mode and ``(None,)``
899 for ``"default"`` mode.
899 for ``"default"`` mode.
900
900
901 The implementation must yield attribute descriptors (see the class
901 The implementation must yield attribute descriptors (see the class
902 ``Descriptor`` for more info). The ``__xattrs__`` method may also return
902 ``Descriptor`` for more info). The ``__xattrs__`` method may also return
903 attribute descriptor strings (and ``None``) which will be converted to real
903 attribute descriptor strings (and ``None``) which will be converted to real
904 descriptors by ``upgradexattr()``.
904 descriptors by ``upgradexattr()``.
905 """
905 """
906 try:
906 try:
907 func = item.__xattrs__
907 func = item.__xattrs__
908 except AttributeError:
908 except AttributeError:
909 if mode == "detail":
909 if mode == "detail":
910 for attrname in dir(item):
910 for attrname in dir(item):
911 yield AttributeDescriptor(attrname)
911 yield AttributeDescriptor(attrname)
912 else:
912 else:
913 yield selfdescriptor
913 yield selfdescriptor
914 else:
914 else:
915 for attr in func(mode):
915 for attr in func(mode):
916 yield upgradexattr(attr)
916 yield upgradexattr(attr)
917 xattrs = simplegeneric.generic(xattrs)
917 xattrs = simplegeneric.generic(xattrs)
918
918
919
919
920 def xattrs_complex(self, mode="default"):
920 def xattrs_complex(self, mode="default"):
921 if mode == "detail":
921 if mode == "detail":
922 return (AttributeDescriptor("real"), AttributeDescriptor("imag"))
922 return (AttributeDescriptor("real"), AttributeDescriptor("imag"))
923 return (selfdescriptor,)
923 return (selfdescriptor,)
924 xattrs.when_type(complex)(xattrs_complex)
924 xattrs.when_type(complex)(xattrs_complex)
925
925
926
926
927 def _isdict(item):
927 def _isdict(item):
928 try:
928 try:
929 itermeth = item.__class__.__iter__
929 itermeth = item.__class__.__iter__
930 except (AttributeError, TypeError):
930 except (AttributeError, TypeError):
931 return False
931 return False
932 return itermeth is dict.__iter__ or itermeth is types.DictProxyType.__iter__
932 return itermeth is dict.__iter__ or itermeth is types.DictProxyType.__iter__
933
933
934
934
935 def _isstr(item):
935 def _isstr(item):
936 if not isinstance(item, basestring):
936 if not isinstance(item, basestring):
937 return False
937 return False
938 try:
938 try:
939 itermeth = item.__class__.__iter__
939 itermeth = item.__class__.__iter__
940 except AttributeError:
940 except AttributeError:
941 return True
941 return True
942 return False # ``__iter__`` has been redefined
942 return False # ``__iter__`` has been redefined
943
943
944
944
945 def xiter(item):
945 def xiter(item):
946 """
946 """
947 Generic function that implements iteration for pipeline expression. If no
947 Generic function that implements iteration for pipeline expression. If no
948 implementation is registered for ``item`` ``xiter`` falls back to ``iter``.
948 implementation is registered for ``item`` ``xiter`` falls back to ``iter``.
949 """
949 """
950 try:
950 try:
951 func = item.__xiter__
951 func = item.__xiter__
952 except AttributeError:
952 except AttributeError:
953 if _isdict(item):
953 if _isdict(item):
954 def items(item):
954 def items(item):
955 fields = ("key", "value")
955 fields = ("key", "value")
956 for (key, value) in item.iteritems():
956 for (key, value) in item.iteritems():
957 yield Fields(fields, key=key, value=value)
957 yield Fields(fields, key=key, value=value)
958 return items(item)
958 return items(item)
959 elif isinstance(item, new.module):
959 elif isinstance(item, new.module):
960 def items(item):
960 def items(item):
961 fields = ("key", "value")
961 fields = ("key", "value")
962 for key in sorted(item.__dict__):
962 for key in sorted(item.__dict__):
963 yield Fields(fields, key=key, value=getattr(item, key))
963 yield Fields(fields, key=key, value=getattr(item, key))
964 return items(item)
964 return items(item)
965 elif _isstr(item):
965 elif _isstr(item):
966 if not item:
966 if not item:
967 raise ValueError("can't enter empty string")
967 raise ValueError("can't enter empty string")
968 lines = item.splitlines()
968 lines = item.splitlines()
969 if len(lines) == 1:
969 if len(lines) == 1:
970 def iterone(item):
970 def iterone(item):
971 yield item
971 yield item
972 return iterone(item)
972 return iterone(item)
973 else:
973 else:
974 return iter(lines)
974 return iter(lines)
975 return iter(item)
975 return iter(item)
976 else:
976 else:
977 return iter(func()) # iter() just to be safe
977 return iter(func()) # iter() just to be safe
978 xiter = simplegeneric.generic(xiter)
978 xiter = simplegeneric.generic(xiter)
979
979
980
980
981 class ichain(Pipe):
981 class ichain(Pipe):
982 """
982 """
983 Chains multiple ``Table``s into one.
983 Chains multiple ``Table``s into one.
984 """
984 """
985
985
986 def __init__(self, *iters):
986 def __init__(self, *iters):
987 self.iters = iters
987 self.iters = iters
988
988
989 def __iter__(self):
989 def __iter__(self):
990 return itertools.chain(*self.iters)
990 return itertools.chain(*self.iters)
991
991
992 def __xrepr__(self, mode="default"):
992 def __xrepr__(self, mode="default"):
993 if mode == "header" or mode == "footer":
993 if mode == "header" or mode == "footer":
994 for (i, item) in enumerate(self.iters):
994 for (i, item) in enumerate(self.iters):
995 if i:
995 if i:
996 yield (astyle.style_default, "+")
996 yield (astyle.style_default, "+")
997 if isinstance(item, Pipe):
997 if isinstance(item, Pipe):
998 yield (astyle.style_default, "(")
998 yield (astyle.style_default, "(")
999 for part in xrepr(item, mode):
999 for part in xrepr(item, mode):
1000 yield part
1000 yield part
1001 if isinstance(item, Pipe):
1001 if isinstance(item, Pipe):
1002 yield (astyle.style_default, ")")
1002 yield (astyle.style_default, ")")
1003 else:
1003 else:
1004 yield (astyle.style_default, repr(self))
1004 yield (astyle.style_default, repr(self))
1005
1005
1006 def __repr__(self):
1006 def __repr__(self):
1007 args = ", ".join([repr(it) for it in self.iters])
1007 args = ", ".join([repr(it) for it in self.iters])
1008 return "%s.%s(%s)" % \
1008 return "%s.%s(%s)" % \
1009 (self.__class__.__module__, self.__class__.__name__, args)
1009 (self.__class__.__module__, self.__class__.__name__, args)
1010
1010
1011
1011
1012 class ifile(path.path):
1012 class ifile(path.path):
1013 """
1013 """
1014 file (or directory) object.
1014 file (or directory) object.
1015 """
1015 """
1016
1016
1017 def getmode(self):
1017 def getmode(self):
1018 return self.stat().st_mode
1018 return self.stat().st_mode
1019 mode = property(getmode, None, None, "Access mode")
1019 mode = property(getmode, None, None, "Access mode")
1020
1020
1021 def gettype(self):
1021 def gettype(self):
1022 data = [
1022 data = [
1023 (stat.S_ISREG, "file"),
1023 (stat.S_ISREG, "file"),
1024 (stat.S_ISDIR, "dir"),
1024 (stat.S_ISDIR, "dir"),
1025 (stat.S_ISCHR, "chardev"),
1025 (stat.S_ISCHR, "chardev"),
1026 (stat.S_ISBLK, "blockdev"),
1026 (stat.S_ISBLK, "blockdev"),
1027 (stat.S_ISFIFO, "fifo"),
1027 (stat.S_ISFIFO, "fifo"),
1028 (stat.S_ISLNK, "symlink"),
1028 (stat.S_ISLNK, "symlink"),
1029 (stat.S_ISSOCK,"socket"),
1029 (stat.S_ISSOCK,"socket"),
1030 ]
1030 ]
1031 lstat = self.lstat()
1031 lstat = self.lstat()
1032 if lstat is not None:
1032 if lstat is not None:
1033 types = set([text for (func, text) in data if func(lstat.st_mode)])
1033 types = set([text for (func, text) in data if func(lstat.st_mode)])
1034 else:
1034 else:
1035 types = set()
1035 types = set()
1036 m = self.mode
1036 m = self.mode
1037 types.update([text for (func, text) in data if func(m)])
1037 types.update([text for (func, text) in data if func(m)])
1038 return ", ".join(types)
1038 return ", ".join(types)
1039 type = property(gettype, None, None, "file type (file, directory, link, etc.)")
1039 type = property(gettype, None, None, "file type (file, directory, link, etc.)")
1040
1040
1041 def getmodestr(self):
1041 def getmodestr(self):
1042 m = self.mode
1042 m = self.mode
1043 data = [
1043 data = [
1044 (stat.S_IRUSR, "-r"),
1044 (stat.S_IRUSR, "-r"),
1045 (stat.S_IWUSR, "-w"),
1045 (stat.S_IWUSR, "-w"),
1046 (stat.S_IXUSR, "-x"),
1046 (stat.S_IXUSR, "-x"),
1047 (stat.S_IRGRP, "-r"),
1047 (stat.S_IRGRP, "-r"),
1048 (stat.S_IWGRP, "-w"),
1048 (stat.S_IWGRP, "-w"),
1049 (stat.S_IXGRP, "-x"),
1049 (stat.S_IXGRP, "-x"),
1050 (stat.S_IROTH, "-r"),
1050 (stat.S_IROTH, "-r"),
1051 (stat.S_IWOTH, "-w"),
1051 (stat.S_IWOTH, "-w"),
1052 (stat.S_IXOTH, "-x"),
1052 (stat.S_IXOTH, "-x"),
1053 ]
1053 ]
1054 return "".join([text[bool(m&bit)] for (bit, text) in data])
1054 return "".join([text[bool(m&bit)] for (bit, text) in data])
1055
1055
1056 modestr = property(getmodestr, None, None, "Access mode as string")
1056 modestr = property(getmodestr, None, None, "Access mode as string")
1057
1057
1058 def getblocks(self):
1058 def getblocks(self):
1059 return self.stat().st_blocks
1059 return self.stat().st_blocks
1060 blocks = property(getblocks, None, None, "File size in blocks")
1060 blocks = property(getblocks, None, None, "File size in blocks")
1061
1061
1062 def getblksize(self):
1062 def getblksize(self):
1063 return self.stat().st_blksize
1063 return self.stat().st_blksize
1064 blksize = property(getblksize, None, None, "Filesystem block size")
1064 blksize = property(getblksize, None, None, "Filesystem block size")
1065
1065
1066 def getdev(self):
1066 def getdev(self):
1067 return self.stat().st_dev
1067 return self.stat().st_dev
1068 dev = property(getdev)
1068 dev = property(getdev)
1069
1069
1070 def getnlink(self):
1070 def getnlink(self):
1071 return self.stat().st_nlink
1071 return self.stat().st_nlink
1072 nlink = property(getnlink, None, None, "Number of links")
1072 nlink = property(getnlink, None, None, "Number of links")
1073
1073
1074 def getuid(self):
1074 def getuid(self):
1075 return self.stat().st_uid
1075 return self.stat().st_uid
1076 uid = property(getuid, None, None, "User id of file owner")
1076 uid = property(getuid, None, None, "User id of file owner")
1077
1077
1078 def getgid(self):
1078 def getgid(self):
1079 return self.stat().st_gid
1079 return self.stat().st_gid
1080 gid = property(getgid, None, None, "Group id of file owner")
1080 gid = property(getgid, None, None, "Group id of file owner")
1081
1081
1082 def getowner(self):
1082 def getowner(self):
1083 stat = self.stat()
1083 stat = self.stat()
1084 try:
1084 try:
1085 return pwd.getpwuid(stat.st_uid).pw_name
1085 return pwd.getpwuid(stat.st_uid).pw_name
1086 except KeyError:
1086 except KeyError:
1087 return stat.st_uid
1087 return stat.st_uid
1088 owner = property(getowner, None, None, "Owner name (or id)")
1088 owner = property(getowner, None, None, "Owner name (or id)")
1089
1089
1090 def getgroup(self):
1090 def getgroup(self):
1091 stat = self.stat()
1091 stat = self.stat()
1092 try:
1092 try:
1093 return grp.getgrgid(stat.st_gid).gr_name
1093 return grp.getgrgid(stat.st_gid).gr_name
1094 except KeyError:
1094 except KeyError:
1095 return stat.st_gid
1095 return stat.st_gid
1096 group = property(getgroup, None, None, "Group name (or id)")
1096 group = property(getgroup, None, None, "Group name (or id)")
1097
1097
1098 def getadate(self):
1098 def getadate(self):
1099 return datetime.datetime.utcfromtimestamp(self.atime)
1099 return datetime.datetime.utcfromtimestamp(self.atime)
1100 adate = property(getadate, None, None, "Access date")
1100 adate = property(getadate, None, None, "Access date")
1101
1101
1102 def getcdate(self):
1102 def getcdate(self):
1103 return datetime.datetime.utcfromtimestamp(self.ctime)
1103 return datetime.datetime.utcfromtimestamp(self.ctime)
1104 cdate = property(getcdate, None, None, "Creation date")
1104 cdate = property(getcdate, None, None, "Creation date")
1105
1105
1106 def getmdate(self):
1106 def getmdate(self):
1107 return datetime.datetime.utcfromtimestamp(self.mtime)
1107 return datetime.datetime.utcfromtimestamp(self.mtime)
1108 mdate = property(getmdate, None, None, "Modification date")
1108 mdate = property(getmdate, None, None, "Modification date")
1109
1109
1110 def mimetype(self):
1110 def mimetype(self):
1111 """
1111 """
1112 Return MIME type guessed from the extension.
1112 Return MIME type guessed from the extension.
1113 """
1113 """
1114 return mimetypes.guess_type(self.basename())[0]
1114 return mimetypes.guess_type(self.basename())[0]
1115
1115
1116 def encoding(self):
1116 def encoding(self):
1117 """
1117 """
1118 Return guessed compression (like "compress" or "gzip").
1118 Return guessed compression (like "compress" or "gzip").
1119 """
1119 """
1120 return mimetypes.guess_type(self.basename())[1]
1120 return mimetypes.guess_type(self.basename())[1]
1121
1121
1122 def __repr__(self):
1122 def __repr__(self):
1123 return "ifile(%s)" % path._base.__repr__(self)
1123 return "ifile(%s)" % path._base.__repr__(self)
1124
1124
1125 if sys.platform == "win32":
1125 if sys.platform == "win32":
1126 defaultattrs = (None, "type", "size", "modestr", "mdate")
1126 defaultattrs = (None, "type", "size", "modestr", "mdate")
1127 else:
1127 else:
1128 defaultattrs = (None, "type", "size", "modestr", "owner", "group", "mdate")
1128 defaultattrs = (None, "type", "size", "modestr", "owner", "group", "mdate")
1129
1129
1130 def __xattrs__(self, mode="default"):
1130 def __xattrs__(self, mode="default"):
1131 if mode == "detail":
1131 if mode == "detail":
1132 return (
1132 return (
1133 "name",
1133 "name",
1134 "basename()",
1134 "basename()",
1135 "abspath()",
1135 "abspath()",
1136 "realpath()",
1136 "realpath()",
1137 "type",
1137 "type",
1138 "mode",
1138 "mode",
1139 "modestr",
1139 "modestr",
1140 "stat()",
1140 "stat()",
1141 "lstat()",
1141 "lstat()",
1142 "uid",
1142 "uid",
1143 "gid",
1143 "gid",
1144 "owner",
1144 "owner",
1145 "group",
1145 "group",
1146 "dev",
1146 "dev",
1147 "nlink",
1147 "nlink",
1148 "ctime",
1148 "ctime",
1149 "mtime",
1149 "mtime",
1150 "atime",
1150 "atime",
1151 "cdate",
1151 "cdate",
1152 "mdate",
1152 "mdate",
1153 "adate",
1153 "adate",
1154 "size",
1154 "size",
1155 "blocks",
1155 "blocks",
1156 "blksize",
1156 "blksize",
1157 "isdir()",
1157 "isdir()",
1158 "islink()",
1158 "islink()",
1159 "mimetype()",
1159 "mimetype()",
1160 "encoding()",
1160 "encoding()",
1161 "-listdir()",
1161 "-listdir()",
1162 "-dirs()",
1162 "-dirs()",
1163 "-files()",
1163 "-files()",
1164 "-walk()",
1164 "-walk()",
1165 "-walkdirs()",
1165 "-walkdirs()",
1166 "-walkfiles()",
1166 "-walkfiles()",
1167 )
1167 )
1168 else:
1168 else:
1169 return self.defaultattrs
1169 return self.defaultattrs
1170
1170
1171
1171
1172 def xiter_ifile(self):
1172 def xiter_ifile(self):
1173 if self.isdir():
1173 if self.isdir():
1174 yield (self / os.pardir).abspath()
1174 yield (self / os.pardir).abspath()
1175 for child in sorted(self.listdir()):
1175 for child in sorted(self.listdir()):
1176 yield child
1176 yield child
1177 else:
1177 else:
1178 f = self.open("rb")
1178 f = self.open("rb")
1179 for line in f:
1179 for line in f:
1180 yield line
1180 yield line
1181 f.close()
1181 f.close()
1182 xiter.when_type(ifile)(xiter_ifile)
1182 xiter.when_type(ifile)(xiter_ifile)
1183
1183
1184
1184
1185 # We need to implement ``xrepr`` for ``ifile`` as a generic function, because
1185 # We need to implement ``xrepr`` for ``ifile`` as a generic function, because
1186 # otherwise ``xrepr_str`` would kick in.
1186 # otherwise ``xrepr_str`` would kick in.
1187 def xrepr_ifile(self, mode="default"):
1187 def xrepr_ifile(self, mode="default"):
1188 try:
1188 try:
1189 if self.isdir():
1189 if self.isdir():
1190 name = "idir"
1190 name = "idir"
1191 style = astyle.style_dir
1191 style = astyle.style_dir
1192 else:
1192 else:
1193 name = "ifile"
1193 name = "ifile"
1194 style = astyle.style_file
1194 style = astyle.style_file
1195 except IOError:
1195 except IOError:
1196 name = "ifile"
1196 name = "ifile"
1197 style = astyle.style_default
1197 style = astyle.style_default
1198 if mode in ("cell", "header", "footer"):
1198 if mode in ("cell", "header", "footer"):
1199 abspath = repr(path._base(self.normpath()))
1199 abspath = repr(path._base(self.normpath()))
1200 if abspath.startswith("u"):
1200 if abspath.startswith("u"):
1201 abspath = abspath[2:-1]
1201 abspath = abspath[2:-1]
1202 else:
1202 else:
1203 abspath = abspath[1:-1]
1203 abspath = abspath[1:-1]
1204 if mode == "cell":
1204 if mode == "cell":
1205 yield (style, abspath)
1205 yield (style, abspath)
1206 else:
1206 else:
1207 yield (style, "%s(%s)" % (name, abspath))
1207 yield (style, "%s(%s)" % (name, abspath))
1208 else:
1208 else:
1209 yield (style, repr(self))
1209 yield (style, repr(self))
1210 xrepr.when_type(ifile)(xrepr_ifile)
1210 xrepr.when_type(ifile)(xrepr_ifile)
1211
1211
1212
1212
1213 class ils(Table):
1213 class ils(Table):
1214 """
1214 """
1215 List the current (or a specified) directory.
1215 List the current (or a specified) directory.
1216
1216
1217 Examples::
1217 Examples::
1218
1218
1219 >>> ils
1219 >>> ils
1220 <class 'IPython.extensions.ipipe.ils'>
1220 <class 'IPython.extensions.ipipe.ils'>
1221 >>> ils("/usr/local/lib/python2.4")
1221 >>> ils("/usr/local/lib/python2.4")
1222 IPython.extensions.ipipe.ils('/usr/local/lib/python2.4')
1222 IPython.extensions.ipipe.ils('/usr/local/lib/python2.4')
1223 >>> ils("~")
1223 >>> ils("~")
1224 IPython.extensions.ipipe.ils('/home/fperez')
1224 IPython.extensions.ipipe.ils('/home/fperez')
1225 # all-random
1225 # all-random
1226 """
1226 """
1227 def __init__(self, base=os.curdir, dirs=True, files=True):
1227 def __init__(self, base=os.curdir, dirs=True, files=True):
1228 self.base = os.path.expanduser(base)
1228 self.base = os.path.expanduser(base)
1229 self.dirs = dirs
1229 self.dirs = dirs
1230 self.files = files
1230 self.files = files
1231
1231
1232 def __iter__(self):
1232 def __iter__(self):
1233 base = ifile(self.base)
1233 base = ifile(self.base)
1234 yield (base / os.pardir).abspath()
1234 yield (base / os.pardir).abspath()
1235 for child in sorted(base.listdir()):
1235 for child in sorted(base.listdir()):
1236 if self.dirs:
1236 if self.dirs:
1237 if self.files:
1237 if self.files:
1238 yield child
1238 yield child
1239 else:
1239 else:
1240 if child.isdir():
1240 if child.isdir():
1241 yield child
1241 yield child
1242 elif self.files:
1242 elif self.files:
1243 if not child.isdir():
1243 if not child.isdir():
1244 yield child
1244 yield child
1245
1245
1246 def __xrepr__(self, mode="default"):
1246 def __xrepr__(self, mode="default"):
1247 return xrepr(ifile(self.base), mode)
1247 return xrepr(ifile(self.base), mode)
1248
1248
1249 def __repr__(self):
1249 def __repr__(self):
1250 return "%s.%s(%r)" % \
1250 return "%s.%s(%r)" % \
1251 (self.__class__.__module__, self.__class__.__name__, self.base)
1251 (self.__class__.__module__, self.__class__.__name__, self.base)
1252
1252
1253
1253
1254 class iglob(Table):
1254 class iglob(Table):
1255 """
1255 """
1256 List all files and directories matching a specified pattern.
1256 List all files and directories matching a specified pattern.
1257 (See ``glob.glob()`` for more info.).
1257 (See ``glob.glob()`` for more info.).
1258
1258
1259 Examples::
1259 Examples::
1260
1260
1261 >>> iglob("*.py")
1261 >>> iglob("*.py")
1262 IPython.extensions.ipipe.iglob('*.py')
1262 IPython.extensions.ipipe.iglob('*.py')
1263 """
1263 """
1264 def __init__(self, glob):
1264 def __init__(self, glob):
1265 self.glob = glob
1265 self.glob = glob
1266
1266
1267 def __iter__(self):
1267 def __iter__(self):
1268 for name in glob.glob(self.glob):
1268 for name in glob.glob(self.glob):
1269 yield ifile(name)
1269 yield ifile(name)
1270
1270
1271 def __xrepr__(self, mode="default"):
1271 def __xrepr__(self, mode="default"):
1272 if mode == "header" or mode == "footer" or mode == "cell":
1272 if mode == "header" or mode == "footer" or mode == "cell":
1273 yield (astyle.style_default,
1273 yield (astyle.style_default,
1274 "%s(%r)" % (self.__class__.__name__, self.glob))
1274 "%s(%r)" % (self.__class__.__name__, self.glob))
1275 else:
1275 else:
1276 yield (astyle.style_default, repr(self))
1276 yield (astyle.style_default, repr(self))
1277
1277
1278 def __repr__(self):
1278 def __repr__(self):
1279 return "%s.%s(%r)" % \
1279 return "%s.%s(%r)" % \
1280 (self.__class__.__module__, self.__class__.__name__, self.glob)
1280 (self.__class__.__module__, self.__class__.__name__, self.glob)
1281
1281
1282
1282
1283 class iwalk(Table):
1283 class iwalk(Table):
1284 """
1284 """
1285 List all files and directories in a directory and it's subdirectory::
1285 List all files and directories in a directory and it's subdirectory::
1286
1286
1287 >>> iwalk
1287 >>> iwalk
1288 <class 'IPython.extensions.ipipe.iwalk'>
1288 <class 'IPython.extensions.ipipe.iwalk'>
1289 >>> iwalk("/usr/lib")
1289 >>> iwalk("/usr/lib")
1290 IPython.extensions.ipipe.iwalk('/usr/lib')
1290 IPython.extensions.ipipe.iwalk('/usr/lib')
1291 >>> iwalk("~")
1291 >>> iwalk("~")
1292 IPython.extensions.ipipe.iwalk('/home/fperez') # random
1292 IPython.extensions.ipipe.iwalk('/home/fperez') # random
1293
1293
1294 """
1294 """
1295 def __init__(self, base=os.curdir, dirs=True, files=True):
1295 def __init__(self, base=os.curdir, dirs=True, files=True):
1296 self.base = os.path.expanduser(base)
1296 self.base = os.path.expanduser(base)
1297 self.dirs = dirs
1297 self.dirs = dirs
1298 self.files = files
1298 self.files = files
1299
1299
1300 def __iter__(self):
1300 def __iter__(self):
1301 for (dirpath, dirnames, filenames) in os.walk(self.base):
1301 for (dirpath, dirnames, filenames) in os.walk(self.base):
1302 if self.dirs:
1302 if self.dirs:
1303 for name in sorted(dirnames):
1303 for name in sorted(dirnames):
1304 yield ifile(os.path.join(dirpath, name))
1304 yield ifile(os.path.join(dirpath, name))
1305 if self.files:
1305 if self.files:
1306 for name in sorted(filenames):
1306 for name in sorted(filenames):
1307 yield ifile(os.path.join(dirpath, name))
1307 yield ifile(os.path.join(dirpath, name))
1308
1308
1309 def __xrepr__(self, mode="default"):
1309 def __xrepr__(self, mode="default"):
1310 if mode == "header" or mode == "footer" or mode == "cell":
1310 if mode == "header" or mode == "footer" or mode == "cell":
1311 yield (astyle.style_default,
1311 yield (astyle.style_default,
1312 "%s(%r)" % (self.__class__.__name__, self.base))
1312 "%s(%r)" % (self.__class__.__name__, self.base))
1313 else:
1313 else:
1314 yield (astyle.style_default, repr(self))
1314 yield (astyle.style_default, repr(self))
1315
1315
1316 def __repr__(self):
1316 def __repr__(self):
1317 return "%s.%s(%r)" % \
1317 return "%s.%s(%r)" % \
1318 (self.__class__.__module__, self.__class__.__name__, self.base)
1318 (self.__class__.__module__, self.__class__.__name__, self.base)
1319
1319
1320
1320
1321 class ipwdentry(object):
1321 class ipwdentry(object):
1322 """
1322 """
1323 ``ipwdentry`` objects encapsulate entries in the Unix user account and
1323 ``ipwdentry`` objects encapsulate entries in the Unix user account and
1324 password database.
1324 password database.
1325 """
1325 """
1326 def __init__(self, id):
1326 def __init__(self, id):
1327 self._id = id
1327 self._id = id
1328 self._entry = None
1328 self._entry = None
1329
1329
1330 def __eq__(self, other):
1330 def __eq__(self, other):
1331 return self.__class__ is other.__class__ and self._id == other._id
1331 return self.__class__ is other.__class__ and self._id == other._id
1332
1332
1333 def __ne__(self, other):
1333 def __ne__(self, other):
1334 return self.__class__ is not other.__class__ or self._id != other._id
1334 return self.__class__ is not other.__class__ or self._id != other._id
1335
1335
1336 def _getentry(self):
1336 def _getentry(self):
1337 if self._entry is None:
1337 if self._entry is None:
1338 if isinstance(self._id, basestring):
1338 if isinstance(self._id, basestring):
1339 self._entry = pwd.getpwnam(self._id)
1339 self._entry = pwd.getpwnam(self._id)
1340 else:
1340 else:
1341 self._entry = pwd.getpwuid(self._id)
1341 self._entry = pwd.getpwuid(self._id)
1342 return self._entry
1342 return self._entry
1343
1343
1344 def getname(self):
1344 def getname(self):
1345 if isinstance(self._id, basestring):
1345 if isinstance(self._id, basestring):
1346 return self._id
1346 return self._id
1347 else:
1347 else:
1348 return self._getentry().pw_name
1348 return self._getentry().pw_name
1349 name = property(getname, None, None, "User name")
1349 name = property(getname, None, None, "User name")
1350
1350
1351 def getpasswd(self):
1351 def getpasswd(self):
1352 return self._getentry().pw_passwd
1352 return self._getentry().pw_passwd
1353 passwd = property(getpasswd, None, None, "Password")
1353 passwd = property(getpasswd, None, None, "Password")
1354
1354
1355 def getuid(self):
1355 def getuid(self):
1356 if isinstance(self._id, basestring):
1356 if isinstance(self._id, basestring):
1357 return self._getentry().pw_uid
1357 return self._getentry().pw_uid
1358 else:
1358 else:
1359 return self._id
1359 return self._id
1360 uid = property(getuid, None, None, "User id")
1360 uid = property(getuid, None, None, "User id")
1361
1361
1362 def getgid(self):
1362 def getgid(self):
1363 return self._getentry().pw_gid
1363 return self._getentry().pw_gid
1364 gid = property(getgid, None, None, "Primary group id")
1364 gid = property(getgid, None, None, "Primary group id")
1365
1365
1366 def getgroup(self):
1366 def getgroup(self):
1367 return igrpentry(self.gid)
1367 return igrpentry(self.gid)
1368 group = property(getgroup, None, None, "Group")
1368 group = property(getgroup, None, None, "Group")
1369
1369
1370 def getgecos(self):
1370 def getgecos(self):
1371 return self._getentry().pw_gecos
1371 return self._getentry().pw_gecos
1372 gecos = property(getgecos, None, None, "Information (e.g. full user name)")
1372 gecos = property(getgecos, None, None, "Information (e.g. full user name)")
1373
1373
1374 def getdir(self):
1374 def getdir(self):
1375 return self._getentry().pw_dir
1375 return self._getentry().pw_dir
1376 dir = property(getdir, None, None, "$HOME directory")
1376 dir = property(getdir, None, None, "$HOME directory")
1377
1377
1378 def getshell(self):
1378 def getshell(self):
1379 return self._getentry().pw_shell
1379 return self._getentry().pw_shell
1380 shell = property(getshell, None, None, "Login shell")
1380 shell = property(getshell, None, None, "Login shell")
1381
1381
1382 def __xattrs__(self, mode="default"):
1382 def __xattrs__(self, mode="default"):
1383 return ("name", "passwd", "uid", "gid", "gecos", "dir", "shell")
1383 return ("name", "passwd", "uid", "gid", "gecos", "dir", "shell")
1384
1384
1385 def __repr__(self):
1385 def __repr__(self):
1386 return "%s.%s(%r)" % \
1386 return "%s.%s(%r)" % \
1387 (self.__class__.__module__, self.__class__.__name__, self._id)
1387 (self.__class__.__module__, self.__class__.__name__, self._id)
1388
1388
1389
1389
1390 class ipwd(Table):
1390 class ipwd(Table):
1391 """
1391 """
1392 List all entries in the Unix user account and password database.
1392 List all entries in the Unix user account and password database.
1393
1393
1394 Example::
1394 Example::
1395
1395
1396 >>> ipwd | isort("uid")
1396 >>> ipwd | isort("uid")
1397 <IPython.extensions.ipipe.isort key='uid' reverse=False at 0x849efec>
1397 <IPython.extensions.ipipe.isort key='uid' reverse=False at 0x849efec>
1398 # random
1398 # random
1399 """
1399 """
1400 def __iter__(self):
1400 def __iter__(self):
1401 for entry in pwd.getpwall():
1401 for entry in pwd.getpwall():
1402 yield ipwdentry(entry.pw_name)
1402 yield ipwdentry(entry.pw_name)
1403
1403
1404 def __xrepr__(self, mode="default"):
1404 def __xrepr__(self, mode="default"):
1405 if mode == "header" or mode == "footer" or mode == "cell":
1405 if mode == "header" or mode == "footer" or mode == "cell":
1406 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1406 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1407 else:
1407 else:
1408 yield (astyle.style_default, repr(self))
1408 yield (astyle.style_default, repr(self))
1409
1409
1410
1410
1411 class igrpentry(object):
1411 class igrpentry(object):
1412 """
1412 """
1413 ``igrpentry`` objects encapsulate entries in the Unix group database.
1413 ``igrpentry`` objects encapsulate entries in the Unix group database.
1414 """
1414 """
1415 def __init__(self, id):
1415 def __init__(self, id):
1416 self._id = id
1416 self._id = id
1417 self._entry = None
1417 self._entry = None
1418
1418
1419 def __eq__(self, other):
1419 def __eq__(self, other):
1420 return self.__class__ is other.__class__ and self._id == other._id
1420 return self.__class__ is other.__class__ and self._id == other._id
1421
1421
1422 def __ne__(self, other):
1422 def __ne__(self, other):
1423 return self.__class__ is not other.__class__ or self._id != other._id
1423 return self.__class__ is not other.__class__ or self._id != other._id
1424
1424
1425 def _getentry(self):
1425 def _getentry(self):
1426 if self._entry is None:
1426 if self._entry is None:
1427 if isinstance(self._id, basestring):
1427 if isinstance(self._id, basestring):
1428 self._entry = grp.getgrnam(self._id)
1428 self._entry = grp.getgrnam(self._id)
1429 else:
1429 else:
1430 self._entry = grp.getgrgid(self._id)
1430 self._entry = grp.getgrgid(self._id)
1431 return self._entry
1431 return self._entry
1432
1432
1433 def getname(self):
1433 def getname(self):
1434 if isinstance(self._id, basestring):
1434 if isinstance(self._id, basestring):
1435 return self._id
1435 return self._id
1436 else:
1436 else:
1437 return self._getentry().gr_name
1437 return self._getentry().gr_name
1438 name = property(getname, None, None, "Group name")
1438 name = property(getname, None, None, "Group name")
1439
1439
1440 def getpasswd(self):
1440 def getpasswd(self):
1441 return self._getentry().gr_passwd
1441 return self._getentry().gr_passwd
1442 passwd = property(getpasswd, None, None, "Password")
1442 passwd = property(getpasswd, None, None, "Password")
1443
1443
1444 def getgid(self):
1444 def getgid(self):
1445 if isinstance(self._id, basestring):
1445 if isinstance(self._id, basestring):
1446 return self._getentry().gr_gid
1446 return self._getentry().gr_gid
1447 else:
1447 else:
1448 return self._id
1448 return self._id
1449 gid = property(getgid, None, None, "Group id")
1449 gid = property(getgid, None, None, "Group id")
1450
1450
1451 def getmem(self):
1451 def getmem(self):
1452 return self._getentry().gr_mem
1452 return self._getentry().gr_mem
1453 mem = property(getmem, None, None, "Members")
1453 mem = property(getmem, None, None, "Members")
1454
1454
1455 def __xattrs__(self, mode="default"):
1455 def __xattrs__(self, mode="default"):
1456 return ("name", "passwd", "gid", "mem")
1456 return ("name", "passwd", "gid", "mem")
1457
1457
1458 def __xrepr__(self, mode="default"):
1458 def __xrepr__(self, mode="default"):
1459 if mode == "header" or mode == "footer" or mode == "cell":
1459 if mode == "header" or mode == "footer" or mode == "cell":
1460 yield (astyle.style_default, "group ")
1460 yield (astyle.style_default, "group ")
1461 try:
1461 try:
1462 yield (astyle.style_default, self.name)
1462 yield (astyle.style_default, self.name)
1463 except KeyError:
1463 except KeyError:
1464 if isinstance(self._id, basestring):
1464 if isinstance(self._id, basestring):
1465 yield (astyle.style_default, self.name_id)
1465 yield (astyle.style_default, self.name_id)
1466 else:
1466 else:
1467 yield (astyle.style_type_number, str(self._id))
1467 yield (astyle.style_type_number, str(self._id))
1468 else:
1468 else:
1469 yield (astyle.style_default, repr(self))
1469 yield (astyle.style_default, repr(self))
1470
1470
1471 def __iter__(self):
1471 def __iter__(self):
1472 for member in self.mem:
1472 for member in self.mem:
1473 yield ipwdentry(member)
1473 yield ipwdentry(member)
1474
1474
1475 def __repr__(self):
1475 def __repr__(self):
1476 return "%s.%s(%r)" % \
1476 return "%s.%s(%r)" % \
1477 (self.__class__.__module__, self.__class__.__name__, self._id)
1477 (self.__class__.__module__, self.__class__.__name__, self._id)
1478
1478
1479
1479
1480 class igrp(Table):
1480 class igrp(Table):
1481 """
1481 """
1482 This ``Table`` lists all entries in the Unix group database.
1482 This ``Table`` lists all entries in the Unix group database.
1483 """
1483 """
1484 def __iter__(self):
1484 def __iter__(self):
1485 for entry in grp.getgrall():
1485 for entry in grp.getgrall():
1486 yield igrpentry(entry.gr_name)
1486 yield igrpentry(entry.gr_name)
1487
1487
1488 def __xrepr__(self, mode="default"):
1488 def __xrepr__(self, mode="default"):
1489 if mode == "header" or mode == "footer":
1489 if mode == "header" or mode == "footer":
1490 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1490 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1491 else:
1491 else:
1492 yield (astyle.style_default, repr(self))
1492 yield (astyle.style_default, repr(self))
1493
1493
1494
1494
1495 class Fields(object):
1495 class Fields(object):
1496 def __init__(self, fieldnames, **fields):
1496 def __init__(self, fieldnames, **fields):
1497 self.__fieldnames = [upgradexattr(fieldname) for fieldname in fieldnames]
1497 self.__fieldnames = [upgradexattr(fieldname) for fieldname in fieldnames]
1498 for (key, value) in fields.iteritems():
1498 for (key, value) in fields.iteritems():
1499 setattr(self, key, value)
1499 setattr(self, key, value)
1500
1500
1501 def __xattrs__(self, mode="default"):
1501 def __xattrs__(self, mode="default"):
1502 return self.__fieldnames
1502 return self.__fieldnames
1503
1503
1504 def __xrepr__(self, mode="default"):
1504 def __xrepr__(self, mode="default"):
1505 yield (-1, False)
1505 yield (-1, False)
1506 if mode == "header" or mode == "cell":
1506 if mode == "header" or mode == "cell":
1507 yield (astyle.style_default, self.__class__.__name__)
1507 yield (astyle.style_default, self.__class__.__name__)
1508 yield (astyle.style_default, "(")
1508 yield (astyle.style_default, "(")
1509 for (i, f) in enumerate(self.__fieldnames):
1509 for (i, f) in enumerate(self.__fieldnames):
1510 if i:
1510 if i:
1511 yield (astyle.style_default, ", ")
1511 yield (astyle.style_default, ", ")
1512 yield (astyle.style_default, f.name())
1512 yield (astyle.style_default, f.name())
1513 yield (astyle.style_default, "=")
1513 yield (astyle.style_default, "=")
1514 for part in xrepr(getattr(self, f), "default"):
1514 for part in xrepr(getattr(self, f), "default"):
1515 yield part
1515 yield part
1516 yield (astyle.style_default, ")")
1516 yield (astyle.style_default, ")")
1517 elif mode == "footer":
1517 elif mode == "footer":
1518 yield (astyle.style_default, self.__class__.__name__)
1518 yield (astyle.style_default, self.__class__.__name__)
1519 yield (astyle.style_default, "(")
1519 yield (astyle.style_default, "(")
1520 for (i, f) in enumerate(self.__fieldnames):
1520 for (i, f) in enumerate(self.__fieldnames):
1521 if i:
1521 if i:
1522 yield (astyle.style_default, ", ")
1522 yield (astyle.style_default, ", ")
1523 yield (astyle.style_default, f.name())
1523 yield (astyle.style_default, f.name())
1524 yield (astyle.style_default, ")")
1524 yield (astyle.style_default, ")")
1525 else:
1525 else:
1526 yield (astyle.style_default, repr(self))
1526 yield (astyle.style_default, repr(self))
1527
1527
1528
1528
1529 class FieldTable(Table, list):
1529 class FieldTable(Table, list):
1530 def __init__(self, *fields):
1530 def __init__(self, *fields):
1531 Table.__init__(self)
1531 Table.__init__(self)
1532 list.__init__(self)
1532 list.__init__(self)
1533 self.fields = fields
1533 self.fields = fields
1534
1534
1535 def add(self, **fields):
1535 def add(self, **fields):
1536 self.append(Fields(self.fields, **fields))
1536 self.append(Fields(self.fields, **fields))
1537
1537
1538 def __xrepr__(self, mode="default"):
1538 def __xrepr__(self, mode="default"):
1539 yield (-1, False)
1539 yield (-1, False)
1540 if mode == "header" or mode == "footer":
1540 if mode == "header" or mode == "footer":
1541 yield (astyle.style_default, self.__class__.__name__)
1541 yield (astyle.style_default, self.__class__.__name__)
1542 yield (astyle.style_default, "(")
1542 yield (astyle.style_default, "(")
1543 for (i, f) in enumerate(self.__fieldnames):
1543 for (i, f) in enumerate(self.__fieldnames):
1544 if i:
1544 if i:
1545 yield (astyle.style_default, ", ")
1545 yield (astyle.style_default, ", ")
1546 yield (astyle.style_default, f)
1546 yield (astyle.style_default, f)
1547 yield (astyle.style_default, ")")
1547 yield (astyle.style_default, ")")
1548 else:
1548 else:
1549 yield (astyle.style_default, repr(self))
1549 yield (astyle.style_default, repr(self))
1550
1550
1551 def __repr__(self):
1551 def __repr__(self):
1552 return "<%s.%s object with fields=%r at 0x%x>" % \
1552 return "<%s.%s object with fields=%r at 0x%x>" % \
1553 (self.__class__.__module__, self.__class__.__name__,
1553 (self.__class__.__module__, self.__class__.__name__,
1554 ", ".join(map(repr, self.fields)), id(self))
1554 ", ".join(map(repr, self.fields)), id(self))
1555
1555
1556
1556
1557 class List(list):
1557 class List(list):
1558 def __xattrs__(self, mode="default"):
1558 def __xattrs__(self, mode="default"):
1559 return xrange(len(self))
1559 return xrange(len(self))
1560
1560
1561 def __xrepr__(self, mode="default"):
1561 def __xrepr__(self, mode="default"):
1562 yield (-1, False)
1562 yield (-1, False)
1563 if mode == "header" or mode == "cell" or mode == "footer" or mode == "default":
1563 if mode == "header" or mode == "cell" or mode == "footer" or mode == "default":
1564 yield (astyle.style_default, self.__class__.__name__)
1564 yield (astyle.style_default, self.__class__.__name__)
1565 yield (astyle.style_default, "(")
1565 yield (astyle.style_default, "(")
1566 for (i, item) in enumerate(self):
1566 for (i, item) in enumerate(self):
1567 if i:
1567 if i:
1568 yield (astyle.style_default, ", ")
1568 yield (astyle.style_default, ", ")
1569 for part in xrepr(item, "default"):
1569 for part in xrepr(item, "default"):
1570 yield part
1570 yield part
1571 yield (astyle.style_default, ")")
1571 yield (astyle.style_default, ")")
1572 else:
1572 else:
1573 yield (astyle.style_default, repr(self))
1573 yield (astyle.style_default, repr(self))
1574
1574
1575
1575
1576 class ienv(Table):
1576 class ienv(Table):
1577 """
1577 """
1578 List environment variables.
1578 List environment variables.
1579
1579
1580 Example::
1580 Example::
1581
1581
1582 >>> ienv
1582 >>> ienv
1583 <class 'IPython.extensions.ipipe.ienv'>
1583 <class 'IPython.extensions.ipipe.ienv'>
1584 """
1584 """
1585
1585
1586 def __iter__(self):
1586 def __iter__(self):
1587 fields = ("key", "value")
1587 fields = ("key", "value")
1588 for (key, value) in os.environ.iteritems():
1588 for (key, value) in os.environ.iteritems():
1589 yield Fields(fields, key=key, value=value)
1589 yield Fields(fields, key=key, value=value)
1590
1590
1591 def __xrepr__(self, mode="default"):
1591 def __xrepr__(self, mode="default"):
1592 if mode == "header" or mode == "cell":
1592 if mode == "header" or mode == "cell":
1593 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1593 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1594 else:
1594 else:
1595 yield (astyle.style_default, repr(self))
1595 yield (astyle.style_default, repr(self))
1596
1596
1597
1597
1598 class ihist(Table):
1598 class ihist(Table):
1599 """
1599 """
1600 IPython input history
1600 IPython input history
1601
1601
1602 Example::
1602 Example::
1603
1603
1604 >>> ihist
1604 >>> ihist
1605 <class 'IPython.extensions.ipipe.ihist'>
1605 <class 'IPython.extensions.ipipe.ihist'>
1606 >>> ihist(True) # raw mode
1606 >>> ihist(True) # raw mode
1607 <IPython.extensions.ipipe.ihist object at 0x849602c> # random
1607 <IPython.extensions.ipipe.ihist object at 0x849602c> # random
1608 """
1608 """
1609 def __init__(self, raw=True):
1609 def __init__(self, raw=True):
1610 self.raw = raw
1610 self.raw = raw
1611
1611
1612 def __iter__(self):
1612 def __iter__(self):
1613 api = ipapi.get()
1613 api = ipapi.get()
1614 if self.raw:
1614 if self.raw:
1615 for line in api.input_hist_raw:
1615 for line in api.input_hist_raw:
1616 yield line.rstrip("\n")
1616 yield line.rstrip("\n")
1617 else:
1617 else:
1618 for line in api.input_hist:
1618 for line in api.input_hist:
1619 yield line.rstrip("\n")
1619 yield line.rstrip("\n")
1620
1620
1621
1621
1622 class Alias(object):
1622 class Alias(object):
1623 """
1623 """
1624 Entry in the alias table
1624 Entry in the alias table
1625 """
1625 """
1626 def __init__(self, name, args, command):
1626 def __init__(self, name, args, command):
1627 self.name = name
1627 self.name = name
1628 self.args = args
1628 self.args = args
1629 self.command = command
1629 self.command = command
1630
1630
1631 def __xattrs__(self, mode="default"):
1631 def __xattrs__(self, mode="default"):
1632 return ("name", "args", "command")
1632 return ("name", "args", "command")
1633
1633
1634
1634
1635 class ialias(Table):
1635 class ialias(Table):
1636 """
1636 """
1637 IPython alias list
1637 IPython alias list
1638
1638
1639 Example::
1639 Example::
1640
1640
1641 >>> ialias
1641 >>> ialias
1642 <class 'IPython.extensions.ipipe.ialias'>
1642 <class 'IPython.extensions.ipipe.ialias'>
1643 """
1643 """
1644 def __iter__(self):
1644 def __iter__(self):
1645 api = ipapi.get()
1645 api = ipapi.get()
1646
1646
1647 for (name, (args, command)) in api.alias_manager.alias_table.iteritems():
1647 for (name, (args, command)) in api.alias_manager.alias_table.iteritems():
1648 yield Alias(name, args, command)
1648 yield Alias(name, args, command)
1649
1649
1650
1650
1651 class icsv(Pipe):
1651 class icsv(Pipe):
1652 """
1652 """
1653 This ``Pipe`` turns the input (with must be a pipe outputting lines
1653 This ``Pipe`` turns the input (with must be a pipe outputting lines
1654 or an ``ifile``) into lines of CVS columns.
1654 or an ``ifile``) into lines of CVS columns.
1655 """
1655 """
1656 def __init__(self, **csvargs):
1656 def __init__(self, **csvargs):
1657 """
1657 """
1658 Create an ``icsv`` object. ``cvsargs`` will be passed through as
1658 Create an ``icsv`` object. ``cvsargs`` will be passed through as
1659 keyword arguments to ``cvs.reader()``.
1659 keyword arguments to ``cvs.reader()``.
1660 """
1660 """
1661 self.csvargs = csvargs
1661 self.csvargs = csvargs
1662
1662
1663 def __iter__(self):
1663 def __iter__(self):
1664 input = self.input
1664 input = self.input
1665 if isinstance(input, ifile):
1665 if isinstance(input, ifile):
1666 input = input.open("rb")
1666 input = input.open("rb")
1667 reader = csv.reader(input, **self.csvargs)
1667 reader = csv.reader(input, **self.csvargs)
1668 for line in reader:
1668 for line in reader:
1669 yield List(line)
1669 yield List(line)
1670
1670
1671 def __xrepr__(self, mode="default"):
1671 def __xrepr__(self, mode="default"):
1672 yield (-1, False)
1672 yield (-1, False)
1673 if mode == "header" or mode == "footer":
1673 if mode == "header" or mode == "footer":
1674 input = getattr(self, "input", None)
1674 input = getattr(self, "input", None)
1675 if input is not None:
1675 if input is not None:
1676 for part in xrepr(input, mode):
1676 for part in xrepr(input, mode):
1677 yield part
1677 yield part
1678 yield (astyle.style_default, " | ")
1678 yield (astyle.style_default, " | ")
1679 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1679 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1680 for (i, (name, value)) in enumerate(self.csvargs.iteritems()):
1680 for (i, (name, value)) in enumerate(self.csvargs.iteritems()):
1681 if i:
1681 if i:
1682 yield (astyle.style_default, ", ")
1682 yield (astyle.style_default, ", ")
1683 yield (astyle.style_default, name)
1683 yield (astyle.style_default, name)
1684 yield (astyle.style_default, "=")
1684 yield (astyle.style_default, "=")
1685 for part in xrepr(value, "default"):
1685 for part in xrepr(value, "default"):
1686 yield part
1686 yield part
1687 yield (astyle.style_default, ")")
1687 yield (astyle.style_default, ")")
1688 else:
1688 else:
1689 yield (astyle.style_default, repr(self))
1689 yield (astyle.style_default, repr(self))
1690
1690
1691 def __repr__(self):
1691 def __repr__(self):
1692 args = ", ".join(["%s=%r" % item for item in self.csvargs.iteritems()])
1692 args = ", ".join(["%s=%r" % item for item in self.csvargs.iteritems()])
1693 return "<%s.%s %s at 0x%x>" % \
1693 return "<%s.%s %s at 0x%x>" % \
1694 (self.__class__.__module__, self.__class__.__name__, args, id(self))
1694 (self.__class__.__module__, self.__class__.__name__, args, id(self))
1695
1695
1696
1696
1697 class ix(Table):
1697 class ix(Table):
1698 """
1698 """
1699 Execute a system command and list its output as lines
1699 Execute a system command and list its output as lines
1700 (similar to ``os.popen()``).
1700 (similar to ``os.popen()``).
1701
1701
1702 Examples::
1702 Examples::
1703
1703
1704 >>> ix("ps x")
1704 >>> ix("ps x")
1705 IPython.extensions.ipipe.ix('ps x')
1705 IPython.extensions.ipipe.ix('ps x')
1706
1706
1707 >>> ix("find .") | ifile
1707 >>> ix("find .") | ifile
1708 <IPython.extensions.ipipe.ieval expr=<class 'IPython.extensions.ipipe.ifile'> at 0x8509d2c>
1708 <IPython.extensions.ipipe.ieval expr=<class 'IPython.extensions.ipipe.ifile'> at 0x8509d2c>
1709 # random
1709 # random
1710 """
1710 """
1711 def __init__(self, cmd):
1711 def __init__(self, cmd):
1712 self.cmd = cmd
1712 self.cmd = cmd
1713 self._pipeout = None
1713 self._pipeout = None
1714
1714
1715 def __iter__(self):
1715 def __iter__(self):
1716 (_pipein, self._pipeout) = os.popen4(self.cmd)
1716 (_pipein, self._pipeout) = os.popen4(self.cmd)
1717 _pipein.close()
1717 _pipein.close()
1718 for l in self._pipeout:
1718 for l in self._pipeout:
1719 yield l.rstrip("\r\n")
1719 yield l.rstrip("\r\n")
1720 self._pipeout.close()
1720 self._pipeout.close()
1721 self._pipeout = None
1721 self._pipeout = None
1722
1722
1723 def __del__(self):
1723 def __del__(self):
1724 if self._pipeout is not None and not self._pipeout.closed:
1724 if self._pipeout is not None and not self._pipeout.closed:
1725 self._pipeout.close()
1725 self._pipeout.close()
1726 self._pipeout = None
1726 self._pipeout = None
1727
1727
1728 def __xrepr__(self, mode="default"):
1728 def __xrepr__(self, mode="default"):
1729 if mode == "header" or mode == "footer":
1729 if mode == "header" or mode == "footer":
1730 yield (astyle.style_default,
1730 yield (astyle.style_default,
1731 "%s(%r)" % (self.__class__.__name__, self.cmd))
1731 "%s(%r)" % (self.__class__.__name__, self.cmd))
1732 else:
1732 else:
1733 yield (astyle.style_default, repr(self))
1733 yield (astyle.style_default, repr(self))
1734
1734
1735 def __repr__(self):
1735 def __repr__(self):
1736 return "%s.%s(%r)" % \
1736 return "%s.%s(%r)" % \
1737 (self.__class__.__module__, self.__class__.__name__, self.cmd)
1737 (self.__class__.__module__, self.__class__.__name__, self.cmd)
1738
1738
1739
1739
1740 class ifilter(Pipe):
1740 class ifilter(Pipe):
1741 """
1741 """
1742 Filter an input pipe. Only objects where an expression evaluates to true
1742 Filter an input pipe. Only objects where an expression evaluates to true
1743 (and doesn't raise an exception) are listed.
1743 (and doesn't raise an exception) are listed.
1744
1744
1745 Examples::
1745 Examples::
1746
1746
1747 >>> ils | ifilter("_.isfile() and size>1000")
1747 >>> ils | ifilter("_.isfile() and size>1000")
1748 >>> igrp | ifilter("len(mem)")
1748 >>> igrp | ifilter("len(mem)")
1749 >>> sys.modules | ifilter(lambda _:_.value is not None)
1749 >>> sys.modules | ifilter(lambda _:_.value is not None)
1750 # all-random
1750 # all-random
1751 """
1751 """
1752
1752
1753 def __init__(self, expr, globals=None, errors="raiseifallfail"):
1753 def __init__(self, expr, globals=None, errors="raiseifallfail"):
1754 """
1754 """
1755 Create an ``ifilter`` object. ``expr`` can be a callable or a string
1755 Create an ``ifilter`` object. ``expr`` can be a callable or a string
1756 containing an expression. ``globals`` will be used as the global
1756 containing an expression. ``globals`` will be used as the global
1757 namespace for calling string expressions (defaulting to IPython's
1757 namespace for calling string expressions (defaulting to IPython's
1758 user namespace). ``errors`` specifies how exception during evaluation
1758 user namespace). ``errors`` specifies how exception during evaluation
1759 of ``expr`` are handled:
1759 of ``expr`` are handled:
1760
1760
1761 ``"drop"``
1761 ``"drop"``
1762 drop all items that have errors;
1762 drop all items that have errors;
1763
1763
1764 ``"keep"``
1764 ``"keep"``
1765 keep all items that have errors;
1765 keep all items that have errors;
1766
1766
1767 ``"keeperror"``
1767 ``"keeperror"``
1768 keep the exception of all items that have errors;
1768 keep the exception of all items that have errors;
1769
1769
1770 ``"raise"``
1770 ``"raise"``
1771 raise the exception;
1771 raise the exception;
1772
1772
1773 ``"raiseifallfail"``
1773 ``"raiseifallfail"``
1774 raise the first exception if all items have errors; otherwise drop
1774 raise the first exception if all items have errors; otherwise drop
1775 those with errors (this is the default).
1775 those with errors (this is the default).
1776 """
1776 """
1777 self.expr = expr
1777 self.expr = expr
1778 self.globals = globals
1778 self.globals = globals
1779 self.errors = errors
1779 self.errors = errors
1780
1780
1781 def __iter__(self):
1781 def __iter__(self):
1782 if callable(self.expr):
1782 if callable(self.expr):
1783 test = self.expr
1783 test = self.expr
1784 else:
1784 else:
1785 g = getglobals(self.globals)
1785 g = getglobals(self.globals)
1786 expr = compile(self.expr, "ipipe-expression", "eval")
1786 expr = compile(self.expr, "ipipe-expression", "eval")
1787 def test(item):
1787 def test(item):
1788 return eval(expr, g, AttrNamespace(item))
1788 return eval(expr, g, AttrNamespace(item))
1789
1789
1790 ok = 0
1790 ok = 0
1791 exc_info = None
1791 exc_info = None
1792 for item in xiter(self.input):
1792 for item in xiter(self.input):
1793 try:
1793 try:
1794 if test(item):
1794 if test(item):
1795 yield item
1795 yield item
1796 ok += 1
1796 ok += 1
1797 except (KeyboardInterrupt, SystemExit):
1797 except (KeyboardInterrupt, SystemExit):
1798 raise
1798 raise
1799 except Exception, exc:
1799 except Exception as exc:
1800 if self.errors == "drop":
1800 if self.errors == "drop":
1801 pass # Ignore errors
1801 pass # Ignore errors
1802 elif self.errors == "keep":
1802 elif self.errors == "keep":
1803 yield item
1803 yield item
1804 elif self.errors == "keeperror":
1804 elif self.errors == "keeperror":
1805 yield exc
1805 yield exc
1806 elif self.errors == "raise":
1806 elif self.errors == "raise":
1807 raise
1807 raise
1808 elif self.errors == "raiseifallfail":
1808 elif self.errors == "raiseifallfail":
1809 if exc_info is None:
1809 if exc_info is None:
1810 exc_info = sys.exc_info()
1810 exc_info = sys.exc_info()
1811 if not ok and exc_info is not None:
1811 if not ok and exc_info is not None:
1812 raise exc_info[0], exc_info[1], exc_info[2]
1812 raise exc_info[0], exc_info[1], exc_info[2]
1813
1813
1814 def __xrepr__(self, mode="default"):
1814 def __xrepr__(self, mode="default"):
1815 if mode == "header" or mode == "footer":
1815 if mode == "header" or mode == "footer":
1816 input = getattr(self, "input", None)
1816 input = getattr(self, "input", None)
1817 if input is not None:
1817 if input is not None:
1818 for part in xrepr(input, mode):
1818 for part in xrepr(input, mode):
1819 yield part
1819 yield part
1820 yield (astyle.style_default, " | ")
1820 yield (astyle.style_default, " | ")
1821 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1821 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1822 for part in xrepr(self.expr, "default"):
1822 for part in xrepr(self.expr, "default"):
1823 yield part
1823 yield part
1824 yield (astyle.style_default, ")")
1824 yield (astyle.style_default, ")")
1825 else:
1825 else:
1826 yield (astyle.style_default, repr(self))
1826 yield (astyle.style_default, repr(self))
1827
1827
1828 def __repr__(self):
1828 def __repr__(self):
1829 return "<%s.%s expr=%r at 0x%x>" % \
1829 return "<%s.%s expr=%r at 0x%x>" % \
1830 (self.__class__.__module__, self.__class__.__name__,
1830 (self.__class__.__module__, self.__class__.__name__,
1831 self.expr, id(self))
1831 self.expr, id(self))
1832
1832
1833
1833
1834 class ieval(Pipe):
1834 class ieval(Pipe):
1835 """
1835 """
1836 Evaluate an expression for each object in the input pipe.
1836 Evaluate an expression for each object in the input pipe.
1837
1837
1838 Examples::
1838 Examples::
1839
1839
1840 >>> ils | ieval("_.abspath()")
1840 >>> ils | ieval("_.abspath()")
1841 # random
1841 # random
1842 >>> sys.path | ieval(ifile)
1842 >>> sys.path | ieval(ifile)
1843 # random
1843 # random
1844 """
1844 """
1845
1845
1846 def __init__(self, expr, globals=None, errors="raiseifallfail"):
1846 def __init__(self, expr, globals=None, errors="raiseifallfail"):
1847 """
1847 """
1848 Create an ``ieval`` object. ``expr`` can be a callable or a string
1848 Create an ``ieval`` object. ``expr`` can be a callable or a string
1849 containing an expression. For the meaning of ``globals`` and
1849 containing an expression. For the meaning of ``globals`` and
1850 ``errors`` see ``ifilter``.
1850 ``errors`` see ``ifilter``.
1851 """
1851 """
1852 self.expr = expr
1852 self.expr = expr
1853 self.globals = globals
1853 self.globals = globals
1854 self.errors = errors
1854 self.errors = errors
1855
1855
1856 def __iter__(self):
1856 def __iter__(self):
1857 if callable(self.expr):
1857 if callable(self.expr):
1858 do = self.expr
1858 do = self.expr
1859 else:
1859 else:
1860 g = getglobals(self.globals)
1860 g = getglobals(self.globals)
1861 expr = compile(self.expr, "ipipe-expression", "eval")
1861 expr = compile(self.expr, "ipipe-expression", "eval")
1862 def do(item):
1862 def do(item):
1863 return eval(expr, g, AttrNamespace(item))
1863 return eval(expr, g, AttrNamespace(item))
1864
1864
1865 ok = 0
1865 ok = 0
1866 exc_info = None
1866 exc_info = None
1867 for item in xiter(self.input):
1867 for item in xiter(self.input):
1868 try:
1868 try:
1869 yield do(item)
1869 yield do(item)
1870 except (KeyboardInterrupt, SystemExit):
1870 except (KeyboardInterrupt, SystemExit):
1871 raise
1871 raise
1872 except Exception, exc:
1872 except Exception as exc:
1873 if self.errors == "drop":
1873 if self.errors == "drop":
1874 pass # Ignore errors
1874 pass # Ignore errors
1875 elif self.errors == "keep":
1875 elif self.errors == "keep":
1876 yield item
1876 yield item
1877 elif self.errors == "keeperror":
1877 elif self.errors == "keeperror":
1878 yield exc
1878 yield exc
1879 elif self.errors == "raise":
1879 elif self.errors == "raise":
1880 raise
1880 raise
1881 elif self.errors == "raiseifallfail":
1881 elif self.errors == "raiseifallfail":
1882 if exc_info is None:
1882 if exc_info is None:
1883 exc_info = sys.exc_info()
1883 exc_info = sys.exc_info()
1884 if not ok and exc_info is not None:
1884 if not ok and exc_info is not None:
1885 raise exc_info[0], exc_info[1], exc_info[2]
1885 raise exc_info[0], exc_info[1], exc_info[2]
1886
1886
1887 def __xrepr__(self, mode="default"):
1887 def __xrepr__(self, mode="default"):
1888 if mode == "header" or mode == "footer":
1888 if mode == "header" or mode == "footer":
1889 input = getattr(self, "input", None)
1889 input = getattr(self, "input", None)
1890 if input is not None:
1890 if input is not None:
1891 for part in xrepr(input, mode):
1891 for part in xrepr(input, mode):
1892 yield part
1892 yield part
1893 yield (astyle.style_default, " | ")
1893 yield (astyle.style_default, " | ")
1894 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1894 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1895 for part in xrepr(self.expr, "default"):
1895 for part in xrepr(self.expr, "default"):
1896 yield part
1896 yield part
1897 yield (astyle.style_default, ")")
1897 yield (astyle.style_default, ")")
1898 else:
1898 else:
1899 yield (astyle.style_default, repr(self))
1899 yield (astyle.style_default, repr(self))
1900
1900
1901 def __repr__(self):
1901 def __repr__(self):
1902 return "<%s.%s expr=%r at 0x%x>" % \
1902 return "<%s.%s expr=%r at 0x%x>" % \
1903 (self.__class__.__module__, self.__class__.__name__,
1903 (self.__class__.__module__, self.__class__.__name__,
1904 self.expr, id(self))
1904 self.expr, id(self))
1905
1905
1906
1906
1907 class ienum(Pipe):
1907 class ienum(Pipe):
1908 """
1908 """
1909 Enumerate the input pipe (i.e. wrap each input object in an object
1909 Enumerate the input pipe (i.e. wrap each input object in an object
1910 with ``index`` and ``object`` attributes).
1910 with ``index`` and ``object`` attributes).
1911
1911
1912 Examples::
1912 Examples::
1913
1913
1914 >>> xrange(20) | ieval("_,_*_") | ienum | ifilter("index % 2 == 0") | ieval("object")
1914 >>> xrange(20) | ieval("_,_*_") | ienum | ifilter("index % 2 == 0") | ieval("object")
1915 """
1915 """
1916 skip_doctest = True
1916 skip_doctest = True
1917
1917
1918 def __iter__(self):
1918 def __iter__(self):
1919 fields = ("index", "object")
1919 fields = ("index", "object")
1920 for (index, object) in enumerate(xiter(self.input)):
1920 for (index, object) in enumerate(xiter(self.input)):
1921 yield Fields(fields, index=index, object=object)
1921 yield Fields(fields, index=index, object=object)
1922
1922
1923
1923
1924 class isort(Pipe):
1924 class isort(Pipe):
1925 """
1925 """
1926 Sorts the input pipe.
1926 Sorts the input pipe.
1927
1927
1928 Examples::
1928 Examples::
1929
1929
1930 >>> ils | isort("size")
1930 >>> ils | isort("size")
1931 <IPython.extensions.ipipe.isort key='size' reverse=False at 0x849ec2c>
1931 <IPython.extensions.ipipe.isort key='size' reverse=False at 0x849ec2c>
1932 >>> ils | isort("_.isdir(), _.lower()", reverse=True)
1932 >>> ils | isort("_.isdir(), _.lower()", reverse=True)
1933 <IPython.extensions.ipipe.isort key='_.isdir(), _.lower()' reverse=True at 0x849eacc>
1933 <IPython.extensions.ipipe.isort key='_.isdir(), _.lower()' reverse=True at 0x849eacc>
1934 # all-random
1934 # all-random
1935 """
1935 """
1936
1936
1937 def __init__(self, key=None, globals=None, reverse=False):
1937 def __init__(self, key=None, globals=None, reverse=False):
1938 """
1938 """
1939 Create an ``isort`` object. ``key`` can be a callable or a string
1939 Create an ``isort`` object. ``key`` can be a callable or a string
1940 containing an expression (or ``None`` in which case the items
1940 containing an expression (or ``None`` in which case the items
1941 themselves will be sorted). If ``reverse`` is true the sort order
1941 themselves will be sorted). If ``reverse`` is true the sort order
1942 will be reversed. For the meaning of ``globals`` see ``ifilter``.
1942 will be reversed. For the meaning of ``globals`` see ``ifilter``.
1943 """
1943 """
1944 self.key = key
1944 self.key = key
1945 self.globals = globals
1945 self.globals = globals
1946 self.reverse = reverse
1946 self.reverse = reverse
1947
1947
1948 def __iter__(self):
1948 def __iter__(self):
1949 if self.key is None:
1949 if self.key is None:
1950 items = sorted(xiter(self.input), reverse=self.reverse)
1950 items = sorted(xiter(self.input), reverse=self.reverse)
1951 elif callable(self.key):
1951 elif callable(self.key):
1952 items = sorted(xiter(self.input), key=self.key, reverse=self.reverse)
1952 items = sorted(xiter(self.input), key=self.key, reverse=self.reverse)
1953 else:
1953 else:
1954 g = getglobals(self.globals)
1954 g = getglobals(self.globals)
1955 key = compile(self.key, "ipipe-expression", "eval")
1955 key = compile(self.key, "ipipe-expression", "eval")
1956 def realkey(item):
1956 def realkey(item):
1957 return eval(key, g, AttrNamespace(item))
1957 return eval(key, g, AttrNamespace(item))
1958 items = sorted(xiter(self.input), key=realkey, reverse=self.reverse)
1958 items = sorted(xiter(self.input), key=realkey, reverse=self.reverse)
1959 for item in items:
1959 for item in items:
1960 yield item
1960 yield item
1961
1961
1962 def __xrepr__(self, mode="default"):
1962 def __xrepr__(self, mode="default"):
1963 if mode == "header" or mode == "footer":
1963 if mode == "header" or mode == "footer":
1964 input = getattr(self, "input", None)
1964 input = getattr(self, "input", None)
1965 if input is not None:
1965 if input is not None:
1966 for part in xrepr(input, mode):
1966 for part in xrepr(input, mode):
1967 yield part
1967 yield part
1968 yield (astyle.style_default, " | ")
1968 yield (astyle.style_default, " | ")
1969 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1969 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1970 for part in xrepr(self.key, "default"):
1970 for part in xrepr(self.key, "default"):
1971 yield part
1971 yield part
1972 if self.reverse:
1972 if self.reverse:
1973 yield (astyle.style_default, ", ")
1973 yield (astyle.style_default, ", ")
1974 for part in xrepr(True, "default"):
1974 for part in xrepr(True, "default"):
1975 yield part
1975 yield part
1976 yield (astyle.style_default, ")")
1976 yield (astyle.style_default, ")")
1977 else:
1977 else:
1978 yield (astyle.style_default, repr(self))
1978 yield (astyle.style_default, repr(self))
1979
1979
1980 def __repr__(self):
1980 def __repr__(self):
1981 return "<%s.%s key=%r reverse=%r at 0x%x>" % \
1981 return "<%s.%s key=%r reverse=%r at 0x%x>" % \
1982 (self.__class__.__module__, self.__class__.__name__,
1982 (self.__class__.__module__, self.__class__.__name__,
1983 self.key, self.reverse, id(self))
1983 self.key, self.reverse, id(self))
1984
1984
1985
1985
1986 tab = 3 # for expandtabs()
1986 tab = 3 # for expandtabs()
1987
1987
1988 def _format(field):
1988 def _format(field):
1989 if isinstance(field, str):
1989 if isinstance(field, str):
1990 text = repr(field.expandtabs(tab))[1:-1]
1990 text = repr(field.expandtabs(tab))[1:-1]
1991 elif isinstance(field, unicode):
1991 elif isinstance(field, unicode):
1992 text = repr(field.expandtabs(tab))[2:-1]
1992 text = repr(field.expandtabs(tab))[2:-1]
1993 elif isinstance(field, datetime.datetime):
1993 elif isinstance(field, datetime.datetime):
1994 # Don't use strftime() here, as this requires year >= 1900
1994 # Don't use strftime() here, as this requires year >= 1900
1995 text = "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \
1995 text = "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \
1996 (field.year, field.month, field.day,
1996 (field.year, field.month, field.day,
1997 field.hour, field.minute, field.second, field.microsecond)
1997 field.hour, field.minute, field.second, field.microsecond)
1998 elif isinstance(field, datetime.date):
1998 elif isinstance(field, datetime.date):
1999 text = "%04d-%02d-%02d" % (field.year, field.month, field.day)
1999 text = "%04d-%02d-%02d" % (field.year, field.month, field.day)
2000 else:
2000 else:
2001 text = repr(field)
2001 text = repr(field)
2002 return text
2002 return text
2003
2003
2004
2004
2005 class Display(object):
2005 class Display(object):
2006 class __metaclass__(type):
2006 class __metaclass__(type):
2007 def __ror__(self, input):
2007 def __ror__(self, input):
2008 return input | self()
2008 return input | self()
2009
2009
2010 def __init__(self, input=None):
2010 def __init__(self, input=None):
2011 self.input = input
2011 self.input = input
2012
2012
2013 def __ror__(self, input):
2013 def __ror__(self, input):
2014 self.input = input
2014 self.input = input
2015 return self
2015 return self
2016
2016
2017 def display(self):
2017 def display(self):
2018 pass
2018 pass
2019
2019
2020
2020
2021 class iless(Display):
2021 class iless(Display):
2022 cmd = "less --quit-if-one-screen --LONG-PROMPT --LINE-NUMBERS --chop-long-lines --shift=8 --RAW-CONTROL-CHARS"
2022 cmd = "less --quit-if-one-screen --LONG-PROMPT --LINE-NUMBERS --chop-long-lines --shift=8 --RAW-CONTROL-CHARS"
2023
2023
2024 def display(self):
2024 def display(self):
2025 try:
2025 try:
2026 pager = os.popen(self.cmd, "w")
2026 pager = os.popen(self.cmd, "w")
2027 try:
2027 try:
2028 for item in xiter(self.input):
2028 for item in xiter(self.input):
2029 first = False
2029 first = False
2030 for attr in xattrs(item, "default"):
2030 for attr in xattrs(item, "default"):
2031 if first:
2031 if first:
2032 first = False
2032 first = False
2033 else:
2033 else:
2034 pager.write(" ")
2034 pager.write(" ")
2035 attr = upgradexattr(attr)
2035 attr = upgradexattr(attr)
2036 if not isinstance(attr, SelfDescriptor):
2036 if not isinstance(attr, SelfDescriptor):
2037 pager.write(attr.name())
2037 pager.write(attr.name())
2038 pager.write("=")
2038 pager.write("=")
2039 pager.write(str(attr.value(item)))
2039 pager.write(str(attr.value(item)))
2040 pager.write("\n")
2040 pager.write("\n")
2041 finally:
2041 finally:
2042 pager.close()
2042 pager.close()
2043 except Exception, exc:
2043 except Exception as exc:
2044 print "%s: %s" % (exc.__class__.__name__, str(exc))
2044 print "%s: %s" % (exc.__class__.__name__, str(exc))
2045
2045
2046
2046
2047 class _RedirectIO(object):
2047 class _RedirectIO(object):
2048 def __init__(self,*args,**kwargs):
2048 def __init__(self,*args,**kwargs):
2049 """
2049 """
2050 Map the system output streams to self.
2050 Map the system output streams to self.
2051 """
2051 """
2052 self.stream = StringIO.StringIO()
2052 self.stream = StringIO.StringIO()
2053 self.stdout = sys.stdout
2053 self.stdout = sys.stdout
2054 sys.stdout = self
2054 sys.stdout = self
2055 self.stderr = sys.stderr
2055 self.stderr = sys.stderr
2056 sys.stderr = self
2056 sys.stderr = self
2057
2057
2058 def write(self, text):
2058 def write(self, text):
2059 """
2059 """
2060 Write both to screen and to self.
2060 Write both to screen and to self.
2061 """
2061 """
2062 self.stream.write(text)
2062 self.stream.write(text)
2063 self.stdout.write(text)
2063 self.stdout.write(text)
2064 if "\n" in text:
2064 if "\n" in text:
2065 self.stdout.flush()
2065 self.stdout.flush()
2066
2066
2067 def writelines(self, lines):
2067 def writelines(self, lines):
2068 """
2068 """
2069 Write lines both to screen and to self.
2069 Write lines both to screen and to self.
2070 """
2070 """
2071 self.stream.writelines(lines)
2071 self.stream.writelines(lines)
2072 self.stdout.writelines(lines)
2072 self.stdout.writelines(lines)
2073 self.stdout.flush()
2073 self.stdout.flush()
2074
2074
2075 def restore(self):
2075 def restore(self):
2076 """
2076 """
2077 Restore the default system streams.
2077 Restore the default system streams.
2078 """
2078 """
2079 self.stdout.flush()
2079 self.stdout.flush()
2080 self.stderr.flush()
2080 self.stderr.flush()
2081 sys.stdout = self.stdout
2081 sys.stdout = self.stdout
2082 sys.stderr = self.stderr
2082 sys.stderr = self.stderr
2083
2083
2084
2084
2085 class icap(Table):
2085 class icap(Table):
2086 """
2086 """
2087 Execute a python string and capture any output to stderr/stdout.
2087 Execute a python string and capture any output to stderr/stdout.
2088
2088
2089 Examples::
2089 Examples::
2090
2090
2091 >>> import time
2091 >>> import time
2092 >>> icap("for i in range(10): print i, time.sleep(0.1)")
2092 >>> icap("for i in range(10): print i, time.sleep(0.1)")
2093
2093
2094 """
2094 """
2095 skip_doctest = True
2095 skip_doctest = True
2096
2096
2097 def __init__(self, expr, globals=None):
2097 def __init__(self, expr, globals=None):
2098 self.expr = expr
2098 self.expr = expr
2099 self.globals = globals
2099 self.globals = globals
2100 log = _RedirectIO()
2100 log = _RedirectIO()
2101 try:
2101 try:
2102 exec(expr, getglobals(globals))
2102 exec(expr, getglobals(globals))
2103 finally:
2103 finally:
2104 log.restore()
2104 log.restore()
2105 self.stream = log.stream
2105 self.stream = log.stream
2106
2106
2107 def __iter__(self):
2107 def __iter__(self):
2108 self.stream.seek(0)
2108 self.stream.seek(0)
2109 for line in self.stream:
2109 for line in self.stream:
2110 yield line.rstrip("\r\n")
2110 yield line.rstrip("\r\n")
2111
2111
2112 def __xrepr__(self, mode="default"):
2112 def __xrepr__(self, mode="default"):
2113 if mode == "header" or mode == "footer":
2113 if mode == "header" or mode == "footer":
2114 yield (astyle.style_default,
2114 yield (astyle.style_default,
2115 "%s(%r)" % (self.__class__.__name__, self.expr))
2115 "%s(%r)" % (self.__class__.__name__, self.expr))
2116 else:
2116 else:
2117 yield (astyle.style_default, repr(self))
2117 yield (astyle.style_default, repr(self))
2118
2118
2119 def __repr__(self):
2119 def __repr__(self):
2120 return "%s.%s(%r)" % \
2120 return "%s.%s(%r)" % \
2121 (self.__class__.__module__, self.__class__.__name__, self.expr)
2121 (self.__class__.__module__, self.__class__.__name__, self.expr)
2122
2122
2123
2123
2124 def xformat(value, mode, maxlength):
2124 def xformat(value, mode, maxlength):
2125 align = None
2125 align = None
2126 full = True
2126 full = True
2127 width = 0
2127 width = 0
2128 text = astyle.Text()
2128 text = astyle.Text()
2129 for (style, part) in xrepr(value, mode):
2129 for (style, part) in xrepr(value, mode):
2130 # only consider the first result
2130 # only consider the first result
2131 if align is None:
2131 if align is None:
2132 if isinstance(style, int):
2132 if isinstance(style, int):
2133 # (style, text) really is (alignment, stop)
2133 # (style, text) really is (alignment, stop)
2134 align = style
2134 align = style
2135 full = part
2135 full = part
2136 continue
2136 continue
2137 else:
2137 else:
2138 align = -1
2138 align = -1
2139 full = True
2139 full = True
2140 if not isinstance(style, int):
2140 if not isinstance(style, int):
2141 text.append((style, part))
2141 text.append((style, part))
2142 width += len(part)
2142 width += len(part)
2143 if width >= maxlength and not full:
2143 if width >= maxlength and not full:
2144 text.append((astyle.style_ellisis, "..."))
2144 text.append((astyle.style_ellisis, "..."))
2145 width += 3
2145 width += 3
2146 break
2146 break
2147 if align is None: # default to left alignment
2147 if align is None: # default to left alignment
2148 align = -1
2148 align = -1
2149 return (align, width, text)
2149 return (align, width, text)
2150
2150
2151
2151
2152
2152
2153 import astyle
2153 import astyle
2154
2154
2155 class idump(Display):
2155 class idump(Display):
2156 # The approximate maximum length of a column entry
2156 # The approximate maximum length of a column entry
2157 maxattrlength = 200
2157 maxattrlength = 200
2158
2158
2159 # Style for column names
2159 # Style for column names
2160 style_header = astyle.Style.fromstr("white:black:bold")
2160 style_header = astyle.Style.fromstr("white:black:bold")
2161
2161
2162 def __init__(self, input=None, *attrs):
2162 def __init__(self, input=None, *attrs):
2163 Display.__init__(self, input)
2163 Display.__init__(self, input)
2164 self.attrs = [upgradexattr(attr) for attr in attrs]
2164 self.attrs = [upgradexattr(attr) for attr in attrs]
2165 self.headerpadchar = " "
2165 self.headerpadchar = " "
2166 self.headersepchar = "|"
2166 self.headersepchar = "|"
2167 self.datapadchar = " "
2167 self.datapadchar = " "
2168 self.datasepchar = "|"
2168 self.datasepchar = "|"
2169
2169
2170 def display(self):
2170 def display(self):
2171 stream = Term.cout
2171 stream = Term.cout
2172 allattrs = []
2172 allattrs = []
2173 attrset = set()
2173 attrset = set()
2174 colwidths = {}
2174 colwidths = {}
2175 rows = []
2175 rows = []
2176 for item in xiter(self.input):
2176 for item in xiter(self.input):
2177 row = {}
2177 row = {}
2178 attrs = self.attrs
2178 attrs = self.attrs
2179 if not attrs:
2179 if not attrs:
2180 attrs = xattrs(item, "default")
2180 attrs = xattrs(item, "default")
2181 for attr in attrs:
2181 for attr in attrs:
2182 if attr not in attrset:
2182 if attr not in attrset:
2183 allattrs.append(attr)
2183 allattrs.append(attr)
2184 attrset.add(attr)
2184 attrset.add(attr)
2185 colwidths[attr] = len(attr.name())
2185 colwidths[attr] = len(attr.name())
2186 try:
2186 try:
2187 value = attr.value(item)
2187 value = attr.value(item)
2188 except (KeyboardInterrupt, SystemExit):
2188 except (KeyboardInterrupt, SystemExit):
2189 raise
2189 raise
2190 except Exception, exc:
2190 except Exception as exc:
2191 value = exc
2191 value = exc
2192 (align, width, text) = xformat(value, "cell", self.maxattrlength)
2192 (align, width, text) = xformat(value, "cell", self.maxattrlength)
2193 colwidths[attr] = max(colwidths[attr], width)
2193 colwidths[attr] = max(colwidths[attr], width)
2194 # remember alignment, length and colored parts
2194 # remember alignment, length and colored parts
2195 row[attr] = (align, width, text)
2195 row[attr] = (align, width, text)
2196 rows.append(row)
2196 rows.append(row)
2197
2197
2198 stream.write("\n")
2198 stream.write("\n")
2199 for (i, attr) in enumerate(allattrs):
2199 for (i, attr) in enumerate(allattrs):
2200 attrname = attr.name()
2200 attrname = attr.name()
2201 self.style_header(attrname).write(stream)
2201 self.style_header(attrname).write(stream)
2202 spc = colwidths[attr] - len(attrname)
2202 spc = colwidths[attr] - len(attrname)
2203 if i < len(colwidths)-1:
2203 if i < len(colwidths)-1:
2204 stream.write(self.headerpadchar*spc)
2204 stream.write(self.headerpadchar*spc)
2205 stream.write(self.headersepchar)
2205 stream.write(self.headersepchar)
2206 stream.write("\n")
2206 stream.write("\n")
2207
2207
2208 for row in rows:
2208 for row in rows:
2209 for (i, attr) in enumerate(allattrs):
2209 for (i, attr) in enumerate(allattrs):
2210 (align, width, text) = row[attr]
2210 (align, width, text) = row[attr]
2211 spc = colwidths[attr] - width
2211 spc = colwidths[attr] - width
2212 if align == -1:
2212 if align == -1:
2213 text.write(stream)
2213 text.write(stream)
2214 if i < len(colwidths)-1:
2214 if i < len(colwidths)-1:
2215 stream.write(self.datapadchar*spc)
2215 stream.write(self.datapadchar*spc)
2216 elif align == 0:
2216 elif align == 0:
2217 spc = colwidths[attr] - width
2217 spc = colwidths[attr] - width
2218 spc1 = spc//2
2218 spc1 = spc//2
2219 spc2 = spc-spc1
2219 spc2 = spc-spc1
2220 stream.write(self.datapadchar*spc1)
2220 stream.write(self.datapadchar*spc1)
2221 text.write(stream)
2221 text.write(stream)
2222 if i < len(colwidths)-1:
2222 if i < len(colwidths)-1:
2223 stream.write(self.datapadchar*spc2)
2223 stream.write(self.datapadchar*spc2)
2224 else:
2224 else:
2225 stream.write(self.datapadchar*spc)
2225 stream.write(self.datapadchar*spc)
2226 text.write(stream)
2226 text.write(stream)
2227 if i < len(colwidths)-1:
2227 if i < len(colwidths)-1:
2228 stream.write(self.datasepchar)
2228 stream.write(self.datasepchar)
2229 stream.write("\n")
2229 stream.write("\n")
2230
2230
2231
2231
2232 class AttributeDetail(Table):
2232 class AttributeDetail(Table):
2233 """
2233 """
2234 ``AttributeDetail`` objects are use for displaying a detailed list of object
2234 ``AttributeDetail`` objects are use for displaying a detailed list of object
2235 attributes.
2235 attributes.
2236 """
2236 """
2237 def __init__(self, object, descriptor):
2237 def __init__(self, object, descriptor):
2238 self.object = object
2238 self.object = object
2239 self.descriptor = descriptor
2239 self.descriptor = descriptor
2240
2240
2241 def __iter__(self):
2241 def __iter__(self):
2242 return self.descriptor.iter(self.object)
2242 return self.descriptor.iter(self.object)
2243
2243
2244 def name(self):
2244 def name(self):
2245 return self.descriptor.name()
2245 return self.descriptor.name()
2246
2246
2247 def attrtype(self):
2247 def attrtype(self):
2248 return self.descriptor.attrtype(self.object)
2248 return self.descriptor.attrtype(self.object)
2249
2249
2250 def valuetype(self):
2250 def valuetype(self):
2251 return self.descriptor.valuetype(self.object)
2251 return self.descriptor.valuetype(self.object)
2252
2252
2253 def doc(self):
2253 def doc(self):
2254 return self.descriptor.doc(self.object)
2254 return self.descriptor.doc(self.object)
2255
2255
2256 def shortdoc(self):
2256 def shortdoc(self):
2257 return self.descriptor.shortdoc(self.object)
2257 return self.descriptor.shortdoc(self.object)
2258
2258
2259 def value(self):
2259 def value(self):
2260 return self.descriptor.value(self.object)
2260 return self.descriptor.value(self.object)
2261
2261
2262 def __xattrs__(self, mode="default"):
2262 def __xattrs__(self, mode="default"):
2263 attrs = ("name()", "attrtype()", "valuetype()", "value()", "shortdoc()")
2263 attrs = ("name()", "attrtype()", "valuetype()", "value()", "shortdoc()")
2264 if mode == "detail":
2264 if mode == "detail":
2265 attrs += ("doc()",)
2265 attrs += ("doc()",)
2266 return attrs
2266 return attrs
2267
2267
2268 def __xrepr__(self, mode="default"):
2268 def __xrepr__(self, mode="default"):
2269 yield (-1, True)
2269 yield (-1, True)
2270 valuetype = self.valuetype()
2270 valuetype = self.valuetype()
2271 if valuetype is not noitem:
2271 if valuetype is not noitem:
2272 for part in xrepr(valuetype):
2272 for part in xrepr(valuetype):
2273 yield part
2273 yield part
2274 yield (astyle.style_default, " ")
2274 yield (astyle.style_default, " ")
2275 yield (astyle.style_default, self.attrtype())
2275 yield (astyle.style_default, self.attrtype())
2276 yield (astyle.style_default, " ")
2276 yield (astyle.style_default, " ")
2277 yield (astyle.style_default, self.name())
2277 yield (astyle.style_default, self.name())
2278 yield (astyle.style_default, " of ")
2278 yield (astyle.style_default, " of ")
2279 for part in xrepr(self.object):
2279 for part in xrepr(self.object):
2280 yield part
2280 yield part
2281
2281
2282
2282
2283 try:
2283 try:
2284 from ibrowse import ibrowse
2284 from ibrowse import ibrowse
2285 except ImportError:
2285 except ImportError:
2286 # No curses (probably Windows) => try igrid
2286 # No curses (probably Windows) => try igrid
2287 try:
2287 try:
2288 from igrid import igrid
2288 from igrid import igrid
2289 except ImportError:
2289 except ImportError:
2290 # no wx either => use ``idump`` as the default display.
2290 # no wx either => use ``idump`` as the default display.
2291 defaultdisplay = idump
2291 defaultdisplay = idump
2292 else:
2292 else:
2293 defaultdisplay = igrid
2293 defaultdisplay = igrid
2294 __all__.append("igrid")
2294 __all__.append("igrid")
2295 else:
2295 else:
2296 defaultdisplay = ibrowse
2296 defaultdisplay = ibrowse
2297 __all__.append("ibrowse")
2297 __all__.append("ibrowse")
2298
2298
2299
2299
2300 # If we're running under IPython, register our objects with IPython's
2300 # If we're running under IPython, register our objects with IPython's
2301 # generic function ``result_display``, else install a displayhook
2301 # generic function ``result_display``, else install a displayhook
2302 # directly as sys.displayhook
2302 # directly as sys.displayhook
2303 if generics is not None:
2303 if generics is not None:
2304 def display_display(obj):
2304 def display_display(obj):
2305 return obj.display()
2305 return obj.display()
2306 generics.result_display.when_type(Display)(display_display)
2306 generics.result_display.when_type(Display)(display_display)
2307
2307
2308 def display_tableobject(obj):
2308 def display_tableobject(obj):
2309 return display_display(defaultdisplay(obj))
2309 return display_display(defaultdisplay(obj))
2310 generics.result_display.when_type(Table)(display_tableobject)
2310 generics.result_display.when_type(Table)(display_tableobject)
2311
2311
2312 def display_tableclass(obj):
2312 def display_tableclass(obj):
2313 return display_tableobject(obj())
2313 return display_tableobject(obj())
2314 generics.result_display.when_type(Table.__metaclass__)(display_tableclass)
2314 generics.result_display.when_type(Table.__metaclass__)(display_tableclass)
2315 else:
2315 else:
2316 def installdisplayhook():
2316 def installdisplayhook():
2317 _originalhook = sys.displayhook
2317 _originalhook = sys.displayhook
2318 def displayhook(obj):
2318 def displayhook(obj):
2319 if isinstance(obj, type) and issubclass(obj, Table):
2319 if isinstance(obj, type) and issubclass(obj, Table):
2320 obj = obj()
2320 obj = obj()
2321 if isinstance(obj, Table):
2321 if isinstance(obj, Table):
2322 obj = defaultdisplay(obj)
2322 obj = defaultdisplay(obj)
2323 if isinstance(obj, Display):
2323 if isinstance(obj, Display):
2324 return obj.display()
2324 return obj.display()
2325 else:
2325 else:
2326 _originalhook(obj)
2326 _originalhook(obj)
2327 sys.displayhook = displayhook
2327 sys.displayhook = displayhook
2328 installdisplayhook()
2328 installdisplayhook()
@@ -1,343 +1,343 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 # -*- test-case-name: IPython.frontend.tests.test_frontendbase -*-
2 # -*- test-case-name: IPython.frontend.tests.test_frontendbase -*-
3 """
3 """
4 frontendbase provides an interface and base class for GUI frontends for
4 frontendbase provides an interface and base class for GUI frontends for
5 IPython.kernel/IPython.kernel.core.
5 IPython.kernel/IPython.kernel.core.
6
6
7 Frontend implementations will likely want to subclass FrontEndBase.
7 Frontend implementations will likely want to subclass FrontEndBase.
8
8
9 Author: Barry Wark
9 Author: Barry Wark
10 """
10 """
11 __docformat__ = "restructuredtext en"
11 __docformat__ = "restructuredtext en"
12
12
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14 # Copyright (C) 2008-2011 The IPython Development Team
14 # Copyright (C) 2008-2011 The IPython Development Team
15 #
15 #
16 # Distributed under the terms of the BSD License. The full license is in
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
17 # the file COPYING, distributed as part of this software.
18 #-------------------------------------------------------------------------------
18 #-------------------------------------------------------------------------------
19
19
20 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
21 # Imports
21 # Imports
22 #-------------------------------------------------------------------------------
22 #-------------------------------------------------------------------------------
23 import string
23 import string
24 import codeop
24 import codeop
25 import uuid
25 import uuid
26
26
27
27
28 from IPython.frontend.zopeinterface import (
28 from IPython.frontend.zopeinterface import (
29 Interface,
29 Interface,
30 Attribute,
30 Attribute,
31 )
31 )
32 from IPython.kernel.core.history import FrontEndHistory
32 from IPython.kernel.core.history import FrontEndHistory
33 from IPython.kernel.core.util import Bunch
33 from IPython.kernel.core.util import Bunch
34
34
35 ##############################################################################
35 ##############################################################################
36 # TEMPORARY!!! fake configuration, while we decide whether to use tconfig or
36 # TEMPORARY!!! fake configuration, while we decide whether to use tconfig or
37 # not
37 # not
38
38
39 rc = Bunch()
39 rc = Bunch()
40 rc.prompt_in1 = r'In [$number]: '
40 rc.prompt_in1 = r'In [$number]: '
41 rc.prompt_in2 = r'...'
41 rc.prompt_in2 = r'...'
42 rc.prompt_out = r'Out [$number]: '
42 rc.prompt_out = r'Out [$number]: '
43
43
44 ##############################################################################
44 ##############################################################################
45 # Interface definitions
45 # Interface definitions
46 ##############################################################################
46 ##############################################################################
47
47
48 class IFrontEndFactory(Interface):
48 class IFrontEndFactory(Interface):
49 """Factory interface for frontends."""
49 """Factory interface for frontends."""
50
50
51 def __call__(engine=None, history=None):
51 def __call__(engine=None, history=None):
52 """
52 """
53 Parameters:
53 Parameters:
54 interpreter : IPython.kernel.engineservice.IEngineCore
54 interpreter : IPython.kernel.engineservice.IEngineCore
55 """
55 """
56
56
57 pass
57 pass
58
58
59
59
60 class IFrontEnd(Interface):
60 class IFrontEnd(Interface):
61 """Interface for frontends. All methods return t.i.d.Deferred"""
61 """Interface for frontends. All methods return t.i.d.Deferred"""
62
62
63 Attribute("input_prompt_template", "string.Template instance\
63 Attribute("input_prompt_template", "string.Template instance\
64 substituteable with execute result.")
64 substituteable with execute result.")
65 Attribute("output_prompt_template", "string.Template instance\
65 Attribute("output_prompt_template", "string.Template instance\
66 substituteable with execute result.")
66 substituteable with execute result.")
67 Attribute("continuation_prompt_template", "string.Template instance\
67 Attribute("continuation_prompt_template", "string.Template instance\
68 substituteable with execute result.")
68 substituteable with execute result.")
69
69
70 def update_cell_prompt(result, blockID=None):
70 def update_cell_prompt(result, blockID=None):
71 """Subclass may override to update the input prompt for a block.
71 """Subclass may override to update the input prompt for a block.
72
72
73 In asynchronous frontends, this method will be called as a
73 In asynchronous frontends, this method will be called as a
74 twisted.internet.defer.Deferred's callback/errback.
74 twisted.internet.defer.Deferred's callback/errback.
75 Implementations should thus return result when finished.
75 Implementations should thus return result when finished.
76
76
77 Result is a result dict in case of success, and a
77 Result is a result dict in case of success, and a
78 twisted.python.util.failure.Failure in case of an error
78 twisted.python.util.failure.Failure in case of an error
79 """
79 """
80
80
81 pass
81 pass
82
82
83 def render_result(result):
83 def render_result(result):
84 """Render the result of an execute call. Implementors may choose the
84 """Render the result of an execute call. Implementors may choose the
85 method of rendering.
85 method of rendering.
86 For example, a notebook-style frontend might render a Chaco plot
86 For example, a notebook-style frontend might render a Chaco plot
87 inline.
87 inline.
88
88
89 Parameters:
89 Parameters:
90 result : dict (result of IEngineBase.execute )
90 result : dict (result of IEngineBase.execute )
91 blockID = result['blockID']
91 blockID = result['blockID']
92
92
93 Result:
93 Result:
94 Output of frontend rendering
94 Output of frontend rendering
95 """
95 """
96
96
97 pass
97 pass
98
98
99 def render_error(failure):
99 def render_error(failure):
100 """Subclasses must override to render the failure.
100 """Subclasses must override to render the failure.
101
101
102 In asynchronous frontend, since this method will be called as a
102 In asynchronous frontend, since this method will be called as a
103 twisted.internet.defer.Deferred's callback. Implementations
103 twisted.internet.defer.Deferred's callback. Implementations
104 should thus return result when finished.
104 should thus return result when finished.
105
105
106 blockID = failure.blockID
106 blockID = failure.blockID
107 """
107 """
108
108
109 pass
109 pass
110
110
111 def input_prompt(number=''):
111 def input_prompt(number=''):
112 """Returns the input prompt by subsituting into
112 """Returns the input prompt by subsituting into
113 self.input_prompt_template
113 self.input_prompt_template
114 """
114 """
115 pass
115 pass
116
116
117 def output_prompt(number=''):
117 def output_prompt(number=''):
118 """Returns the output prompt by subsituting into
118 """Returns the output prompt by subsituting into
119 self.output_prompt_template
119 self.output_prompt_template
120 """
120 """
121
121
122 pass
122 pass
123
123
124 def continuation_prompt():
124 def continuation_prompt():
125 """Returns the continuation prompt by subsituting into
125 """Returns the continuation prompt by subsituting into
126 self.continuation_prompt_template
126 self.continuation_prompt_template
127 """
127 """
128
128
129 pass
129 pass
130
130
131 def is_complete(block):
131 def is_complete(block):
132 """Returns True if block is complete, False otherwise."""
132 """Returns True if block is complete, False otherwise."""
133
133
134 pass
134 pass
135
135
136
136
137 def get_history_previous(current_block):
137 def get_history_previous(current_block):
138 """Returns the block previous in the history. Saves currentBlock if
138 """Returns the block previous in the history. Saves currentBlock if
139 the history_cursor is currently at the end of the input history"""
139 the history_cursor is currently at the end of the input history"""
140 pass
140 pass
141
141
142 def get_history_next():
142 def get_history_next():
143 """Returns the next block in the history."""
143 """Returns the next block in the history."""
144
144
145 pass
145 pass
146
146
147 def complete(self, line):
147 def complete(self, line):
148 """Returns the list of possible completions, and the completed
148 """Returns the list of possible completions, and the completed
149 line.
149 line.
150
150
151 The input argument is the full line to be completed. This method
151 The input argument is the full line to be completed. This method
152 returns both the line completed as much as possible, and the list
152 returns both the line completed as much as possible, and the list
153 of further possible completions (full words).
153 of further possible completions (full words).
154 """
154 """
155 pass
155 pass
156
156
157
157
158 ##############################################################################
158 ##############################################################################
159 # Base class for all the frontends.
159 # Base class for all the frontends.
160 ##############################################################################
160 ##############################################################################
161
161
162 class FrontEndBase(object):
162 class FrontEndBase(object):
163 """
163 """
164 FrontEndBase manages the state tasks for a CLI frontend:
164 FrontEndBase manages the state tasks for a CLI frontend:
165 - Input and output history management
165 - Input and output history management
166 - Input/continuation and output prompt generation
166 - Input/continuation and output prompt generation
167
167
168 Some issues (due to possibly unavailable engine):
168 Some issues (due to possibly unavailable engine):
169 - How do we get the current cell number for the engine?
169 - How do we get the current cell number for the engine?
170 - How do we handle completions?
170 - How do we handle completions?
171 """
171 """
172
172
173 history_cursor = 0
173 history_cursor = 0
174
174
175 input_prompt_template = string.Template(rc.prompt_in1)
175 input_prompt_template = string.Template(rc.prompt_in1)
176 output_prompt_template = string.Template(rc.prompt_out)
176 output_prompt_template = string.Template(rc.prompt_out)
177 continuation_prompt_template = string.Template(rc.prompt_in2)
177 continuation_prompt_template = string.Template(rc.prompt_in2)
178
178
179 def __init__(self, shell=None, history=None):
179 def __init__(self, shell=None, history=None):
180 self.shell = shell
180 self.shell = shell
181 if history is None:
181 if history is None:
182 self.history = FrontEndHistory(input_cache=[''])
182 self.history = FrontEndHistory(input_cache=[''])
183 else:
183 else:
184 self.history = history
184 self.history = history
185
185
186
186
187 def input_prompt(self, number=''):
187 def input_prompt(self, number=''):
188 """Returns the current input prompt
188 """Returns the current input prompt
189
189
190 It would be great to use ipython1.core.prompts.Prompt1 here
190 It would be great to use ipython1.core.prompts.Prompt1 here
191 """
191 """
192 return self.input_prompt_template.safe_substitute({'number':number})
192 return self.input_prompt_template.safe_substitute({'number':number})
193
193
194
194
195 def continuation_prompt(self):
195 def continuation_prompt(self):
196 """Returns the current continuation prompt"""
196 """Returns the current continuation prompt"""
197
197
198 return self.continuation_prompt_template.safe_substitute()
198 return self.continuation_prompt_template.safe_substitute()
199
199
200 def output_prompt(self, number=''):
200 def output_prompt(self, number=''):
201 """Returns the output prompt for result"""
201 """Returns the output prompt for result"""
202
202
203 return self.output_prompt_template.safe_substitute({'number':number})
203 return self.output_prompt_template.safe_substitute({'number':number})
204
204
205
205
206 def is_complete(self, block):
206 def is_complete(self, block):
207 """Determine if block is complete.
207 """Determine if block is complete.
208
208
209 Parameters
209 Parameters
210 block : string
210 block : string
211
211
212 Result
212 Result
213 True if block can be sent to the engine without compile errors.
213 True if block can be sent to the engine without compile errors.
214 False otherwise.
214 False otherwise.
215 """
215 """
216
216
217 try:
217 try:
218 is_complete = codeop.compile_command(block.rstrip() + '\n\n',
218 is_complete = codeop.compile_command(block.rstrip() + '\n\n',
219 "<string>", "exec")
219 "<string>", "exec")
220 except:
220 except:
221 return False
221 return False
222
222
223 lines = block.split('\n')
223 lines = block.split('\n')
224 return ((is_complete is not None)
224 return ((is_complete is not None)
225 and (len(lines)==1 or str(lines[-1])==''))
225 and (len(lines)==1 or str(lines[-1])==''))
226
226
227
227
228 def execute(self, block, blockID=None):
228 def execute(self, block, blockID=None):
229 """Execute the block and return the result.
229 """Execute the block and return the result.
230
230
231 Parameters:
231 Parameters:
232 block : {str, AST}
232 block : {str, AST}
233 blockID : any
233 blockID : any
234 Caller may provide an ID to identify this block.
234 Caller may provide an ID to identify this block.
235 result['blockID'] := blockID
235 result['blockID'] := blockID
236
236
237 Result:
237 Result:
238 Deferred result of self.interpreter.execute
238 Deferred result of self.interpreter.execute
239 """
239 """
240
240
241 if(not self.is_complete(block)):
241 if(not self.is_complete(block)):
242 raise Exception("Block is not compilable")
242 raise Exception("Block is not compilable")
243
243
244 if(blockID == None):
244 if(blockID == None):
245 blockID = uuid.uuid4()
245 blockID = uuid.uuid4()
246
246
247 try:
247 try:
248 result = self.shell.execute(block)
248 result = self.shell.execute(block)
249 except Exception,e:
249 except Exception as e:
250 e = self._add_block_id_for_failure(e, blockID=blockID)
250 e = self._add_block_id_for_failure(e, blockID=blockID)
251 e = self.update_cell_prompt(e, blockID=blockID)
251 e = self.update_cell_prompt(e, blockID=blockID)
252 e = self.render_error(e)
252 e = self.render_error(e)
253 else:
253 else:
254 result = self._add_block_id_for_result(result, blockID=blockID)
254 result = self._add_block_id_for_result(result, blockID=blockID)
255 result = self.update_cell_prompt(result, blockID=blockID)
255 result = self.update_cell_prompt(result, blockID=blockID)
256 result = self.render_result(result)
256 result = self.render_result(result)
257
257
258 return result
258 return result
259
259
260
260
261 def _add_block_id_for_result(self, result, blockID):
261 def _add_block_id_for_result(self, result, blockID):
262 """Add the blockID to result or failure. Unfortunatley, we have to
262 """Add the blockID to result or failure. Unfortunatley, we have to
263 treat failures differently than result dicts.
263 treat failures differently than result dicts.
264 """
264 """
265
265
266 result['blockID'] = blockID
266 result['blockID'] = blockID
267
267
268 return result
268 return result
269
269
270 def _add_block_id_for_failure(self, failure, blockID):
270 def _add_block_id_for_failure(self, failure, blockID):
271 """_add_block_id_for_failure"""
271 """_add_block_id_for_failure"""
272 failure.blockID = blockID
272 failure.blockID = blockID
273 return failure
273 return failure
274
274
275
275
276 def _add_history(self, result, block=None):
276 def _add_history(self, result, block=None):
277 """Add block to the history"""
277 """Add block to the history"""
278
278
279 assert(block != None)
279 assert(block != None)
280 self.history.add_items([block])
280 self.history.add_items([block])
281 self.history_cursor += 1
281 self.history_cursor += 1
282
282
283 return result
283 return result
284
284
285
285
286 def get_history_previous(self, current_block):
286 def get_history_previous(self, current_block):
287 """ Returns previous history string and decrement history cursor.
287 """ Returns previous history string and decrement history cursor.
288 """
288 """
289 command = self.history.get_history_item(self.history_cursor - 1)
289 command = self.history.get_history_item(self.history_cursor - 1)
290
290
291 if command is not None:
291 if command is not None:
292 if(self.history_cursor+1 == len(self.history.input_cache)):
292 if(self.history_cursor+1 == len(self.history.input_cache)):
293 self.history.input_cache[self.history_cursor] = current_block
293 self.history.input_cache[self.history_cursor] = current_block
294 self.history_cursor -= 1
294 self.history_cursor -= 1
295 return command
295 return command
296
296
297
297
298 def get_history_next(self):
298 def get_history_next(self):
299 """ Returns next history string and increment history cursor.
299 """ Returns next history string and increment history cursor.
300 """
300 """
301 command = self.history.get_history_item(self.history_cursor+1)
301 command = self.history.get_history_item(self.history_cursor+1)
302
302
303 if command is not None:
303 if command is not None:
304 self.history_cursor += 1
304 self.history_cursor += 1
305 return command
305 return command
306
306
307 ###
307 ###
308 # Subclasses probably want to override these methods...
308 # Subclasses probably want to override these methods...
309 ###
309 ###
310
310
311 def update_cell_prompt(self, result, blockID=None):
311 def update_cell_prompt(self, result, blockID=None):
312 """Subclass may override to update the input prompt for a block.
312 """Subclass may override to update the input prompt for a block.
313
313
314 This method only really makes sens in asyncrhonous frontend.
314 This method only really makes sens in asyncrhonous frontend.
315 Since this method will be called as a
315 Since this method will be called as a
316 twisted.internet.defer.Deferred's callback, implementations should
316 twisted.internet.defer.Deferred's callback, implementations should
317 return result when finished.
317 return result when finished.
318 """
318 """
319
319
320 raise NotImplementedError
320 raise NotImplementedError
321
321
322
322
323 def render_result(self, result):
323 def render_result(self, result):
324 """Subclasses must override to render result.
324 """Subclasses must override to render result.
325
325
326 In asynchronous frontends, this method will be called as a
326 In asynchronous frontends, this method will be called as a
327 twisted.internet.defer.Deferred's callback. Implementations
327 twisted.internet.defer.Deferred's callback. Implementations
328 should thus return result when finished.
328 should thus return result when finished.
329 """
329 """
330
330
331 raise NotImplementedError
331 raise NotImplementedError
332
332
333
333
334 def render_error(self, failure):
334 def render_error(self, failure):
335 """Subclasses must override to render the failure.
335 """Subclasses must override to render the failure.
336
336
337 In asynchronous frontends, this method will be called as a
337 In asynchronous frontends, this method will be called as a
338 twisted.internet.defer.Deferred's callback. Implementations
338 twisted.internet.defer.Deferred's callback. Implementations
339 should thus return result when finished.
339 should thus return result when finished.
340 """
340 """
341
341
342 raise NotImplementedError
342 raise NotImplementedError
343
343
@@ -1,373 +1,373 b''
1 """
1 """
2 Base front end class for all line-oriented frontends, rather than
2 Base front end class for all line-oriented frontends, rather than
3 block-oriented.
3 block-oriented.
4
4
5 Currently this focuses on synchronous frontends.
5 Currently this focuses on synchronous frontends.
6 """
6 """
7 __docformat__ = "restructuredtext en"
7 __docformat__ = "restructuredtext en"
8
8
9 #-------------------------------------------------------------------------------
9 #-------------------------------------------------------------------------------
10 # Copyright (C) 2008-2011 The IPython Development Team
10 # Copyright (C) 2008-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 import re
19 import re
20
20
21 import sys
21 import sys
22 import codeop
22 import codeop
23
23
24 from frontendbase import FrontEndBase
24 from frontendbase import FrontEndBase
25 from IPython.kernel.core.interpreter import Interpreter
25 from IPython.kernel.core.interpreter import Interpreter
26
26
27 def common_prefix(strings):
27 def common_prefix(strings):
28 """ Given a list of strings, return the common prefix between all
28 """ Given a list of strings, return the common prefix between all
29 these strings.
29 these strings.
30 """
30 """
31 ref = strings[0]
31 ref = strings[0]
32 prefix = ''
32 prefix = ''
33 for size in range(len(ref)):
33 for size in range(len(ref)):
34 test_prefix = ref[:size+1]
34 test_prefix = ref[:size+1]
35 for string in strings[1:]:
35 for string in strings[1:]:
36 if not string.startswith(test_prefix):
36 if not string.startswith(test_prefix):
37 return prefix
37 return prefix
38 prefix = test_prefix
38 prefix = test_prefix
39
39
40 return prefix
40 return prefix
41
41
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Base class for the line-oriented front ends
43 # Base class for the line-oriented front ends
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45
45
46 class LineFrontEndBase(FrontEndBase):
46 class LineFrontEndBase(FrontEndBase):
47 """ Concrete implementation of the FrontEndBase class. This is meant
47 """ Concrete implementation of the FrontEndBase class. This is meant
48 to be the base class behind all the frontend that are line-oriented,
48 to be the base class behind all the frontend that are line-oriented,
49 rather than block-oriented.
49 rather than block-oriented.
50 """
50 """
51
51
52 # We need to keep the prompt number, to be able to increment
52 # We need to keep the prompt number, to be able to increment
53 # it when there is an exception.
53 # it when there is an exception.
54 prompt_number = 1
54 prompt_number = 1
55
55
56 # We keep a reference to the last result: it helps testing and
56 # We keep a reference to the last result: it helps testing and
57 # programatic control of the frontend.
57 # programatic control of the frontend.
58 last_result = dict(number=0)
58 last_result = dict(number=0)
59
59
60 # The last prompt displayed. Useful for continuation prompts.
60 # The last prompt displayed. Useful for continuation prompts.
61 last_prompt = ''
61 last_prompt = ''
62
62
63 # The input buffer being edited
63 # The input buffer being edited
64 input_buffer = ''
64 input_buffer = ''
65
65
66 # Set to true for debug output
66 # Set to true for debug output
67 debug = False
67 debug = False
68
68
69 # A banner to print at startup
69 # A banner to print at startup
70 banner = None
70 banner = None
71
71
72 #--------------------------------------------------------------------------
72 #--------------------------------------------------------------------------
73 # FrontEndBase interface
73 # FrontEndBase interface
74 #--------------------------------------------------------------------------
74 #--------------------------------------------------------------------------
75
75
76 def __init__(self, shell=None, history=None, banner=None, *args, **kwargs):
76 def __init__(self, shell=None, history=None, banner=None, *args, **kwargs):
77 if shell is None:
77 if shell is None:
78 shell = Interpreter()
78 shell = Interpreter()
79 FrontEndBase.__init__(self, shell=shell, history=history)
79 FrontEndBase.__init__(self, shell=shell, history=history)
80
80
81 if banner is not None:
81 if banner is not None:
82 self.banner = banner
82 self.banner = banner
83
83
84 def start(self):
84 def start(self):
85 """ Put the frontend in a state where it is ready for user
85 """ Put the frontend in a state where it is ready for user
86 interaction.
86 interaction.
87 """
87 """
88 if self.banner is not None:
88 if self.banner is not None:
89 self.write(self.banner, refresh=False)
89 self.write(self.banner, refresh=False)
90
90
91 self.new_prompt(self.input_prompt_template.substitute(number=1))
91 self.new_prompt(self.input_prompt_template.substitute(number=1))
92
92
93
93
94 def complete(self, line):
94 def complete(self, line):
95 """Complete line in engine's user_ns
95 """Complete line in engine's user_ns
96
96
97 Parameters
97 Parameters
98 ----------
98 ----------
99 line : string
99 line : string
100
100
101 Returns
101 Returns
102 -------
102 -------
103 The replacement for the line and the list of possible completions.
103 The replacement for the line and the list of possible completions.
104 """
104 """
105 completions = self.shell.complete(line)
105 completions = self.shell.complete(line)
106 complete_sep = re.compile('[\s\{\}\[\]\(\)\=]')
106 complete_sep = re.compile('[\s\{\}\[\]\(\)\=]')
107 if completions:
107 if completions:
108 prefix = common_prefix(completions)
108 prefix = common_prefix(completions)
109 residual = complete_sep.split(line)[:-1]
109 residual = complete_sep.split(line)[:-1]
110 line = line[:-len(residual)] + prefix
110 line = line[:-len(residual)] + prefix
111 return line, completions
111 return line, completions
112
112
113
113
114 def render_result(self, result):
114 def render_result(self, result):
115 """ Frontend-specific rendering of the result of a calculation
115 """ Frontend-specific rendering of the result of a calculation
116 that has been sent to an engine.
116 that has been sent to an engine.
117 """
117 """
118 if 'stdout' in result and result['stdout']:
118 if 'stdout' in result and result['stdout']:
119 self.write('\n' + result['stdout'])
119 self.write('\n' + result['stdout'])
120 if 'display' in result and result['display']:
120 if 'display' in result and result['display']:
121 self.write("%s%s\n" % (
121 self.write("%s%s\n" % (
122 self.output_prompt_template.substitute(
122 self.output_prompt_template.substitute(
123 number=result['number']),
123 number=result['number']),
124 result['display']['pprint']
124 result['display']['pprint']
125 ) )
125 ) )
126
126
127
127
128 def render_error(self, failure):
128 def render_error(self, failure):
129 """ Frontend-specific rendering of error.
129 """ Frontend-specific rendering of error.
130 """
130 """
131 self.write('\n\n'+str(failure)+'\n\n')
131 self.write('\n\n'+str(failure)+'\n\n')
132 return failure
132 return failure
133
133
134
134
135 def is_complete(self, string):
135 def is_complete(self, string):
136 """ Check if a string forms a complete, executable set of
136 """ Check if a string forms a complete, executable set of
137 commands.
137 commands.
138
138
139 For the line-oriented frontend, multi-line code is not executed
139 For the line-oriented frontend, multi-line code is not executed
140 as soon as it is complete: the users has to enter two line
140 as soon as it is complete: the users has to enter two line
141 returns.
141 returns.
142 """
142 """
143 if string in ('', '\n'):
143 if string in ('', '\n'):
144 # Prefiltering, eg through ipython0, may return an empty
144 # Prefiltering, eg through ipython0, may return an empty
145 # string although some operations have been accomplished. We
145 # string although some operations have been accomplished. We
146 # thus want to consider an empty string as a complete
146 # thus want to consider an empty string as a complete
147 # statement.
147 # statement.
148 return True
148 return True
149 elif ( len(self.input_buffer.split('\n'))>2
149 elif ( len(self.input_buffer.split('\n'))>2
150 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
150 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
151 return False
151 return False
152 else:
152 else:
153 self.capture_output()
153 self.capture_output()
154 try:
154 try:
155 # Add line returns here, to make sure that the statement is
155 # Add line returns here, to make sure that the statement is
156 # complete (except if '\' was used).
156 # complete (except if '\' was used).
157 # This should probably be done in a different place (like
157 # This should probably be done in a different place (like
158 # maybe 'prefilter_input' method? For now, this works.
158 # maybe 'prefilter_input' method? For now, this works.
159 clean_string = string.rstrip('\n')
159 clean_string = string.rstrip('\n')
160 if not clean_string.endswith('\\'): clean_string +='\n\n'
160 if not clean_string.endswith('\\'): clean_string +='\n\n'
161 is_complete = codeop.compile_command(clean_string,
161 is_complete = codeop.compile_command(clean_string,
162 "<string>", "exec")
162 "<string>", "exec")
163 self.release_output()
163 self.release_output()
164 except Exception, e:
164 except Exception as e:
165 # XXX: Hack: return True so that the
165 # XXX: Hack: return True so that the
166 # code gets executed and the error captured.
166 # code gets executed and the error captured.
167 is_complete = True
167 is_complete = True
168 return is_complete
168 return is_complete
169
169
170
170
171 def write(self, string, refresh=True):
171 def write(self, string, refresh=True):
172 """ Write some characters to the display.
172 """ Write some characters to the display.
173
173
174 Subclass should overide this method.
174 Subclass should overide this method.
175
175
176 The refresh keyword argument is used in frontends with an
176 The refresh keyword argument is used in frontends with an
177 event loop, to choose whether the write should trigget an UI
177 event loop, to choose whether the write should trigget an UI
178 refresh, and thus be syncrhonous, or not.
178 refresh, and thus be syncrhonous, or not.
179 """
179 """
180 print >>sys.__stderr__, string
180 print >>sys.__stderr__, string
181
181
182
182
183 def execute(self, python_string, raw_string=None):
183 def execute(self, python_string, raw_string=None):
184 """ Stores the raw_string in the history, and sends the
184 """ Stores the raw_string in the history, and sends the
185 python string to the interpreter.
185 python string to the interpreter.
186 """
186 """
187 if raw_string is None:
187 if raw_string is None:
188 raw_string = python_string
188 raw_string = python_string
189 # Create a false result, in case there is an exception
189 # Create a false result, in case there is an exception
190 self.last_result = dict(number=self.prompt_number)
190 self.last_result = dict(number=self.prompt_number)
191
191
192 try:
192 try:
193 try:
193 try:
194 self.history.input_cache[-1] = raw_string.rstrip()
194 self.history.input_cache[-1] = raw_string.rstrip()
195 result = self.shell.execute(python_string)
195 result = self.shell.execute(python_string)
196 self.last_result = result
196 self.last_result = result
197 self.render_result(result)
197 self.render_result(result)
198 except:
198 except:
199 self.show_traceback()
199 self.show_traceback()
200 finally:
200 finally:
201 self.after_execute()
201 self.after_execute()
202
202
203
203
204 #--------------------------------------------------------------------------
204 #--------------------------------------------------------------------------
205 # LineFrontEndBase interface
205 # LineFrontEndBase interface
206 #--------------------------------------------------------------------------
206 #--------------------------------------------------------------------------
207
207
208 def prefilter_input(self, string):
208 def prefilter_input(self, string):
209 """ Prefilter the input to turn it in valid python.
209 """ Prefilter the input to turn it in valid python.
210 """
210 """
211 string = string.replace('\r\n', '\n')
211 string = string.replace('\r\n', '\n')
212 string = string.replace('\t', 4*' ')
212 string = string.replace('\t', 4*' ')
213 # Clean the trailing whitespace
213 # Clean the trailing whitespace
214 string = '\n'.join(l.rstrip() for l in string.split('\n'))
214 string = '\n'.join(l.rstrip() for l in string.split('\n'))
215 return string
215 return string
216
216
217
217
218 def after_execute(self):
218 def after_execute(self):
219 """ All the operations required after an execution to put the
219 """ All the operations required after an execution to put the
220 terminal back in a shape where it is usable.
220 terminal back in a shape where it is usable.
221 """
221 """
222 self.prompt_number += 1
222 self.prompt_number += 1
223 self.new_prompt(self.input_prompt_template.substitute(
223 self.new_prompt(self.input_prompt_template.substitute(
224 number=(self.last_result['number'] + 1)))
224 number=(self.last_result['number'] + 1)))
225 # Start a new empty history entry
225 # Start a new empty history entry
226 self._add_history(None, '')
226 self._add_history(None, '')
227 self.history_cursor = len(self.history.input_cache) - 1
227 self.history_cursor = len(self.history.input_cache) - 1
228
228
229
229
230 def complete_current_input(self):
230 def complete_current_input(self):
231 """ Do code completion on current line.
231 """ Do code completion on current line.
232 """
232 """
233 if self.debug:
233 if self.debug:
234 print >>sys.__stdout__, "complete_current_input",
234 print >>sys.__stdout__, "complete_current_input",
235 line = self.input_buffer
235 line = self.input_buffer
236 new_line, completions = self.complete(line)
236 new_line, completions = self.complete(line)
237 if len(completions)>1:
237 if len(completions)>1:
238 self.write_completion(completions, new_line=new_line)
238 self.write_completion(completions, new_line=new_line)
239 elif not line == new_line:
239 elif not line == new_line:
240 self.input_buffer = new_line
240 self.input_buffer = new_line
241 if self.debug:
241 if self.debug:
242 print >>sys.__stdout__, 'line', line
242 print >>sys.__stdout__, 'line', line
243 print >>sys.__stdout__, 'new_line', new_line
243 print >>sys.__stdout__, 'new_line', new_line
244 print >>sys.__stdout__, completions
244 print >>sys.__stdout__, completions
245
245
246
246
247 def get_line_width(self):
247 def get_line_width(self):
248 """ Return the width of the line in characters.
248 """ Return the width of the line in characters.
249 """
249 """
250 return 80
250 return 80
251
251
252
252
253 def write_completion(self, possibilities, new_line=None):
253 def write_completion(self, possibilities, new_line=None):
254 """ Write the list of possible completions.
254 """ Write the list of possible completions.
255
255
256 new_line is the completed input line that should be displayed
256 new_line is the completed input line that should be displayed
257 after the completion are writen. If None, the input_buffer
257 after the completion are writen. If None, the input_buffer
258 before the completion is used.
258 before the completion is used.
259 """
259 """
260 if new_line is None:
260 if new_line is None:
261 new_line = self.input_buffer
261 new_line = self.input_buffer
262
262
263 self.write('\n')
263 self.write('\n')
264 max_len = len(max(possibilities, key=len)) + 1
264 max_len = len(max(possibilities, key=len)) + 1
265
265
266 # Now we check how much symbol we can put on a line...
266 # Now we check how much symbol we can put on a line...
267 chars_per_line = self.get_line_width()
267 chars_per_line = self.get_line_width()
268 symbols_per_line = max(1, chars_per_line/max_len)
268 symbols_per_line = max(1, chars_per_line/max_len)
269
269
270 pos = 1
270 pos = 1
271 completion_string = []
271 completion_string = []
272 for symbol in possibilities:
272 for symbol in possibilities:
273 if pos < symbols_per_line:
273 if pos < symbols_per_line:
274 completion_string.append(symbol.ljust(max_len))
274 completion_string.append(symbol.ljust(max_len))
275 pos += 1
275 pos += 1
276 else:
276 else:
277 completion_string.append(symbol.rstrip() + '\n')
277 completion_string.append(symbol.rstrip() + '\n')
278 pos = 1
278 pos = 1
279 self.write(''.join(completion_string))
279 self.write(''.join(completion_string))
280 self.new_prompt(self.input_prompt_template.substitute(
280 self.new_prompt(self.input_prompt_template.substitute(
281 number=self.last_result['number'] + 1))
281 number=self.last_result['number'] + 1))
282 self.input_buffer = new_line
282 self.input_buffer = new_line
283
283
284
284
285 def new_prompt(self, prompt):
285 def new_prompt(self, prompt):
286 """ Prints a prompt and starts a new editing buffer.
286 """ Prints a prompt and starts a new editing buffer.
287
287
288 Subclasses should use this method to make sure that the
288 Subclasses should use this method to make sure that the
289 terminal is put in a state favorable for a new line
289 terminal is put in a state favorable for a new line
290 input.
290 input.
291 """
291 """
292 self.input_buffer = ''
292 self.input_buffer = ''
293 self.write(prompt)
293 self.write(prompt)
294
294
295
295
296 def continuation_prompt(self):
296 def continuation_prompt(self):
297 """Returns the current continuation prompt.
297 """Returns the current continuation prompt.
298 """
298 """
299 return ("."*(len(self.last_prompt)-2) + ': ')
299 return ("."*(len(self.last_prompt)-2) + ': ')
300
300
301
301
302 def execute_command(self, command, hidden=False):
302 def execute_command(self, command, hidden=False):
303 """ Execute a command, not only in the model, but also in the
303 """ Execute a command, not only in the model, but also in the
304 view, if any.
304 view, if any.
305 """
305 """
306 return self.shell.execute(command)
306 return self.shell.execute(command)
307
307
308 #--------------------------------------------------------------------------
308 #--------------------------------------------------------------------------
309 # Private API
309 # Private API
310 #--------------------------------------------------------------------------
310 #--------------------------------------------------------------------------
311
311
312 def _on_enter(self, new_line_pos=0):
312 def _on_enter(self, new_line_pos=0):
313 """ Called when the return key is pressed in a line editing
313 """ Called when the return key is pressed in a line editing
314 buffer.
314 buffer.
315
315
316 Parameters
316 Parameters
317 ----------
317 ----------
318 new_line_pos : integer, optional
318 new_line_pos : integer, optional
319 Position of the new line to add, starting from the
319 Position of the new line to add, starting from the
320 end (0 adds a new line after the last line, -1 before
320 end (0 adds a new line after the last line, -1 before
321 the last line...)
321 the last line...)
322
322
323 Returns
323 Returns
324 -------
324 -------
325 True if execution is triggered
325 True if execution is triggered
326 """
326 """
327 current_buffer = self.input_buffer
327 current_buffer = self.input_buffer
328 # XXX: This string replace is ugly, but there should be no way it
328 # XXX: This string replace is ugly, but there should be no way it
329 # fails.
329 # fails.
330 prompt_less_buffer = re.sub('^' + self.continuation_prompt(),
330 prompt_less_buffer = re.sub('^' + self.continuation_prompt(),
331 '', current_buffer).replace('\n' + self.continuation_prompt(),
331 '', current_buffer).replace('\n' + self.continuation_prompt(),
332 '\n')
332 '\n')
333 cleaned_buffer = self.prefilter_input(prompt_less_buffer)
333 cleaned_buffer = self.prefilter_input(prompt_less_buffer)
334 if self.is_complete(cleaned_buffer):
334 if self.is_complete(cleaned_buffer):
335 self.execute(cleaned_buffer, raw_string=current_buffer)
335 self.execute(cleaned_buffer, raw_string=current_buffer)
336 return True
336 return True
337 else:
337 else:
338 # Start a new line.
338 # Start a new line.
339 new_line_pos = -new_line_pos
339 new_line_pos = -new_line_pos
340 lines = current_buffer.split('\n')[:-1]
340 lines = current_buffer.split('\n')[:-1]
341 prompt_less_lines = prompt_less_buffer.split('\n')
341 prompt_less_lines = prompt_less_buffer.split('\n')
342 # Create the new line, with the continuation prompt, and the
342 # Create the new line, with the continuation prompt, and the
343 # same amount of indent than the line above it.
343 # same amount of indent than the line above it.
344 new_line = self.continuation_prompt() + \
344 new_line = self.continuation_prompt() + \
345 self._get_indent_string('\n'.join(
345 self._get_indent_string('\n'.join(
346 prompt_less_lines[:new_line_pos-1]))
346 prompt_less_lines[:new_line_pos-1]))
347 if len(lines) == 1:
347 if len(lines) == 1:
348 # We are starting a first continuation line. Indent it.
348 # We are starting a first continuation line. Indent it.
349 new_line += '\t'
349 new_line += '\t'
350 elif current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'):
350 elif current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'):
351 # The last line ends with ":", autoindent the new line.
351 # The last line ends with ":", autoindent the new line.
352 new_line += '\t'
352 new_line += '\t'
353
353
354 if new_line_pos == 0:
354 if new_line_pos == 0:
355 lines.append(new_line)
355 lines.append(new_line)
356 else:
356 else:
357 lines.insert(new_line_pos, new_line)
357 lines.insert(new_line_pos, new_line)
358 self.input_buffer = '\n'.join(lines)
358 self.input_buffer = '\n'.join(lines)
359
359
360
360
361 def _get_indent_string(self, string):
361 def _get_indent_string(self, string):
362 """ Return the string of whitespace that prefixes a line. Used to
362 """ Return the string of whitespace that prefixes a line. Used to
363 add the right amount of indendation when creating a new line.
363 add the right amount of indendation when creating a new line.
364 """
364 """
365 string = string.replace('\t', ' '*4)
365 string = string.replace('\t', ' '*4)
366 string = string.split('\n')[-1]
366 string = string.split('\n')[-1]
367 indent_chars = len(string) - len(string.lstrip())
367 indent_chars = len(string) - len(string.lstrip())
368 indent_string = '\t'*(indent_chars // 4) + \
368 indent_string = '\t'*(indent_chars // 4) + \
369 ' '*(indent_chars % 4)
369 ' '*(indent_chars % 4)
370
370
371 return indent_string
371 return indent_string
372
372
373
373
@@ -1,118 +1,118 b''
1 """
1 """
2 Entry point for a simple application giving a graphical frontend to
2 Entry point for a simple application giving a graphical frontend to
3 ipython.
3 ipython.
4 """
4 """
5
5
6 try:
6 try:
7 import wx
7 import wx
8 except ImportError, e:
8 except ImportError as e:
9 e.args[0] = """%s
9 e.args[0] = """%s
10 ________________________________________________________________________________
10 ________________________________________________________________________________
11 You need wxPython to run this application.
11 You need wxPython to run this application.
12 """ % e.args[0]
12 """ % e.args[0]
13 raise e
13 raise e
14
14
15 from wx_frontend import WxController
15 from wx_frontend import WxController
16 import __builtin__
16 import __builtin__
17
17
18
18
19 class IPythonXController(WxController):
19 class IPythonXController(WxController):
20 """ Sub class of WxController that adds some application-specific
20 """ Sub class of WxController that adds some application-specific
21 bindings.
21 bindings.
22 """
22 """
23
23
24 debug = False
24 debug = False
25
25
26 def __init__(self, *args, **kwargs):
26 def __init__(self, *args, **kwargs):
27 WxController.__init__(self, *args, **kwargs)
27 WxController.__init__(self, *args, **kwargs)
28 self.ipython0.ask_exit = self.do_exit
28 self.ipython0.ask_exit = self.do_exit
29 # Scroll to top
29 # Scroll to top
30 maxrange = self.GetScrollRange(wx.VERTICAL)
30 maxrange = self.GetScrollRange(wx.VERTICAL)
31 self.ScrollLines(-maxrange)
31 self.ScrollLines(-maxrange)
32
32
33
33
34 def _on_key_down(self, event, skip=True):
34 def _on_key_down(self, event, skip=True):
35 # Intercept Ctrl-D to quit
35 # Intercept Ctrl-D to quit
36 if event.KeyCode == ord('D') and event.ControlDown() and \
36 if event.KeyCode == ord('D') and event.ControlDown() and \
37 self.input_buffer == '' and \
37 self.input_buffer == '' and \
38 self._input_state == 'readline':
38 self._input_state == 'readline':
39 wx.CallAfter(self.ask_exit)
39 wx.CallAfter(self.ask_exit)
40 else:
40 else:
41 WxController._on_key_down(self, event, skip=skip)
41 WxController._on_key_down(self, event, skip=skip)
42
42
43
43
44 def ask_exit(self):
44 def ask_exit(self):
45 """ Ask the user whether to exit.
45 """ Ask the user whether to exit.
46 """
46 """
47 self._input_state = 'subprocess'
47 self._input_state = 'subprocess'
48 self.write('\n', refresh=False)
48 self.write('\n', refresh=False)
49 self.capture_output()
49 self.capture_output()
50 self.ipython0.exit()
50 self.ipython0.exit()
51 self.release_output()
51 self.release_output()
52 if not self.ipython0.exit_now:
52 if not self.ipython0.exit_now:
53 wx.CallAfter(self.new_prompt,
53 wx.CallAfter(self.new_prompt,
54 self.input_prompt_template.substitute(
54 self.input_prompt_template.substitute(
55 number=self.last_result['number'] + 1))
55 number=self.last_result['number'] + 1))
56 else:
56 else:
57 wx.CallAfter(wx.GetApp().Exit)
57 wx.CallAfter(wx.GetApp().Exit)
58 self.write('Exiting ...', refresh=False)
58 self.write('Exiting ...', refresh=False)
59
59
60
60
61 def do_exit(self):
61 def do_exit(self):
62 """ Exits the interpreter, kills the windows.
62 """ Exits the interpreter, kills the windows.
63 """
63 """
64 WxController.do_exit(self)
64 WxController.do_exit(self)
65 self.release_output()
65 self.release_output()
66 wx.CallAfter(wx.Exit)
66 wx.CallAfter(wx.Exit)
67
67
68
68
69
69
70 class IPythonX(wx.Frame):
70 class IPythonX(wx.Frame):
71 """ Main frame of the IPythonX app.
71 """ Main frame of the IPythonX app.
72 """
72 """
73
73
74 def __init__(self, parent, id, title, debug=False):
74 def __init__(self, parent, id, title, debug=False):
75 wx.Frame.__init__(self, parent, id, title, size=(300,250))
75 wx.Frame.__init__(self, parent, id, title, size=(300,250))
76 self._sizer = wx.BoxSizer(wx.VERTICAL)
76 self._sizer = wx.BoxSizer(wx.VERTICAL)
77 self.shell = IPythonXController(self, debug=debug)
77 self.shell = IPythonXController(self, debug=debug)
78 self._sizer.Add(self.shell, 1, wx.EXPAND)
78 self._sizer.Add(self.shell, 1, wx.EXPAND)
79 self.SetSizer(self._sizer)
79 self.SetSizer(self._sizer)
80 self.SetAutoLayout(1)
80 self.SetAutoLayout(1)
81 self.Show(True)
81 self.Show(True)
82 wx.EVT_CLOSE(self, self.on_close)
82 wx.EVT_CLOSE(self, self.on_close)
83
83
84
84
85 def on_close(self, event):
85 def on_close(self, event):
86 """ Called on closing the windows.
86 """ Called on closing the windows.
87
87
88 Stops the event loop, to close all the child windows.
88 Stops the event loop, to close all the child windows.
89 """
89 """
90 wx.CallAfter(wx.Exit)
90 wx.CallAfter(wx.Exit)
91
91
92
92
93 def main():
93 def main():
94 from optparse import OptionParser
94 from optparse import OptionParser
95 usage = """usage: %prog [options]
95 usage = """usage: %prog [options]
96
96
97 Simple graphical frontend to IPython, using WxWidgets."""
97 Simple graphical frontend to IPython, using WxWidgets."""
98 parser = OptionParser(usage=usage)
98 parser = OptionParser(usage=usage)
99 parser.add_option("-d", "--debug",
99 parser.add_option("-d", "--debug",
100 action="store_true", dest="debug", default=False,
100 action="store_true", dest="debug", default=False,
101 help="Enable debug message for the wx frontend.")
101 help="Enable debug message for the wx frontend.")
102
102
103 options, args = parser.parse_args()
103 options, args = parser.parse_args()
104
104
105 # Clear the options, to avoid having the ipython0 instance complain
105 # Clear the options, to avoid having the ipython0 instance complain
106 import sys
106 import sys
107 sys.argv = sys.argv[:1]
107 sys.argv = sys.argv[:1]
108
108
109 app = wx.PySimpleApp()
109 app = wx.PySimpleApp()
110 frame = IPythonX(None, wx.ID_ANY, 'IPythonX', debug=options.debug)
110 frame = IPythonX(None, wx.ID_ANY, 'IPythonX', debug=options.debug)
111 frame.shell.SetFocus()
111 frame.shell.SetFocus()
112 frame.shell.app = app
112 frame.shell.app = app
113 frame.SetSize((680, 460))
113 frame.SetSize((680, 460))
114
114
115 app.MainLoop()
115 app.MainLoop()
116
116
117 if __name__ == '__main__':
117 if __name__ == '__main__':
118 main()
118 main()
@@ -1,64 +1,64 b''
1 """Tests for Octave magics extension."""
1 """Tests for Octave magics extension."""
2
2
3 import nose.tools as nt
3 import nose.tools as nt
4
4
5 try:
5 try:
6 import oct2py
6 import oct2py
7 import numpy as np
7 import numpy as np
8 import numpy.testing as npt
8 import numpy.testing as npt
9
9
10 from IPython.extensions import octavemagic
10 from IPython.extensions import octavemagic
11 except Exception, e:
11 except Exception as e:
12 __test__ = False
12 __test__ = False
13
13
14 global octave
14 global octave
15
15
16 def setup():
16 def setup():
17 ip = get_ipython()
17 ip = get_ipython()
18 global octave
18 global octave
19
19
20 octave = octavemagic.OctaveMagics(ip)
20 octave = octavemagic.OctaveMagics(ip)
21 ip.register_magics(octave)
21 ip.register_magics(octave)
22
22
23 ip.ex('import numpy as np')
23 ip.ex('import numpy as np')
24
24
25 def test_octave_inline():
25 def test_octave_inline():
26 ip = get_ipython()
26 ip = get_ipython()
27 result = ip.run_line_magic('octave', '[1, 2, 3] + 1;')
27 result = ip.run_line_magic('octave', '[1, 2, 3] + 1;')
28 npt.assert_array_equal(result, [[2, 3, 4]])
28 npt.assert_array_equal(result, [[2, 3, 4]])
29
29
30 def test_octave_roundtrip():
30 def test_octave_roundtrip():
31 ip = get_ipython()
31 ip = get_ipython()
32 ip.ex('x = np.arange(3); y = 4.5')
32 ip.ex('x = np.arange(3); y = 4.5')
33 ip.run_line_magic('octave_push', 'x y')
33 ip.run_line_magic('octave_push', 'x y')
34 ip.run_line_magic('octave', 'x = x + 1; y = y + 1;')
34 ip.run_line_magic('octave', 'x = x + 1; y = y + 1;')
35 ip.run_line_magic('octave_pull', 'x y')
35 ip.run_line_magic('octave_pull', 'x y')
36
36
37 npt.assert_array_equal(ip.user_ns['x'], [[1, 2, 3]])
37 npt.assert_array_equal(ip.user_ns['x'], [[1, 2, 3]])
38 nt.assert_equal(ip.user_ns['y'], 5.5)
38 nt.assert_equal(ip.user_ns['y'], 5.5)
39
39
40 def test_octave_cell_magic():
40 def test_octave_cell_magic():
41 ip = get_ipython()
41 ip = get_ipython()
42 ip.ex('x = 3; y = [1, 2]')
42 ip.ex('x = 3; y = [1, 2]')
43 ip.run_cell_magic('octave', '-f png -s 400,400 -i x,y -o z',
43 ip.run_cell_magic('octave', '-f png -s 400,400 -i x,y -o z',
44 'z = x + y;')
44 'z = x + y;')
45 npt.assert_array_equal(ip.user_ns['z'], [[4, 5]])
45 npt.assert_array_equal(ip.user_ns['z'], [[4, 5]])
46
46
47
47
48 def verify_publish_data(source, data):
48 def verify_publish_data(source, data):
49 if 'image/svg+xml' in data:
49 if 'image/svg+xml' in data:
50 svg = data['image/svg+xml']
50 svg = data['image/svg+xml']
51 assert 'height="500px"' in svg
51 assert 'height="500px"' in svg
52 assert 'width="400px"' in svg
52 assert 'width="400px"' in svg
53
53
54 test_octave_plot.svgs_generated += 1
54 test_octave_plot.svgs_generated += 1
55
55
56 def test_octave_plot():
56 def test_octave_plot():
57 octave._publish_display_data = verify_publish_data
57 octave._publish_display_data = verify_publish_data
58 test_octave_plot.svgs_generated = 0
58 test_octave_plot.svgs_generated = 0
59
59
60 ip = get_ipython()
60 ip = get_ipython()
61 ip.run_cell_magic('octave', '-f svg -s 400,500',
61 ip.run_cell_magic('octave', '-f svg -s 400,500',
62 'plot([1, 2, 3]); figure; plot([4, 5, 6]);')
62 'plot([1, 2, 3]); figure; plot([4, 5, 6]);')
63
63
64 nt.assert_equal(test_octave_plot.svgs_generated, 2)
64 nt.assert_equal(test_octave_plot.svgs_generated, 2)
@@ -1,1900 +1,1900 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, 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, 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, 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, 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, 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 def readlines (self, sizehint = -1): # File-like object.
943 def readlines (self, sizehint = -1): # File-like object.
944
944
945 """This reads until EOF using readline() and returns a list containing
945 """This reads until EOF using readline() and returns a list containing
946 the lines thus read. The optional "sizehint" argument is ignored. """
946 the lines thus read. The optional "sizehint" argument is ignored. """
947
947
948 lines = []
948 lines = []
949 while True:
949 while True:
950 line = self.readline()
950 line = self.readline()
951 if not line:
951 if not line:
952 break
952 break
953 lines.append(line)
953 lines.append(line)
954 return lines
954 return lines
955
955
956 def write(self, s): # File-like object.
956 def write(self, s): # File-like object.
957
957
958 """This is similar to send() except that there is no return value.
958 """This is similar to send() except that there is no return value.
959 """
959 """
960
960
961 self.send (s)
961 self.send (s)
962
962
963 def writelines (self, sequence): # File-like object.
963 def writelines (self, sequence): # File-like object.
964
964
965 """This calls write() for each element in the sequence. The sequence
965 """This calls write() for each element in the sequence. The sequence
966 can be any iterable object producing strings, typically a list of
966 can be any iterable object producing strings, typically a list of
967 strings. This does not add line separators There is no return value.
967 strings. This does not add line separators There is no return value.
968 """
968 """
969
969
970 for s in sequence:
970 for s in sequence:
971 self.write (s)
971 self.write (s)
972
972
973 def send(self, s):
973 def send(self, s):
974
974
975 """This sends a string to the child process. This returns the number of
975 """This sends a string to the child process. This returns the number of
976 bytes written. If a log file was set then the data is also written to
976 bytes written. If a log file was set then the data is also written to
977 the log. """
977 the log. """
978
978
979 time.sleep(self.delaybeforesend)
979 time.sleep(self.delaybeforesend)
980
980
981 s2 = self._cast_buffer_type(s)
981 s2 = self._cast_buffer_type(s)
982 if self.logfile is not None:
982 if self.logfile is not None:
983 self.logfile.write(s2)
983 self.logfile.write(s2)
984 self.logfile.flush()
984 self.logfile.flush()
985 if self.logfile_send is not None:
985 if self.logfile_send is not None:
986 self.logfile_send.write(s2)
986 self.logfile_send.write(s2)
987 self.logfile_send.flush()
987 self.logfile_send.flush()
988 c = os.write (self.child_fd, _cast_bytes(s, self.encoding))
988 c = os.write (self.child_fd, _cast_bytes(s, self.encoding))
989 return c
989 return c
990
990
991 def sendline(self, s=''):
991 def sendline(self, s=''):
992
992
993 """This is like send(), but it adds a line feed (os.linesep). This
993 """This is like send(), but it adds a line feed (os.linesep). This
994 returns the number of bytes written. """
994 returns the number of bytes written. """
995
995
996 n = self.send (s)
996 n = self.send (s)
997 n = n + self.send (os.linesep)
997 n = n + self.send (os.linesep)
998 return n
998 return n
999
999
1000 def sendcontrol(self, char):
1000 def sendcontrol(self, char):
1001
1001
1002 """This sends a control character to the child such as Ctrl-C or
1002 """This sends a control character to the child such as Ctrl-C or
1003 Ctrl-D. For example, to send a Ctrl-G (ASCII 7)::
1003 Ctrl-D. For example, to send a Ctrl-G (ASCII 7)::
1004
1004
1005 child.sendcontrol('g')
1005 child.sendcontrol('g')
1006
1006
1007 See also, sendintr() and sendeof().
1007 See also, sendintr() and sendeof().
1008 """
1008 """
1009
1009
1010 char = char.lower()
1010 char = char.lower()
1011 a = ord(char)
1011 a = ord(char)
1012 if a>=97 and a<=122:
1012 if a>=97 and a<=122:
1013 a = a - ord('a') + 1
1013 a = a - ord('a') + 1
1014 return self.send (chr(a))
1014 return self.send (chr(a))
1015 d = {'@':0, '`':0,
1015 d = {'@':0, '`':0,
1016 '[':27, '{':27,
1016 '[':27, '{':27,
1017 '\\':28, '|':28,
1017 '\\':28, '|':28,
1018 ']':29, '}': 29,
1018 ']':29, '}': 29,
1019 '^':30, '~':30,
1019 '^':30, '~':30,
1020 '_':31,
1020 '_':31,
1021 '?':127}
1021 '?':127}
1022 if char not in d:
1022 if char not in d:
1023 return 0
1023 return 0
1024 return self.send (chr(d[char]))
1024 return self.send (chr(d[char]))
1025
1025
1026 def sendeof(self):
1026 def sendeof(self):
1027
1027
1028 """This sends an EOF to the child. This sends a character which causes
1028 """This sends an EOF to the child. This sends a character which causes
1029 the pending parent output buffer to be sent to the waiting child
1029 the pending parent output buffer to be sent to the waiting child
1030 program without waiting for end-of-line. If it is the first character
1030 program without waiting for end-of-line. If it is the first character
1031 of the line, the read() in the user program returns 0, which signifies
1031 of the line, the read() in the user program returns 0, which signifies
1032 end-of-file. This means to work as expected a sendeof() has to be
1032 end-of-file. This means to work as expected a sendeof() has to be
1033 called at the beginning of a line. This method does not send a newline.
1033 called at the beginning of a line. This method does not send a newline.
1034 It is the responsibility of the caller to ensure the eof is sent at the
1034 It is the responsibility of the caller to ensure the eof is sent at the
1035 beginning of a line. """
1035 beginning of a line. """
1036
1036
1037 ### Hmmm... how do I send an EOF?
1037 ### Hmmm... how do I send an EOF?
1038 ###C if ((m = write(pty, *buf, p - *buf)) < 0)
1038 ###C if ((m = write(pty, *buf, p - *buf)) < 0)
1039 ###C return (errno == EWOULDBLOCK) ? n : -1;
1039 ###C return (errno == EWOULDBLOCK) ? n : -1;
1040 #fd = sys.stdin.fileno()
1040 #fd = sys.stdin.fileno()
1041 #old = termios.tcgetattr(fd) # remember current state
1041 #old = termios.tcgetattr(fd) # remember current state
1042 #attr = termios.tcgetattr(fd)
1042 #attr = termios.tcgetattr(fd)
1043 #attr[3] = attr[3] | termios.ICANON # ICANON must be set to recognize EOF
1043 #attr[3] = attr[3] | termios.ICANON # ICANON must be set to recognize EOF
1044 #try: # use try/finally to ensure state gets restored
1044 #try: # use try/finally to ensure state gets restored
1045 # termios.tcsetattr(fd, termios.TCSADRAIN, attr)
1045 # termios.tcsetattr(fd, termios.TCSADRAIN, attr)
1046 # if hasattr(termios, 'CEOF'):
1046 # if hasattr(termios, 'CEOF'):
1047 # os.write (self.child_fd, '%c' % termios.CEOF)
1047 # os.write (self.child_fd, '%c' % termios.CEOF)
1048 # else:
1048 # else:
1049 # # Silly platform does not define CEOF so assume CTRL-D
1049 # # Silly platform does not define CEOF so assume CTRL-D
1050 # os.write (self.child_fd, '%c' % 4)
1050 # os.write (self.child_fd, '%c' % 4)
1051 #finally: # restore state
1051 #finally: # restore state
1052 # termios.tcsetattr(fd, termios.TCSADRAIN, old)
1052 # termios.tcsetattr(fd, termios.TCSADRAIN, old)
1053 if hasattr(termios, 'VEOF'):
1053 if hasattr(termios, 'VEOF'):
1054 char = termios.tcgetattr(self.child_fd)[6][termios.VEOF]
1054 char = termios.tcgetattr(self.child_fd)[6][termios.VEOF]
1055 else:
1055 else:
1056 # platform does not define VEOF so assume CTRL-D
1056 # platform does not define VEOF so assume CTRL-D
1057 char = chr(4)
1057 char = chr(4)
1058 self.send(char)
1058 self.send(char)
1059
1059
1060 def sendintr(self):
1060 def sendintr(self):
1061
1061
1062 """This sends a SIGINT to the child. It does not require
1062 """This sends a SIGINT to the child. It does not require
1063 the SIGINT to be the first character on a line. """
1063 the SIGINT to be the first character on a line. """
1064
1064
1065 if hasattr(termios, 'VINTR'):
1065 if hasattr(termios, 'VINTR'):
1066 char = termios.tcgetattr(self.child_fd)[6][termios.VINTR]
1066 char = termios.tcgetattr(self.child_fd)[6][termios.VINTR]
1067 else:
1067 else:
1068 # platform does not define VINTR so assume CTRL-C
1068 # platform does not define VINTR so assume CTRL-C
1069 char = chr(3)
1069 char = chr(3)
1070 self.send (char)
1070 self.send (char)
1071
1071
1072 def eof (self):
1072 def eof (self):
1073
1073
1074 """This returns True if the EOF exception was ever raised.
1074 """This returns True if the EOF exception was ever raised.
1075 """
1075 """
1076
1076
1077 return self.flag_eof
1077 return self.flag_eof
1078
1078
1079 def terminate(self, force=False):
1079 def terminate(self, force=False):
1080
1080
1081 """This forces a child process to terminate. It starts nicely with
1081 """This forces a child process to terminate. It starts nicely with
1082 SIGHUP and SIGINT. If "force" is True then moves onto SIGKILL. This
1082 SIGHUP and SIGINT. If "force" is True then moves onto SIGKILL. This
1083 returns True if the child was terminated. This returns False if the
1083 returns True if the child was terminated. This returns False if the
1084 child could not be terminated. """
1084 child could not be terminated. """
1085
1085
1086 if not self.isalive():
1086 if not self.isalive():
1087 return True
1087 return True
1088 try:
1088 try:
1089 self.kill(signal.SIGHUP)
1089 self.kill(signal.SIGHUP)
1090 time.sleep(self.delayafterterminate)
1090 time.sleep(self.delayafterterminate)
1091 if not self.isalive():
1091 if not self.isalive():
1092 return True
1092 return True
1093 self.kill(signal.SIGCONT)
1093 self.kill(signal.SIGCONT)
1094 time.sleep(self.delayafterterminate)
1094 time.sleep(self.delayafterterminate)
1095 if not self.isalive():
1095 if not self.isalive():
1096 return True
1096 return True
1097 self.kill(signal.SIGINT)
1097 self.kill(signal.SIGINT)
1098 time.sleep(self.delayafterterminate)
1098 time.sleep(self.delayafterterminate)
1099 if not self.isalive():
1099 if not self.isalive():
1100 return True
1100 return True
1101 if force:
1101 if force:
1102 self.kill(signal.SIGKILL)
1102 self.kill(signal.SIGKILL)
1103 time.sleep(self.delayafterterminate)
1103 time.sleep(self.delayafterterminate)
1104 if not self.isalive():
1104 if not self.isalive():
1105 return True
1105 return True
1106 else:
1106 else:
1107 return False
1107 return False
1108 return False
1108 return False
1109 except OSError, e:
1109 except OSError as e:
1110 # I think there are kernel timing issues that sometimes cause
1110 # I think there are kernel timing issues that sometimes cause
1111 # this to happen. I think isalive() reports True, but the
1111 # this to happen. I think isalive() reports True, but the
1112 # process is dead to the kernel.
1112 # process is dead to the kernel.
1113 # Make one last attempt to see if the kernel is up to date.
1113 # Make one last attempt to see if the kernel is up to date.
1114 time.sleep(self.delayafterterminate)
1114 time.sleep(self.delayafterterminate)
1115 if not self.isalive():
1115 if not self.isalive():
1116 return True
1116 return True
1117 else:
1117 else:
1118 return False
1118 return False
1119
1119
1120 def wait(self):
1120 def wait(self):
1121
1121
1122 """This waits until the child exits. This is a blocking call. This will
1122 """This waits until the child exits. This is a blocking call. This will
1123 not read any data from the child, so this will block forever if the
1123 not read any data from the child, so this will block forever if the
1124 child has unread output and has terminated. In other words, the child
1124 child has unread output and has terminated. In other words, the child
1125 may have printed output then called exit(); but, technically, the child
1125 may have printed output then called exit(); but, technically, the child
1126 is still alive until its output is read. """
1126 is still alive until its output is read. """
1127
1127
1128 if self.isalive():
1128 if self.isalive():
1129 pid, status = os.waitpid(self.pid, 0)
1129 pid, status = os.waitpid(self.pid, 0)
1130 else:
1130 else:
1131 raise ExceptionPexpect ('Cannot wait for dead child process.')
1131 raise ExceptionPexpect ('Cannot wait for dead child process.')
1132 self.exitstatus = os.WEXITSTATUS(status)
1132 self.exitstatus = os.WEXITSTATUS(status)
1133 if os.WIFEXITED (status):
1133 if os.WIFEXITED (status):
1134 self.status = status
1134 self.status = status
1135 self.exitstatus = os.WEXITSTATUS(status)
1135 self.exitstatus = os.WEXITSTATUS(status)
1136 self.signalstatus = None
1136 self.signalstatus = None
1137 self.terminated = True
1137 self.terminated = True
1138 elif os.WIFSIGNALED (status):
1138 elif os.WIFSIGNALED (status):
1139 self.status = status
1139 self.status = status
1140 self.exitstatus = None
1140 self.exitstatus = None
1141 self.signalstatus = os.WTERMSIG(status)
1141 self.signalstatus = os.WTERMSIG(status)
1142 self.terminated = True
1142 self.terminated = True
1143 elif os.WIFSTOPPED (status):
1143 elif os.WIFSTOPPED (status):
1144 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?')
1144 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?')
1145 return self.exitstatus
1145 return self.exitstatus
1146
1146
1147 def isalive(self):
1147 def isalive(self):
1148
1148
1149 """This tests if the child process is running or not. This is
1149 """This tests if the child process is running or not. This is
1150 non-blocking. If the child was terminated then this will read the
1150 non-blocking. If the child was terminated then this will read the
1151 exitstatus or signalstatus of the child. This returns True if the child
1151 exitstatus or signalstatus of the child. This returns True if the child
1152 process appears to be running or False if not. It can take literally
1152 process appears to be running or False if not. It can take literally
1153 SECONDS for Solaris to return the right status. """
1153 SECONDS for Solaris to return the right status. """
1154
1154
1155 if self.terminated:
1155 if self.terminated:
1156 return False
1156 return False
1157
1157
1158 if self.flag_eof:
1158 if self.flag_eof:
1159 # This is for Linux, which requires the blocking form of waitpid to get
1159 # This is for Linux, which requires the blocking form of waitpid to get
1160 # status of a defunct process. This is super-lame. The flag_eof would have
1160 # status of a defunct process. This is super-lame. The flag_eof would have
1161 # been set in read_nonblocking(), so this should be safe.
1161 # been set in read_nonblocking(), so this should be safe.
1162 waitpid_options = 0
1162 waitpid_options = 0
1163 else:
1163 else:
1164 waitpid_options = os.WNOHANG
1164 waitpid_options = os.WNOHANG
1165
1165
1166 try:
1166 try:
1167 pid, status = os.waitpid(self.pid, waitpid_options)
1167 pid, status = os.waitpid(self.pid, waitpid_options)
1168 except OSError as e: # No child processes
1168 except OSError as e: # No child processes
1169 if e.errno == errno.ECHILD:
1169 if e.errno == errno.ECHILD:
1170 raise ExceptionPexpect ('isalive() encountered condition where "terminated" is 0, but there was no child process. Did someone else call waitpid() on our process?')
1170 raise ExceptionPexpect ('isalive() encountered condition where "terminated" is 0, but there was no child process. Did someone else call waitpid() on our process?')
1171 else:
1171 else:
1172 raise e
1172 raise e
1173
1173
1174 # I have to do this twice for Solaris. I can't even believe that I figured this out...
1174 # I have to do this twice for Solaris. I can't even believe that I figured this out...
1175 # If waitpid() returns 0 it means that no child process wishes to
1175 # If waitpid() returns 0 it means that no child process wishes to
1176 # report, and the value of status is undefined.
1176 # report, and the value of status is undefined.
1177 if pid == 0:
1177 if pid == 0:
1178 try:
1178 try:
1179 pid, status = os.waitpid(self.pid, waitpid_options) ### os.WNOHANG) # Solaris!
1179 pid, status = os.waitpid(self.pid, waitpid_options) ### os.WNOHANG) # Solaris!
1180 except OSError, e: # This should never happen...
1180 except OSError as e: # This should never happen...
1181 if e[0] == errno.ECHILD:
1181 if e[0] == errno.ECHILD:
1182 raise ExceptionPexpect ('isalive() encountered condition that should never happen. There was no child process. Did someone else call waitpid() on our process?')
1182 raise ExceptionPexpect ('isalive() encountered condition that should never happen. There was no child process. Did someone else call waitpid() on our process?')
1183 else:
1183 else:
1184 raise e
1184 raise e
1185
1185
1186 # If pid is still 0 after two calls to waitpid() then
1186 # If pid is still 0 after two calls to waitpid() then
1187 # the process really is alive. This seems to work on all platforms, except
1187 # the process really is alive. This seems to work on all platforms, except
1188 # for Irix which seems to require a blocking call on waitpid or select, so I let read_nonblocking
1188 # for Irix which seems to require a blocking call on waitpid or select, so I let read_nonblocking
1189 # take care of this situation (unfortunately, this requires waiting through the timeout).
1189 # take care of this situation (unfortunately, this requires waiting through the timeout).
1190 if pid == 0:
1190 if pid == 0:
1191 return True
1191 return True
1192
1192
1193 if pid == 0:
1193 if pid == 0:
1194 return True
1194 return True
1195
1195
1196 if os.WIFEXITED (status):
1196 if os.WIFEXITED (status):
1197 self.status = status
1197 self.status = status
1198 self.exitstatus = os.WEXITSTATUS(status)
1198 self.exitstatus = os.WEXITSTATUS(status)
1199 self.signalstatus = None
1199 self.signalstatus = None
1200 self.terminated = True
1200 self.terminated = True
1201 elif os.WIFSIGNALED (status):
1201 elif os.WIFSIGNALED (status):
1202 self.status = status
1202 self.status = status
1203 self.exitstatus = None
1203 self.exitstatus = None
1204 self.signalstatus = os.WTERMSIG(status)
1204 self.signalstatus = os.WTERMSIG(status)
1205 self.terminated = True
1205 self.terminated = True
1206 elif os.WIFSTOPPED (status):
1206 elif os.WIFSTOPPED (status):
1207 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?')
1207 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?')
1208 return False
1208 return False
1209
1209
1210 def kill(self, sig):
1210 def kill(self, sig):
1211
1211
1212 """This sends the given signal to the child application. In keeping
1212 """This sends the given signal to the child application. In keeping
1213 with UNIX tradition it has a misleading name. It does not necessarily
1213 with UNIX tradition it has a misleading name. It does not necessarily
1214 kill the child unless you send the right signal. """
1214 kill the child unless you send the right signal. """
1215
1215
1216 # Same as os.kill, but the pid is given for you.
1216 # Same as os.kill, but the pid is given for you.
1217 if self.isalive():
1217 if self.isalive():
1218 os.kill(self.pid, sig)
1218 os.kill(self.pid, sig)
1219
1219
1220 def compile_pattern_list(self, patterns):
1220 def compile_pattern_list(self, patterns):
1221
1221
1222 """This compiles a pattern-string or a list of pattern-strings.
1222 """This compiles a pattern-string or a list of pattern-strings.
1223 Patterns must be a StringType, EOF, TIMEOUT, SRE_Pattern, or a list of
1223 Patterns must be a StringType, EOF, TIMEOUT, SRE_Pattern, or a list of
1224 those. Patterns may also be None which results in an empty list (you
1224 those. Patterns may also be None which results in an empty list (you
1225 might do this if waiting for an EOF or TIMEOUT condition without
1225 might do this if waiting for an EOF or TIMEOUT condition without
1226 expecting any pattern).
1226 expecting any pattern).
1227
1227
1228 This is used by expect() when calling expect_list(). Thus expect() is
1228 This is used by expect() when calling expect_list(). Thus expect() is
1229 nothing more than::
1229 nothing more than::
1230
1230
1231 cpl = self.compile_pattern_list(pl)
1231 cpl = self.compile_pattern_list(pl)
1232 return self.expect_list(cpl, timeout)
1232 return self.expect_list(cpl, timeout)
1233
1233
1234 If you are using expect() within a loop it may be more
1234 If you are using expect() within a loop it may be more
1235 efficient to compile the patterns first and then call expect_list().
1235 efficient to compile the patterns first and then call expect_list().
1236 This avoid calls in a loop to compile_pattern_list()::
1236 This avoid calls in a loop to compile_pattern_list()::
1237
1237
1238 cpl = self.compile_pattern_list(my_pattern)
1238 cpl = self.compile_pattern_list(my_pattern)
1239 while some_condition:
1239 while some_condition:
1240 ...
1240 ...
1241 i = self.expect_list(clp, timeout)
1241 i = self.expect_list(clp, timeout)
1242 ...
1242 ...
1243 """
1243 """
1244
1244
1245 if patterns is None:
1245 if patterns is None:
1246 return []
1246 return []
1247 if not isinstance(patterns, list):
1247 if not isinstance(patterns, list):
1248 patterns = [patterns]
1248 patterns = [patterns]
1249
1249
1250 compile_flags = re.DOTALL # Allow dot to match \n
1250 compile_flags = re.DOTALL # Allow dot to match \n
1251 if self.ignorecase:
1251 if self.ignorecase:
1252 compile_flags = compile_flags | re.IGNORECASE
1252 compile_flags = compile_flags | re.IGNORECASE
1253 compiled_pattern_list = []
1253 compiled_pattern_list = []
1254 for p in patterns:
1254 for p in patterns:
1255 if isinstance(p, (bytes, unicode)):
1255 if isinstance(p, (bytes, unicode)):
1256 p = self._cast_buffer_type(p)
1256 p = self._cast_buffer_type(p)
1257 compiled_pattern_list.append(re.compile(p, compile_flags))
1257 compiled_pattern_list.append(re.compile(p, compile_flags))
1258 elif p is EOF:
1258 elif p is EOF:
1259 compiled_pattern_list.append(EOF)
1259 compiled_pattern_list.append(EOF)
1260 elif p is TIMEOUT:
1260 elif p is TIMEOUT:
1261 compiled_pattern_list.append(TIMEOUT)
1261 compiled_pattern_list.append(TIMEOUT)
1262 elif type(p) is re_type:
1262 elif type(p) is re_type:
1263 p = self._prepare_regex_pattern(p)
1263 p = self._prepare_regex_pattern(p)
1264 compiled_pattern_list.append(p)
1264 compiled_pattern_list.append(p)
1265 else:
1265 else:
1266 raise TypeError ('Argument must be one of StringTypes, EOF, TIMEOUT, SRE_Pattern, or a list of those type. %s' % str(type(p)))
1266 raise TypeError ('Argument must be one of StringTypes, EOF, TIMEOUT, SRE_Pattern, or a list of those type. %s' % str(type(p)))
1267
1267
1268 return compiled_pattern_list
1268 return compiled_pattern_list
1269
1269
1270 def _prepare_regex_pattern(self, p):
1270 def _prepare_regex_pattern(self, p):
1271 "Recompile unicode regexes as bytes regexes. Overridden in subclass."
1271 "Recompile unicode regexes as bytes regexes. Overridden in subclass."
1272 if isinstance(p.pattern, unicode):
1272 if isinstance(p.pattern, unicode):
1273 p = re.compile(p.pattern.encode('utf-8'), p.flags &~ re.UNICODE)
1273 p = re.compile(p.pattern.encode('utf-8'), p.flags &~ re.UNICODE)
1274 return p
1274 return p
1275
1275
1276 def expect(self, pattern, timeout = -1, searchwindowsize=-1):
1276 def expect(self, pattern, timeout = -1, searchwindowsize=-1):
1277
1277
1278 """This seeks through the stream until a pattern is matched. The
1278 """This seeks through the stream until a pattern is matched. The
1279 pattern is overloaded and may take several types. The pattern can be a
1279 pattern is overloaded and may take several types. The pattern can be a
1280 StringType, EOF, a compiled re, or a list of any of those types.
1280 StringType, EOF, a compiled re, or a list of any of those types.
1281 Strings will be compiled to re types. This returns the index into the
1281 Strings will be compiled to re types. This returns the index into the
1282 pattern list. If the pattern was not a list this returns index 0 on a
1282 pattern list. If the pattern was not a list this returns index 0 on a
1283 successful match. This may raise exceptions for EOF or TIMEOUT. To
1283 successful match. This may raise exceptions for EOF or TIMEOUT. To
1284 avoid the EOF or TIMEOUT exceptions add EOF or TIMEOUT to the pattern
1284 avoid the EOF or TIMEOUT exceptions add EOF or TIMEOUT to the pattern
1285 list. That will cause expect to match an EOF or TIMEOUT condition
1285 list. That will cause expect to match an EOF or TIMEOUT condition
1286 instead of raising an exception.
1286 instead of raising an exception.
1287
1287
1288 If you pass a list of patterns and more than one matches, the first match
1288 If you pass a list of patterns and more than one matches, the first match
1289 in the stream is chosen. If more than one pattern matches at that point,
1289 in the stream is chosen. If more than one pattern matches at that point,
1290 the leftmost in the pattern list is chosen. For example::
1290 the leftmost in the pattern list is chosen. For example::
1291
1291
1292 # the input is 'foobar'
1292 # the input is 'foobar'
1293 index = p.expect (['bar', 'foo', 'foobar'])
1293 index = p.expect (['bar', 'foo', 'foobar'])
1294 # returns 1 ('foo') even though 'foobar' is a "better" match
1294 # returns 1 ('foo') even though 'foobar' is a "better" match
1295
1295
1296 Please note, however, that buffering can affect this behavior, since
1296 Please note, however, that buffering can affect this behavior, since
1297 input arrives in unpredictable chunks. For example::
1297 input arrives in unpredictable chunks. For example::
1298
1298
1299 # the input is 'foobar'
1299 # the input is 'foobar'
1300 index = p.expect (['foobar', 'foo'])
1300 index = p.expect (['foobar', 'foo'])
1301 # returns 0 ('foobar') if all input is available at once,
1301 # returns 0 ('foobar') if all input is available at once,
1302 # but returs 1 ('foo') if parts of the final 'bar' arrive late
1302 # but returs 1 ('foo') if parts of the final 'bar' arrive late
1303
1303
1304 After a match is found the instance attributes 'before', 'after' and
1304 After a match is found the instance attributes 'before', 'after' and
1305 'match' will be set. You can see all the data read before the match in
1305 'match' will be set. You can see all the data read before the match in
1306 'before'. You can see the data that was matched in 'after'. The
1306 'before'. You can see the data that was matched in 'after'. The
1307 re.MatchObject used in the re match will be in 'match'. If an error
1307 re.MatchObject used in the re match will be in 'match'. If an error
1308 occurred then 'before' will be set to all the data read so far and
1308 occurred then 'before' will be set to all the data read so far and
1309 'after' and 'match' will be None.
1309 'after' and 'match' will be None.
1310
1310
1311 If timeout is -1 then timeout will be set to the self.timeout value.
1311 If timeout is -1 then timeout will be set to the self.timeout value.
1312
1312
1313 A list entry may be EOF or TIMEOUT instead of a string. This will
1313 A list entry may be EOF or TIMEOUT instead of a string. This will
1314 catch these exceptions and return the index of the list entry instead
1314 catch these exceptions and return the index of the list entry instead
1315 of raising the exception. The attribute 'after' will be set to the
1315 of raising the exception. The attribute 'after' will be set to the
1316 exception type. The attribute 'match' will be None. This allows you to
1316 exception type. The attribute 'match' will be None. This allows you to
1317 write code like this::
1317 write code like this::
1318
1318
1319 index = p.expect (['good', 'bad', pexpect.EOF, pexpect.TIMEOUT])
1319 index = p.expect (['good', 'bad', pexpect.EOF, pexpect.TIMEOUT])
1320 if index == 0:
1320 if index == 0:
1321 do_something()
1321 do_something()
1322 elif index == 1:
1322 elif index == 1:
1323 do_something_else()
1323 do_something_else()
1324 elif index == 2:
1324 elif index == 2:
1325 do_some_other_thing()
1325 do_some_other_thing()
1326 elif index == 3:
1326 elif index == 3:
1327 do_something_completely_different()
1327 do_something_completely_different()
1328
1328
1329 instead of code like this::
1329 instead of code like this::
1330
1330
1331 try:
1331 try:
1332 index = p.expect (['good', 'bad'])
1332 index = p.expect (['good', 'bad'])
1333 if index == 0:
1333 if index == 0:
1334 do_something()
1334 do_something()
1335 elif index == 1:
1335 elif index == 1:
1336 do_something_else()
1336 do_something_else()
1337 except EOF:
1337 except EOF:
1338 do_some_other_thing()
1338 do_some_other_thing()
1339 except TIMEOUT:
1339 except TIMEOUT:
1340 do_something_completely_different()
1340 do_something_completely_different()
1341
1341
1342 These two forms are equivalent. It all depends on what you want. You
1342 These two forms are equivalent. It all depends on what you want. You
1343 can also just expect the EOF if you are waiting for all output of a
1343 can also just expect the EOF if you are waiting for all output of a
1344 child to finish. For example::
1344 child to finish. For example::
1345
1345
1346 p = pexpect.spawn('/bin/ls')
1346 p = pexpect.spawn('/bin/ls')
1347 p.expect (pexpect.EOF)
1347 p.expect (pexpect.EOF)
1348 print p.before
1348 print p.before
1349
1349
1350 If you are trying to optimize for speed then see expect_list().
1350 If you are trying to optimize for speed then see expect_list().
1351 """
1351 """
1352
1352
1353 compiled_pattern_list = self.compile_pattern_list(pattern)
1353 compiled_pattern_list = self.compile_pattern_list(pattern)
1354 return self.expect_list(compiled_pattern_list, timeout, searchwindowsize)
1354 return self.expect_list(compiled_pattern_list, timeout, searchwindowsize)
1355
1355
1356 def expect_list(self, pattern_list, timeout = -1, searchwindowsize = -1):
1356 def expect_list(self, pattern_list, timeout = -1, searchwindowsize = -1):
1357
1357
1358 """This takes a list of compiled regular expressions and returns the
1358 """This takes a list of compiled regular expressions and returns the
1359 index into the pattern_list that matched the child output. The list may
1359 index into the pattern_list that matched the child output. The list may
1360 also contain EOF or TIMEOUT (which are not compiled regular
1360 also contain EOF or TIMEOUT (which are not compiled regular
1361 expressions). This method is similar to the expect() method except that
1361 expressions). This method is similar to the expect() method except that
1362 expect_list() does not recompile the pattern list on every call. This
1362 expect_list() does not recompile the pattern list on every call. This
1363 may help if you are trying to optimize for speed, otherwise just use
1363 may help if you are trying to optimize for speed, otherwise just use
1364 the expect() method. This is called by expect(). If timeout==-1 then
1364 the expect() method. This is called by expect(). If timeout==-1 then
1365 the self.timeout value is used. If searchwindowsize==-1 then the
1365 the self.timeout value is used. If searchwindowsize==-1 then the
1366 self.searchwindowsize value is used. """
1366 self.searchwindowsize value is used. """
1367
1367
1368 return self.expect_loop(searcher_re(pattern_list), timeout, searchwindowsize)
1368 return self.expect_loop(searcher_re(pattern_list), timeout, searchwindowsize)
1369
1369
1370 def expect_exact(self, pattern_list, timeout = -1, searchwindowsize = -1):
1370 def expect_exact(self, pattern_list, timeout = -1, searchwindowsize = -1):
1371
1371
1372 """This is similar to expect(), but uses plain string matching instead
1372 """This is similar to expect(), but uses plain string matching instead
1373 of compiled regular expressions in 'pattern_list'. The 'pattern_list'
1373 of compiled regular expressions in 'pattern_list'. The 'pattern_list'
1374 may be a string; a list or other sequence of strings; or TIMEOUT and
1374 may be a string; a list or other sequence of strings; or TIMEOUT and
1375 EOF.
1375 EOF.
1376
1376
1377 This call might be faster than expect() for two reasons: string
1377 This call might be faster than expect() for two reasons: string
1378 searching is faster than RE matching and it is possible to limit the
1378 searching is faster than RE matching and it is possible to limit the
1379 search to just the end of the input buffer.
1379 search to just the end of the input buffer.
1380
1380
1381 This method is also useful when you don't want to have to worry about
1381 This method is also useful when you don't want to have to worry about
1382 escaping regular expression characters that you want to match."""
1382 escaping regular expression characters that you want to match."""
1383
1383
1384 if isinstance(pattern_list, (bytes, unicode)) or pattern_list in (TIMEOUT, EOF):
1384 if isinstance(pattern_list, (bytes, unicode)) or pattern_list in (TIMEOUT, EOF):
1385 pattern_list = [pattern_list]
1385 pattern_list = [pattern_list]
1386 return self.expect_loop(searcher_string(pattern_list), timeout, searchwindowsize)
1386 return self.expect_loop(searcher_string(pattern_list), timeout, searchwindowsize)
1387
1387
1388 def expect_loop(self, searcher, timeout = -1, searchwindowsize = -1):
1388 def expect_loop(self, searcher, timeout = -1, searchwindowsize = -1):
1389
1389
1390 """This is the common loop used inside expect. The 'searcher' should be
1390 """This is the common loop used inside expect. The 'searcher' should be
1391 an instance of searcher_re or searcher_string, which describes how and what
1391 an instance of searcher_re or searcher_string, which describes how and what
1392 to search for in the input.
1392 to search for in the input.
1393
1393
1394 See expect() for other arguments, return value and exceptions. """
1394 See expect() for other arguments, return value and exceptions. """
1395
1395
1396 self.searcher = searcher
1396 self.searcher = searcher
1397
1397
1398 if timeout == -1:
1398 if timeout == -1:
1399 timeout = self.timeout
1399 timeout = self.timeout
1400 if timeout is not None:
1400 if timeout is not None:
1401 end_time = time.time() + timeout
1401 end_time = time.time() + timeout
1402 if searchwindowsize == -1:
1402 if searchwindowsize == -1:
1403 searchwindowsize = self.searchwindowsize
1403 searchwindowsize = self.searchwindowsize
1404
1404
1405 try:
1405 try:
1406 incoming = self.buffer
1406 incoming = self.buffer
1407 freshlen = len(incoming)
1407 freshlen = len(incoming)
1408 while True: # Keep reading until exception or return.
1408 while True: # Keep reading until exception or return.
1409 index = searcher.search(incoming, freshlen, searchwindowsize)
1409 index = searcher.search(incoming, freshlen, searchwindowsize)
1410 if index >= 0:
1410 if index >= 0:
1411 self.buffer = incoming[searcher.end : ]
1411 self.buffer = incoming[searcher.end : ]
1412 self.before = incoming[ : searcher.start]
1412 self.before = incoming[ : searcher.start]
1413 self.after = incoming[searcher.start : searcher.end]
1413 self.after = incoming[searcher.start : searcher.end]
1414 self.match = searcher.match
1414 self.match = searcher.match
1415 self.match_index = index
1415 self.match_index = index
1416 return self.match_index
1416 return self.match_index
1417 # No match at this point
1417 # No match at this point
1418 if timeout is not None and timeout < 0:
1418 if timeout is not None and timeout < 0:
1419 raise TIMEOUT ('Timeout exceeded in expect_any().')
1419 raise TIMEOUT ('Timeout exceeded in expect_any().')
1420 # Still have time left, so read more data
1420 # Still have time left, so read more data
1421 c = self.read_nonblocking (self.maxread, timeout)
1421 c = self.read_nonblocking (self.maxread, timeout)
1422 freshlen = len(c)
1422 freshlen = len(c)
1423 time.sleep (0.0001)
1423 time.sleep (0.0001)
1424 incoming = incoming + c
1424 incoming = incoming + c
1425 if timeout is not None:
1425 if timeout is not None:
1426 timeout = end_time - time.time()
1426 timeout = end_time - time.time()
1427 except EOF, e:
1427 except EOF as e:
1428 self.buffer = self._empty_buffer
1428 self.buffer = self._empty_buffer
1429 self.before = incoming
1429 self.before = incoming
1430 self.after = EOF
1430 self.after = EOF
1431 index = searcher.eof_index
1431 index = searcher.eof_index
1432 if index >= 0:
1432 if index >= 0:
1433 self.match = EOF
1433 self.match = EOF
1434 self.match_index = index
1434 self.match_index = index
1435 return self.match_index
1435 return self.match_index
1436 else:
1436 else:
1437 self.match = None
1437 self.match = None
1438 self.match_index = None
1438 self.match_index = None
1439 raise EOF (str(e) + '\n' + str(self))
1439 raise EOF (str(e) + '\n' + str(self))
1440 except TIMEOUT, e:
1440 except TIMEOUT as e:
1441 self.buffer = incoming
1441 self.buffer = incoming
1442 self.before = incoming
1442 self.before = incoming
1443 self.after = TIMEOUT
1443 self.after = TIMEOUT
1444 index = searcher.timeout_index
1444 index = searcher.timeout_index
1445 if index >= 0:
1445 if index >= 0:
1446 self.match = TIMEOUT
1446 self.match = TIMEOUT
1447 self.match_index = index
1447 self.match_index = index
1448 return self.match_index
1448 return self.match_index
1449 else:
1449 else:
1450 self.match = None
1450 self.match = None
1451 self.match_index = None
1451 self.match_index = None
1452 raise TIMEOUT (str(e) + '\n' + str(self))
1452 raise TIMEOUT (str(e) + '\n' + str(self))
1453 except:
1453 except:
1454 self.before = incoming
1454 self.before = incoming
1455 self.after = None
1455 self.after = None
1456 self.match = None
1456 self.match = None
1457 self.match_index = None
1457 self.match_index = None
1458 raise
1458 raise
1459
1459
1460 def getwinsize(self):
1460 def getwinsize(self):
1461
1461
1462 """This returns the terminal window size of the child tty. The return
1462 """This returns the terminal window size of the child tty. The return
1463 value is a tuple of (rows, cols). """
1463 value is a tuple of (rows, cols). """
1464
1464
1465 TIOCGWINSZ = getattr(termios, 'TIOCGWINSZ', 1074295912L)
1465 TIOCGWINSZ = getattr(termios, 'TIOCGWINSZ', 1074295912L)
1466 s = struct.pack('HHHH', 0, 0, 0, 0)
1466 s = struct.pack('HHHH', 0, 0, 0, 0)
1467 x = fcntl.ioctl(self.fileno(), TIOCGWINSZ, s)
1467 x = fcntl.ioctl(self.fileno(), TIOCGWINSZ, s)
1468 return struct.unpack('HHHH', x)[0:2]
1468 return struct.unpack('HHHH', x)[0:2]
1469
1469
1470 def setwinsize(self, r, c):
1470 def setwinsize(self, r, c):
1471
1471
1472 """This sets the terminal window size of the child tty. This will cause
1472 """This sets the terminal window size of the child tty. This will cause
1473 a SIGWINCH signal to be sent to the child. This does not change the
1473 a SIGWINCH signal to be sent to the child. This does not change the
1474 physical window size. It changes the size reported to TTY-aware
1474 physical window size. It changes the size reported to TTY-aware
1475 applications like vi or curses -- applications that respond to the
1475 applications like vi or curses -- applications that respond to the
1476 SIGWINCH signal. """
1476 SIGWINCH signal. """
1477
1477
1478 # Check for buggy platforms. Some Python versions on some platforms
1478 # Check for buggy platforms. Some Python versions on some platforms
1479 # (notably OSF1 Alpha and RedHat 7.1) truncate the value for
1479 # (notably OSF1 Alpha and RedHat 7.1) truncate the value for
1480 # termios.TIOCSWINSZ. It is not clear why this happens.
1480 # termios.TIOCSWINSZ. It is not clear why this happens.
1481 # These platforms don't seem to handle the signed int very well;
1481 # These platforms don't seem to handle the signed int very well;
1482 # yet other platforms like OpenBSD have a large negative value for
1482 # yet other platforms like OpenBSD have a large negative value for
1483 # TIOCSWINSZ and they don't have a truncate problem.
1483 # TIOCSWINSZ and they don't have a truncate problem.
1484 # Newer versions of Linux have totally different values for TIOCSWINSZ.
1484 # Newer versions of Linux have totally different values for TIOCSWINSZ.
1485 # Note that this fix is a hack.
1485 # Note that this fix is a hack.
1486 TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561)
1486 TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561)
1487 if TIOCSWINSZ == 2148037735L: # L is not required in Python >= 2.2.
1487 if TIOCSWINSZ == 2148037735L: # L is not required in Python >= 2.2.
1488 TIOCSWINSZ = -2146929561 # Same bits, but with sign.
1488 TIOCSWINSZ = -2146929561 # Same bits, but with sign.
1489 # Note, assume ws_xpixel and ws_ypixel are zero.
1489 # Note, assume ws_xpixel and ws_ypixel are zero.
1490 s = struct.pack('HHHH', r, c, 0, 0)
1490 s = struct.pack('HHHH', r, c, 0, 0)
1491 fcntl.ioctl(self.fileno(), TIOCSWINSZ, s)
1491 fcntl.ioctl(self.fileno(), TIOCSWINSZ, s)
1492
1492
1493 def interact(self, escape_character = b'\x1d', input_filter = None, output_filter = None):
1493 def interact(self, escape_character = b'\x1d', input_filter = None, output_filter = None):
1494
1494
1495 """This gives control of the child process to the interactive user (the
1495 """This gives control of the child process to the interactive user (the
1496 human at the keyboard). Keystrokes are sent to the child process, and
1496 human at the keyboard). Keystrokes are sent to the child process, and
1497 the stdout and stderr output of the child process is printed. This
1497 the stdout and stderr output of the child process is printed. This
1498 simply echos the child stdout and child stderr to the real stdout and
1498 simply echos the child stdout and child stderr to the real stdout and
1499 it echos the real stdin to the child stdin. When the user types the
1499 it echos the real stdin to the child stdin. When the user types the
1500 escape_character this method will stop. The default for
1500 escape_character this method will stop. The default for
1501 escape_character is ^]. This should not be confused with ASCII 27 --
1501 escape_character is ^]. This should not be confused with ASCII 27 --
1502 the ESC character. ASCII 29 was chosen for historical merit because
1502 the ESC character. ASCII 29 was chosen for historical merit because
1503 this is the character used by 'telnet' as the escape character. The
1503 this is the character used by 'telnet' as the escape character. The
1504 escape_character will not be sent to the child process.
1504 escape_character will not be sent to the child process.
1505
1505
1506 You may pass in optional input and output filter functions. These
1506 You may pass in optional input and output filter functions. These
1507 functions should take a string and return a string. The output_filter
1507 functions should take a string and return a string. The output_filter
1508 will be passed all the output from the child process. The input_filter
1508 will be passed all the output from the child process. The input_filter
1509 will be passed all the keyboard input from the user. The input_filter
1509 will be passed all the keyboard input from the user. The input_filter
1510 is run BEFORE the check for the escape_character.
1510 is run BEFORE the check for the escape_character.
1511
1511
1512 Note that if you change the window size of the parent the SIGWINCH
1512 Note that if you change the window size of the parent the SIGWINCH
1513 signal will not be passed through to the child. If you want the child
1513 signal will not be passed through to the child. If you want the child
1514 window size to change when the parent's window size changes then do
1514 window size to change when the parent's window size changes then do
1515 something like the following example::
1515 something like the following example::
1516
1516
1517 import pexpect, struct, fcntl, termios, signal, sys
1517 import pexpect, struct, fcntl, termios, signal, sys
1518 def sigwinch_passthrough (sig, data):
1518 def sigwinch_passthrough (sig, data):
1519 s = struct.pack("HHHH", 0, 0, 0, 0)
1519 s = struct.pack("HHHH", 0, 0, 0, 0)
1520 a = struct.unpack('hhhh', fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ , s))
1520 a = struct.unpack('hhhh', fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ , s))
1521 global p
1521 global p
1522 p.setwinsize(a[0],a[1])
1522 p.setwinsize(a[0],a[1])
1523 p = pexpect.spawn('/bin/bash') # Note this is global and used in sigwinch_passthrough.
1523 p = pexpect.spawn('/bin/bash') # Note this is global and used in sigwinch_passthrough.
1524 signal.signal(signal.SIGWINCH, sigwinch_passthrough)
1524 signal.signal(signal.SIGWINCH, sigwinch_passthrough)
1525 p.interact()
1525 p.interact()
1526 """
1526 """
1527
1527
1528 # Flush the buffer.
1528 # Flush the buffer.
1529 if PY3: self.stdout.write(_cast_unicode(self.buffer, self.encoding))
1529 if PY3: self.stdout.write(_cast_unicode(self.buffer, self.encoding))
1530 else: self.stdout.write(self.buffer)
1530 else: self.stdout.write(self.buffer)
1531 self.stdout.flush()
1531 self.stdout.flush()
1532 self.buffer = self._empty_buffer
1532 self.buffer = self._empty_buffer
1533 mode = tty.tcgetattr(self.STDIN_FILENO)
1533 mode = tty.tcgetattr(self.STDIN_FILENO)
1534 tty.setraw(self.STDIN_FILENO)
1534 tty.setraw(self.STDIN_FILENO)
1535 try:
1535 try:
1536 self.__interact_copy(escape_character, input_filter, output_filter)
1536 self.__interact_copy(escape_character, input_filter, output_filter)
1537 finally:
1537 finally:
1538 tty.tcsetattr(self.STDIN_FILENO, tty.TCSAFLUSH, mode)
1538 tty.tcsetattr(self.STDIN_FILENO, tty.TCSAFLUSH, mode)
1539
1539
1540 def __interact_writen(self, fd, data):
1540 def __interact_writen(self, fd, data):
1541
1541
1542 """This is used by the interact() method.
1542 """This is used by the interact() method.
1543 """
1543 """
1544
1544
1545 while data != b'' and self.isalive():
1545 while data != b'' and self.isalive():
1546 n = os.write(fd, data)
1546 n = os.write(fd, data)
1547 data = data[n:]
1547 data = data[n:]
1548
1548
1549 def __interact_read(self, fd):
1549 def __interact_read(self, fd):
1550
1550
1551 """This is used by the interact() method.
1551 """This is used by the interact() method.
1552 """
1552 """
1553
1553
1554 return os.read(fd, 1000)
1554 return os.read(fd, 1000)
1555
1555
1556 def __interact_copy(self, escape_character = None, input_filter = None, output_filter = None):
1556 def __interact_copy(self, escape_character = None, input_filter = None, output_filter = None):
1557
1557
1558 """This is used by the interact() method.
1558 """This is used by the interact() method.
1559 """
1559 """
1560
1560
1561 while self.isalive():
1561 while self.isalive():
1562 r,w,e = self.__select([self.child_fd, self.STDIN_FILENO], [], [])
1562 r,w,e = self.__select([self.child_fd, self.STDIN_FILENO], [], [])
1563 if self.child_fd in r:
1563 if self.child_fd in r:
1564 data = self.__interact_read(self.child_fd)
1564 data = self.__interact_read(self.child_fd)
1565 if output_filter: data = output_filter(data)
1565 if output_filter: data = output_filter(data)
1566 if self.logfile is not None:
1566 if self.logfile is not None:
1567 self.logfile.write (data)
1567 self.logfile.write (data)
1568 self.logfile.flush()
1568 self.logfile.flush()
1569 os.write(self.STDOUT_FILENO, data)
1569 os.write(self.STDOUT_FILENO, data)
1570 if self.STDIN_FILENO in r:
1570 if self.STDIN_FILENO in r:
1571 data = self.__interact_read(self.STDIN_FILENO)
1571 data = self.__interact_read(self.STDIN_FILENO)
1572 if input_filter: data = input_filter(data)
1572 if input_filter: data = input_filter(data)
1573 i = data.rfind(escape_character)
1573 i = data.rfind(escape_character)
1574 if i != -1:
1574 if i != -1:
1575 data = data[:i]
1575 data = data[:i]
1576 self.__interact_writen(self.child_fd, data)
1576 self.__interact_writen(self.child_fd, data)
1577 break
1577 break
1578 self.__interact_writen(self.child_fd, data)
1578 self.__interact_writen(self.child_fd, data)
1579
1579
1580 def __select (self, iwtd, owtd, ewtd, timeout=None):
1580 def __select (self, iwtd, owtd, ewtd, timeout=None):
1581
1581
1582 """This is a wrapper around select.select() that ignores signals. If
1582 """This is a wrapper around select.select() that ignores signals. If
1583 select.select raises a select.error exception and errno is an EINTR
1583 select.select raises a select.error exception and errno is an EINTR
1584 error then it is ignored. Mainly this is used to ignore sigwinch
1584 error then it is ignored. Mainly this is used to ignore sigwinch
1585 (terminal resize). """
1585 (terminal resize). """
1586
1586
1587 # if select() is interrupted by a signal (errno==EINTR) then
1587 # if select() is interrupted by a signal (errno==EINTR) then
1588 # we loop back and enter the select() again.
1588 # we loop back and enter the select() again.
1589 if timeout is not None:
1589 if timeout is not None:
1590 end_time = time.time() + timeout
1590 end_time = time.time() + timeout
1591 while True:
1591 while True:
1592 try:
1592 try:
1593 return select.select (iwtd, owtd, ewtd, timeout)
1593 return select.select (iwtd, owtd, ewtd, timeout)
1594 except select.error as e:
1594 except select.error as e:
1595 if e.args[0] == errno.EINTR:
1595 if e.args[0] == errno.EINTR:
1596 # if we loop back we have to subtract the amount of time we already waited.
1596 # if we loop back we have to subtract the amount of time we already waited.
1597 if timeout is not None:
1597 if timeout is not None:
1598 timeout = end_time - time.time()
1598 timeout = end_time - time.time()
1599 if timeout < 0:
1599 if timeout < 0:
1600 return ([],[],[])
1600 return ([],[],[])
1601 else: # something else caused the select.error, so this really is an exception
1601 else: # something else caused the select.error, so this really is an exception
1602 raise
1602 raise
1603
1603
1604 class spawn(spawnb):
1604 class spawn(spawnb):
1605 """This is the main class interface for Pexpect. Use this class to start
1605 """This is the main class interface for Pexpect. Use this class to start
1606 and control child applications."""
1606 and control child applications."""
1607
1607
1608 _buffer_type = unicode
1608 _buffer_type = unicode
1609 def _cast_buffer_type(self, s):
1609 def _cast_buffer_type(self, s):
1610 return _cast_unicode(s, self.encoding)
1610 return _cast_unicode(s, self.encoding)
1611 _empty_buffer = u''
1611 _empty_buffer = u''
1612 _pty_newline = u'\r\n'
1612 _pty_newline = u'\r\n'
1613
1613
1614 def __init__(self, command, args=[], timeout=30, maxread=2000, searchwindowsize=None,
1614 def __init__(self, command, args=[], timeout=30, maxread=2000, searchwindowsize=None,
1615 logfile=None, cwd=None, env=None, encoding='utf-8'):
1615 logfile=None, cwd=None, env=None, encoding='utf-8'):
1616 super(spawn, self).__init__(command, args, timeout=timeout, maxread=maxread,
1616 super(spawn, self).__init__(command, args, timeout=timeout, maxread=maxread,
1617 searchwindowsize=searchwindowsize, logfile=logfile, cwd=cwd, env=env)
1617 searchwindowsize=searchwindowsize, logfile=logfile, cwd=cwd, env=env)
1618 self.encoding = encoding
1618 self.encoding = encoding
1619
1619
1620 def _prepare_regex_pattern(self, p):
1620 def _prepare_regex_pattern(self, p):
1621 "Recompile bytes regexes as unicode regexes."
1621 "Recompile bytes regexes as unicode regexes."
1622 if isinstance(p.pattern, bytes):
1622 if isinstance(p.pattern, bytes):
1623 p = re.compile(p.pattern.decode(self.encoding), p.flags)
1623 p = re.compile(p.pattern.decode(self.encoding), p.flags)
1624 return p
1624 return p
1625
1625
1626 def read_nonblocking(self, size=1, timeout=-1):
1626 def read_nonblocking(self, size=1, timeout=-1):
1627 return super(spawn, self).read_nonblocking(size=size, timeout=timeout)\
1627 return super(spawn, self).read_nonblocking(size=size, timeout=timeout)\
1628 .decode(self.encoding)
1628 .decode(self.encoding)
1629
1629
1630 read_nonblocking.__doc__ = spawnb.read_nonblocking.__doc__
1630 read_nonblocking.__doc__ = spawnb.read_nonblocking.__doc__
1631
1631
1632
1632
1633 ##############################################################################
1633 ##############################################################################
1634 # End of spawn class
1634 # End of spawn class
1635 ##############################################################################
1635 ##############################################################################
1636
1636
1637 class searcher_string (object):
1637 class searcher_string (object):
1638
1638
1639 """This is a plain string search helper for the spawn.expect_any() method.
1639 """This is a plain string search helper for the spawn.expect_any() method.
1640 This helper class is for speed. For more powerful regex patterns
1640 This helper class is for speed. For more powerful regex patterns
1641 see the helper class, searcher_re.
1641 see the helper class, searcher_re.
1642
1642
1643 Attributes:
1643 Attributes:
1644
1644
1645 eof_index - index of EOF, or -1
1645 eof_index - index of EOF, or -1
1646 timeout_index - index of TIMEOUT, or -1
1646 timeout_index - index of TIMEOUT, or -1
1647
1647
1648 After a successful match by the search() method the following attributes
1648 After a successful match by the search() method the following attributes
1649 are available:
1649 are available:
1650
1650
1651 start - index into the buffer, first byte of match
1651 start - index into the buffer, first byte of match
1652 end - index into the buffer, first byte after match
1652 end - index into the buffer, first byte after match
1653 match - the matching string itself
1653 match - the matching string itself
1654
1654
1655 """
1655 """
1656
1656
1657 def __init__(self, strings):
1657 def __init__(self, strings):
1658
1658
1659 """This creates an instance of searcher_string. This argument 'strings'
1659 """This creates an instance of searcher_string. This argument 'strings'
1660 may be a list; a sequence of strings; or the EOF or TIMEOUT types. """
1660 may be a list; a sequence of strings; or the EOF or TIMEOUT types. """
1661
1661
1662 self.eof_index = -1
1662 self.eof_index = -1
1663 self.timeout_index = -1
1663 self.timeout_index = -1
1664 self._strings = []
1664 self._strings = []
1665 for n, s in enumerate(strings):
1665 for n, s in enumerate(strings):
1666 if s is EOF:
1666 if s is EOF:
1667 self.eof_index = n
1667 self.eof_index = n
1668 continue
1668 continue
1669 if s is TIMEOUT:
1669 if s is TIMEOUT:
1670 self.timeout_index = n
1670 self.timeout_index = n
1671 continue
1671 continue
1672 self._strings.append((n, s))
1672 self._strings.append((n, s))
1673
1673
1674 def __str__(self):
1674 def __str__(self):
1675
1675
1676 """This returns a human-readable string that represents the state of
1676 """This returns a human-readable string that represents the state of
1677 the object."""
1677 the object."""
1678
1678
1679 ss = [ (ns[0],' %d: "%s"' % ns) for ns in self._strings ]
1679 ss = [ (ns[0],' %d: "%s"' % ns) for ns in self._strings ]
1680 ss.append((-1,'searcher_string:'))
1680 ss.append((-1,'searcher_string:'))
1681 if self.eof_index >= 0:
1681 if self.eof_index >= 0:
1682 ss.append ((self.eof_index,' %d: EOF' % self.eof_index))
1682 ss.append ((self.eof_index,' %d: EOF' % self.eof_index))
1683 if self.timeout_index >= 0:
1683 if self.timeout_index >= 0:
1684 ss.append ((self.timeout_index,' %d: TIMEOUT' % self.timeout_index))
1684 ss.append ((self.timeout_index,' %d: TIMEOUT' % self.timeout_index))
1685 ss.sort()
1685 ss.sort()
1686 return '\n'.join(a[1] for a in ss)
1686 return '\n'.join(a[1] for a in ss)
1687
1687
1688 def search(self, buffer, freshlen, searchwindowsize=None):
1688 def search(self, buffer, freshlen, searchwindowsize=None):
1689
1689
1690 """This searches 'buffer' for the first occurence of one of the search
1690 """This searches 'buffer' for the first occurence of one of the search
1691 strings. 'freshlen' must indicate the number of bytes at the end of
1691 strings. 'freshlen' must indicate the number of bytes at the end of
1692 'buffer' which have not been searched before. It helps to avoid
1692 'buffer' which have not been searched before. It helps to avoid
1693 searching the same, possibly big, buffer over and over again.
1693 searching the same, possibly big, buffer over and over again.
1694
1694
1695 See class spawn for the 'searchwindowsize' argument.
1695 See class spawn for the 'searchwindowsize' argument.
1696
1696
1697 If there is a match this returns the index of that string, and sets
1697 If there is a match this returns the index of that string, and sets
1698 'start', 'end' and 'match'. Otherwise, this returns -1. """
1698 'start', 'end' and 'match'. Otherwise, this returns -1. """
1699
1699
1700 absurd_match = len(buffer)
1700 absurd_match = len(buffer)
1701 first_match = absurd_match
1701 first_match = absurd_match
1702
1702
1703 # 'freshlen' helps a lot here. Further optimizations could
1703 # 'freshlen' helps a lot here. Further optimizations could
1704 # possibly include:
1704 # possibly include:
1705 #
1705 #
1706 # using something like the Boyer-Moore Fast String Searching
1706 # using something like the Boyer-Moore Fast String Searching
1707 # Algorithm; pre-compiling the search through a list of
1707 # Algorithm; pre-compiling the search through a list of
1708 # strings into something that can scan the input once to
1708 # strings into something that can scan the input once to
1709 # search for all N strings; realize that if we search for
1709 # search for all N strings; realize that if we search for
1710 # ['bar', 'baz'] and the input is '...foo' we need not bother
1710 # ['bar', 'baz'] and the input is '...foo' we need not bother
1711 # rescanning until we've read three more bytes.
1711 # rescanning until we've read three more bytes.
1712 #
1712 #
1713 # Sadly, I don't know enough about this interesting topic. /grahn
1713 # Sadly, I don't know enough about this interesting topic. /grahn
1714
1714
1715 for index, s in self._strings:
1715 for index, s in self._strings:
1716 if searchwindowsize is None:
1716 if searchwindowsize is None:
1717 # the match, if any, can only be in the fresh data,
1717 # the match, if any, can only be in the fresh data,
1718 # or at the very end of the old data
1718 # or at the very end of the old data
1719 offset = -(freshlen+len(s))
1719 offset = -(freshlen+len(s))
1720 else:
1720 else:
1721 # better obey searchwindowsize
1721 # better obey searchwindowsize
1722 offset = -searchwindowsize
1722 offset = -searchwindowsize
1723 n = buffer.find(s, offset)
1723 n = buffer.find(s, offset)
1724 if n >= 0 and n < first_match:
1724 if n >= 0 and n < first_match:
1725 first_match = n
1725 first_match = n
1726 best_index, best_match = index, s
1726 best_index, best_match = index, s
1727 if first_match == absurd_match:
1727 if first_match == absurd_match:
1728 return -1
1728 return -1
1729 self.match = best_match
1729 self.match = best_match
1730 self.start = first_match
1730 self.start = first_match
1731 self.end = self.start + len(self.match)
1731 self.end = self.start + len(self.match)
1732 return best_index
1732 return best_index
1733
1733
1734 class searcher_re (object):
1734 class searcher_re (object):
1735
1735
1736 """This is regular expression string search helper for the
1736 """This is regular expression string search helper for the
1737 spawn.expect_any() method. This helper class is for powerful
1737 spawn.expect_any() method. This helper class is for powerful
1738 pattern matching. For speed, see the helper class, searcher_string.
1738 pattern matching. For speed, see the helper class, searcher_string.
1739
1739
1740 Attributes:
1740 Attributes:
1741
1741
1742 eof_index - index of EOF, or -1
1742 eof_index - index of EOF, or -1
1743 timeout_index - index of TIMEOUT, or -1
1743 timeout_index - index of TIMEOUT, or -1
1744
1744
1745 After a successful match by the search() method the following attributes
1745 After a successful match by the search() method the following attributes
1746 are available:
1746 are available:
1747
1747
1748 start - index into the buffer, first byte of match
1748 start - index into the buffer, first byte of match
1749 end - index into the buffer, first byte after match
1749 end - index into the buffer, first byte after match
1750 match - the re.match object returned by a succesful re.search
1750 match - the re.match object returned by a succesful re.search
1751
1751
1752 """
1752 """
1753
1753
1754 def __init__(self, patterns):
1754 def __init__(self, patterns):
1755
1755
1756 """This creates an instance that searches for 'patterns' Where
1756 """This creates an instance that searches for 'patterns' Where
1757 'patterns' may be a list or other sequence of compiled regular
1757 'patterns' may be a list or other sequence of compiled regular
1758 expressions, or the EOF or TIMEOUT types."""
1758 expressions, or the EOF or TIMEOUT types."""
1759
1759
1760 self.eof_index = -1
1760 self.eof_index = -1
1761 self.timeout_index = -1
1761 self.timeout_index = -1
1762 self._searches = []
1762 self._searches = []
1763 for n, s in enumerate(patterns):
1763 for n, s in enumerate(patterns):
1764 if s is EOF:
1764 if s is EOF:
1765 self.eof_index = n
1765 self.eof_index = n
1766 continue
1766 continue
1767 if s is TIMEOUT:
1767 if s is TIMEOUT:
1768 self.timeout_index = n
1768 self.timeout_index = n
1769 continue
1769 continue
1770 self._searches.append((n, s))
1770 self._searches.append((n, s))
1771
1771
1772 def __str__(self):
1772 def __str__(self):
1773
1773
1774 """This returns a human-readable string that represents the state of
1774 """This returns a human-readable string that represents the state of
1775 the object."""
1775 the object."""
1776
1776
1777 ss = [ (n,' %d: re.compile("%s")' % (n,str(s.pattern))) for n,s in self._searches]
1777 ss = [ (n,' %d: re.compile("%s")' % (n,str(s.pattern))) for n,s in self._searches]
1778 ss.append((-1,'searcher_re:'))
1778 ss.append((-1,'searcher_re:'))
1779 if self.eof_index >= 0:
1779 if self.eof_index >= 0:
1780 ss.append ((self.eof_index,' %d: EOF' % self.eof_index))
1780 ss.append ((self.eof_index,' %d: EOF' % self.eof_index))
1781 if self.timeout_index >= 0:
1781 if self.timeout_index >= 0:
1782 ss.append ((self.timeout_index,' %d: TIMEOUT' % self.timeout_index))
1782 ss.append ((self.timeout_index,' %d: TIMEOUT' % self.timeout_index))
1783 ss.sort()
1783 ss.sort()
1784 return '\n'.join(a[1] for a in ss)
1784 return '\n'.join(a[1] for a in ss)
1785
1785
1786 def search(self, buffer, freshlen, searchwindowsize=None):
1786 def search(self, buffer, freshlen, searchwindowsize=None):
1787
1787
1788 """This searches 'buffer' for the first occurence of one of the regular
1788 """This searches 'buffer' for the first occurence of one of the regular
1789 expressions. 'freshlen' must indicate the number of bytes at the end of
1789 expressions. 'freshlen' must indicate the number of bytes at the end of
1790 'buffer' which have not been searched before.
1790 'buffer' which have not been searched before.
1791
1791
1792 See class spawn for the 'searchwindowsize' argument.
1792 See class spawn for the 'searchwindowsize' argument.
1793
1793
1794 If there is a match this returns the index of that string, and sets
1794 If there is a match this returns the index of that string, and sets
1795 'start', 'end' and 'match'. Otherwise, returns -1."""
1795 'start', 'end' and 'match'. Otherwise, returns -1."""
1796
1796
1797 absurd_match = len(buffer)
1797 absurd_match = len(buffer)
1798 first_match = absurd_match
1798 first_match = absurd_match
1799 # 'freshlen' doesn't help here -- we cannot predict the
1799 # 'freshlen' doesn't help here -- we cannot predict the
1800 # length of a match, and the re module provides no help.
1800 # length of a match, and the re module provides no help.
1801 if searchwindowsize is None:
1801 if searchwindowsize is None:
1802 searchstart = 0
1802 searchstart = 0
1803 else:
1803 else:
1804 searchstart = max(0, len(buffer)-searchwindowsize)
1804 searchstart = max(0, len(buffer)-searchwindowsize)
1805 for index, s in self._searches:
1805 for index, s in self._searches:
1806 match = s.search(buffer, searchstart)
1806 match = s.search(buffer, searchstart)
1807 if match is None:
1807 if match is None:
1808 continue
1808 continue
1809 n = match.start()
1809 n = match.start()
1810 if n < first_match:
1810 if n < first_match:
1811 first_match = n
1811 first_match = n
1812 the_match = match
1812 the_match = match
1813 best_index = index
1813 best_index = index
1814 if first_match == absurd_match:
1814 if first_match == absurd_match:
1815 return -1
1815 return -1
1816 self.start = first_match
1816 self.start = first_match
1817 self.match = the_match
1817 self.match = the_match
1818 self.end = self.match.end()
1818 self.end = self.match.end()
1819 return best_index
1819 return best_index
1820
1820
1821 def which (filename):
1821 def which (filename):
1822
1822
1823 """This takes a given filename; tries to find it in the environment path;
1823 """This takes a given filename; tries to find it in the environment path;
1824 then checks if it is executable. This returns the full path to the filename
1824 then checks if it is executable. This returns the full path to the filename
1825 if found and executable. Otherwise this returns None."""
1825 if found and executable. Otherwise this returns None."""
1826
1826
1827 # Special case where filename already contains a path.
1827 # Special case where filename already contains a path.
1828 if os.path.dirname(filename) != '':
1828 if os.path.dirname(filename) != '':
1829 if os.access (filename, os.X_OK):
1829 if os.access (filename, os.X_OK):
1830 return filename
1830 return filename
1831
1831
1832 if not os.environ.has_key('PATH') or os.environ['PATH'] == '':
1832 if not os.environ.has_key('PATH') or os.environ['PATH'] == '':
1833 p = os.defpath
1833 p = os.defpath
1834 else:
1834 else:
1835 p = os.environ['PATH']
1835 p = os.environ['PATH']
1836
1836
1837 pathlist = p.split(os.pathsep)
1837 pathlist = p.split(os.pathsep)
1838
1838
1839 for path in pathlist:
1839 for path in pathlist:
1840 f = os.path.join(path, filename)
1840 f = os.path.join(path, filename)
1841 if os.access(f, os.X_OK):
1841 if os.access(f, os.X_OK):
1842 return f
1842 return f
1843 return None
1843 return None
1844
1844
1845 def split_command_line(command_line):
1845 def split_command_line(command_line):
1846
1846
1847 """This splits a command line into a list of arguments. It splits arguments
1847 """This splits a command line into a list of arguments. It splits arguments
1848 on spaces, but handles embedded quotes, doublequotes, and escaped
1848 on spaces, but handles embedded quotes, doublequotes, and escaped
1849 characters. It's impossible to do this with a regular expression, so I
1849 characters. It's impossible to do this with a regular expression, so I
1850 wrote a little state machine to parse the command line. """
1850 wrote a little state machine to parse the command line. """
1851
1851
1852 arg_list = []
1852 arg_list = []
1853 arg = ''
1853 arg = ''
1854
1854
1855 # Constants to name the states we can be in.
1855 # Constants to name the states we can be in.
1856 state_basic = 0
1856 state_basic = 0
1857 state_esc = 1
1857 state_esc = 1
1858 state_singlequote = 2
1858 state_singlequote = 2
1859 state_doublequote = 3
1859 state_doublequote = 3
1860 state_whitespace = 4 # The state of consuming whitespace between commands.
1860 state_whitespace = 4 # The state of consuming whitespace between commands.
1861 state = state_basic
1861 state = state_basic
1862
1862
1863 for c in command_line:
1863 for c in command_line:
1864 if state == state_basic or state == state_whitespace:
1864 if state == state_basic or state == state_whitespace:
1865 if c == '\\': # Escape the next character
1865 if c == '\\': # Escape the next character
1866 state = state_esc
1866 state = state_esc
1867 elif c == r"'": # Handle single quote
1867 elif c == r"'": # Handle single quote
1868 state = state_singlequote
1868 state = state_singlequote
1869 elif c == r'"': # Handle double quote
1869 elif c == r'"': # Handle double quote
1870 state = state_doublequote
1870 state = state_doublequote
1871 elif c.isspace():
1871 elif c.isspace():
1872 # Add arg to arg_list if we aren't in the middle of whitespace.
1872 # Add arg to arg_list if we aren't in the middle of whitespace.
1873 if state == state_whitespace:
1873 if state == state_whitespace:
1874 None # Do nothing.
1874 None # Do nothing.
1875 else:
1875 else:
1876 arg_list.append(arg)
1876 arg_list.append(arg)
1877 arg = ''
1877 arg = ''
1878 state = state_whitespace
1878 state = state_whitespace
1879 else:
1879 else:
1880 arg = arg + c
1880 arg = arg + c
1881 state = state_basic
1881 state = state_basic
1882 elif state == state_esc:
1882 elif state == state_esc:
1883 arg = arg + c
1883 arg = arg + c
1884 state = state_basic
1884 state = state_basic
1885 elif state == state_singlequote:
1885 elif state == state_singlequote:
1886 if c == r"'":
1886 if c == r"'":
1887 state = state_basic
1887 state = state_basic
1888 else:
1888 else:
1889 arg = arg + c
1889 arg = arg + c
1890 elif state == state_doublequote:
1890 elif state == state_doublequote:
1891 if c == r'"':
1891 if c == r'"':
1892 state = state_basic
1892 state = state_basic
1893 else:
1893 else:
1894 arg = arg + c
1894 arg = arg + c
1895
1895
1896 if arg != '':
1896 if arg != '':
1897 arg_list.append(arg)
1897 arg_list.append(arg)
1898 return arg_list
1898 return arg_list
1899
1899
1900 # vi:set sr et ts=4 sw=4 ft=python :
1900 # vi:set sr et ts=4 sw=4 ft=python :
@@ -1,88 +1,88 b''
1 #
1 #
2 # This file is adapted from a paramiko demo, and thus licensed under LGPL 2.1.
2 # This file is adapted from a paramiko demo, and thus licensed under LGPL 2.1.
3 # Original Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com>
3 # Original Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com>
4 # Edits Copyright (C) 2010 The IPython Team
4 # Edits Copyright (C) 2010 The IPython Team
5 #
5 #
6 # Paramiko is free software; you can redistribute it and/or modify it under the
6 # Paramiko is free software; you can redistribute it and/or modify it under the
7 # terms of the GNU Lesser General Public License as published by the Free
7 # terms of the GNU Lesser General Public License as published by the Free
8 # Software Foundation; either version 2.1 of the License, or (at your option)
8 # Software Foundation; either version 2.1 of the License, or (at your option)
9 # any later version.
9 # any later version.
10 #
10 #
11 # Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY
11 # Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY
12 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14 # details.
14 # details.
15 #
15 #
16 # You should have received a copy of the GNU Lesser General Public License
16 # You should have received a copy of the GNU Lesser General Public License
17 # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
17 # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA.
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA.
19
19
20 """
20 """
21 Sample script showing how to do local port forwarding over paramiko.
21 Sample script showing how to do local port forwarding over paramiko.
22
22
23 This script connects to the requested SSH server and sets up local port
23 This script connects to the requested SSH server and sets up local port
24 forwarding (the openssh -L option) from a local port through a tunneled
24 forwarding (the openssh -L option) from a local port through a tunneled
25 connection to a destination reachable from the SSH server machine.
25 connection to a destination reachable from the SSH server machine.
26 """
26 """
27
27
28 from __future__ import print_function
28 from __future__ import print_function
29
29
30 import logging
30 import logging
31 import select
31 import select
32 import SocketServer
32 import SocketServer
33
33
34 logger = logging.getLogger('ssh')
34 logger = logging.getLogger('ssh')
35
35
36 class ForwardServer (SocketServer.ThreadingTCPServer):
36 class ForwardServer (SocketServer.ThreadingTCPServer):
37 daemon_threads = True
37 daemon_threads = True
38 allow_reuse_address = True
38 allow_reuse_address = True
39
39
40
40
41 class Handler (SocketServer.BaseRequestHandler):
41 class Handler (SocketServer.BaseRequestHandler):
42
42
43 def handle(self):
43 def handle(self):
44 try:
44 try:
45 chan = self.ssh_transport.open_channel('direct-tcpip',
45 chan = self.ssh_transport.open_channel('direct-tcpip',
46 (self.chain_host, self.chain_port),
46 (self.chain_host, self.chain_port),
47 self.request.getpeername())
47 self.request.getpeername())
48 except Exception, e:
48 except Exception as e:
49 logger.debug('Incoming request to %s:%d failed: %s' % (self.chain_host,
49 logger.debug('Incoming request to %s:%d failed: %s' % (self.chain_host,
50 self.chain_port,
50 self.chain_port,
51 repr(e)))
51 repr(e)))
52 return
52 return
53 if chan is None:
53 if chan is None:
54 logger.debug('Incoming request to %s:%d was rejected by the SSH server.' %
54 logger.debug('Incoming request to %s:%d was rejected by the SSH server.' %
55 (self.chain_host, self.chain_port))
55 (self.chain_host, self.chain_port))
56 return
56 return
57
57
58 logger.debug('Connected! Tunnel open %r -> %r -> %r' % (self.request.getpeername(),
58 logger.debug('Connected! Tunnel open %r -> %r -> %r' % (self.request.getpeername(),
59 chan.getpeername(), (self.chain_host, self.chain_port)))
59 chan.getpeername(), (self.chain_host, self.chain_port)))
60 while True:
60 while True:
61 r, w, x = select.select([self.request, chan], [], [])
61 r, w, x = select.select([self.request, chan], [], [])
62 if self.request in r:
62 if self.request in r:
63 data = self.request.recv(1024)
63 data = self.request.recv(1024)
64 if len(data) == 0:
64 if len(data) == 0:
65 break
65 break
66 chan.send(data)
66 chan.send(data)
67 if chan in r:
67 if chan in r:
68 data = chan.recv(1024)
68 data = chan.recv(1024)
69 if len(data) == 0:
69 if len(data) == 0:
70 break
70 break
71 self.request.send(data)
71 self.request.send(data)
72 chan.close()
72 chan.close()
73 self.request.close()
73 self.request.close()
74 logger.debug('Tunnel closed ')
74 logger.debug('Tunnel closed ')
75
75
76
76
77 def forward_tunnel(local_port, remote_host, remote_port, transport):
77 def forward_tunnel(local_port, remote_host, remote_port, transport):
78 # this is a little convoluted, but lets me configure things for the Handler
78 # this is a little convoluted, but lets me configure things for the Handler
79 # object. (SocketServer doesn't give Handlers any way to access the outer
79 # object. (SocketServer doesn't give Handlers any way to access the outer
80 # server normally.)
80 # server normally.)
81 class SubHander (Handler):
81 class SubHander (Handler):
82 chain_host = remote_host
82 chain_host = remote_host
83 chain_port = remote_port
83 chain_port = remote_port
84 ssh_transport = transport
84 ssh_transport = transport
85 ForwardServer(('127.0.0.1', local_port), SubHander).serve_forever()
85 ForwardServer(('127.0.0.1', local_port), SubHander).serve_forever()
86
86
87
87
88 __all__ = ['forward_tunnel']
88 __all__ = ['forward_tunnel']
@@ -1,592 +1,592 b''
1 # coding: utf-8
1 # coding: utf-8
2 """A tornado based IPython notebook server.
2 """A tornado based IPython notebook server.
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 # stdlib
19 # stdlib
20 import errno
20 import errno
21 import logging
21 import logging
22 import os
22 import os
23 import random
23 import random
24 import re
24 import re
25 import select
25 import select
26 import signal
26 import signal
27 import socket
27 import socket
28 import sys
28 import sys
29 import threading
29 import threading
30 import time
30 import time
31 import webbrowser
31 import webbrowser
32
32
33 # Third party
33 # Third party
34 import zmq
34 import zmq
35
35
36 # Install the pyzmq ioloop. This has to be done before anything else from
36 # Install the pyzmq ioloop. This has to be done before anything else from
37 # tornado is imported.
37 # tornado is imported.
38 from zmq.eventloop import ioloop
38 from zmq.eventloop import ioloop
39 ioloop.install()
39 ioloop.install()
40
40
41 from tornado import httpserver
41 from tornado import httpserver
42 from tornado import web
42 from tornado import web
43
43
44 # Our own libraries
44 # Our own libraries
45 from .kernelmanager import MappingKernelManager
45 from .kernelmanager import MappingKernelManager
46 from .handlers import (LoginHandler, LogoutHandler,
46 from .handlers import (LoginHandler, LogoutHandler,
47 ProjectDashboardHandler, NewHandler, NamedNotebookHandler,
47 ProjectDashboardHandler, NewHandler, NamedNotebookHandler,
48 MainKernelHandler, KernelHandler, KernelActionHandler, IOPubHandler,
48 MainKernelHandler, KernelHandler, KernelActionHandler, IOPubHandler,
49 ShellHandler, NotebookRootHandler, NotebookHandler, NotebookCopyHandler,
49 ShellHandler, NotebookRootHandler, NotebookHandler, NotebookCopyHandler,
50 RSTHandler, AuthenticatedFileHandler, PrintNotebookHandler,
50 RSTHandler, AuthenticatedFileHandler, PrintNotebookHandler,
51 MainClusterHandler, ClusterProfileHandler, ClusterActionHandler
51 MainClusterHandler, ClusterProfileHandler, ClusterActionHandler
52 )
52 )
53 from .notebookmanager import NotebookManager
53 from .notebookmanager import NotebookManager
54 from .clustermanager import ClusterManager
54 from .clustermanager import ClusterManager
55
55
56 from IPython.config.application import catch_config_error, boolean_flag
56 from IPython.config.application import catch_config_error, boolean_flag
57 from IPython.core.application import BaseIPythonApplication
57 from IPython.core.application import BaseIPythonApplication
58 from IPython.core.profiledir import ProfileDir
58 from IPython.core.profiledir import ProfileDir
59 from IPython.frontend.consoleapp import IPythonConsoleApp
59 from IPython.frontend.consoleapp import IPythonConsoleApp
60 from IPython.lib.kernel import swallow_argv
60 from IPython.lib.kernel import swallow_argv
61 from IPython.zmq.session import Session, default_secure
61 from IPython.zmq.session import Session, default_secure
62 from IPython.zmq.zmqshell import ZMQInteractiveShell
62 from IPython.zmq.zmqshell import ZMQInteractiveShell
63 from IPython.zmq.ipkernel import (
63 from IPython.zmq.ipkernel import (
64 flags as ipkernel_flags,
64 flags as ipkernel_flags,
65 aliases as ipkernel_aliases,
65 aliases as ipkernel_aliases,
66 IPKernelApp
66 IPKernelApp
67 )
67 )
68 from IPython.utils.traitlets import Dict, Unicode, Integer, List, Enum, Bool
68 from IPython.utils.traitlets import Dict, Unicode, Integer, List, Enum, Bool
69 from IPython.utils import py3compat
69 from IPython.utils import py3compat
70
70
71 #-----------------------------------------------------------------------------
71 #-----------------------------------------------------------------------------
72 # Module globals
72 # Module globals
73 #-----------------------------------------------------------------------------
73 #-----------------------------------------------------------------------------
74
74
75 _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
75 _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
76 _kernel_action_regex = r"(?P<action>restart|interrupt)"
76 _kernel_action_regex = r"(?P<action>restart|interrupt)"
77 _notebook_id_regex = r"(?P<notebook_id>\w+-\w+-\w+-\w+-\w+)"
77 _notebook_id_regex = r"(?P<notebook_id>\w+-\w+-\w+-\w+-\w+)"
78 _profile_regex = r"(?P<profile>[^\/]+)" # there is almost no text that is invalid
78 _profile_regex = r"(?P<profile>[^\/]+)" # there is almost no text that is invalid
79 _cluster_action_regex = r"(?P<action>start|stop)"
79 _cluster_action_regex = r"(?P<action>start|stop)"
80
80
81
81
82 LOCALHOST = '127.0.0.1'
82 LOCALHOST = '127.0.0.1'
83
83
84 _examples = """
84 _examples = """
85 ipython notebook # start the notebook
85 ipython notebook # start the notebook
86 ipython notebook --profile=sympy # use the sympy profile
86 ipython notebook --profile=sympy # use the sympy profile
87 ipython notebook --pylab=inline # pylab in inline plotting mode
87 ipython notebook --pylab=inline # pylab in inline plotting mode
88 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
88 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
89 ipython notebook --port=5555 --ip=* # Listen on port 5555, all interfaces
89 ipython notebook --port=5555 --ip=* # Listen on port 5555, all interfaces
90 """
90 """
91
91
92 #-----------------------------------------------------------------------------
92 #-----------------------------------------------------------------------------
93 # Helper functions
93 # Helper functions
94 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
95
95
96 def url_path_join(a,b):
96 def url_path_join(a,b):
97 if a.endswith('/') and b.startswith('/'):
97 if a.endswith('/') and b.startswith('/'):
98 return a[:-1]+b
98 return a[:-1]+b
99 else:
99 else:
100 return a+b
100 return a+b
101
101
102 def random_ports(port, n):
102 def random_ports(port, n):
103 """Generate a list of n random ports near the given port.
103 """Generate a list of n random ports near the given port.
104
104
105 The first 5 ports will be sequential, and the remaining n-5 will be
105 The first 5 ports will be sequential, and the remaining n-5 will be
106 randomly selected in the range [port-2*n, port+2*n].
106 randomly selected in the range [port-2*n, port+2*n].
107 """
107 """
108 for i in range(min(5, n)):
108 for i in range(min(5, n)):
109 yield port + i
109 yield port + i
110 for i in range(n-5):
110 for i in range(n-5):
111 yield port + random.randint(-2*n, 2*n)
111 yield port + random.randint(-2*n, 2*n)
112
112
113 #-----------------------------------------------------------------------------
113 #-----------------------------------------------------------------------------
114 # The Tornado web application
114 # The Tornado web application
115 #-----------------------------------------------------------------------------
115 #-----------------------------------------------------------------------------
116
116
117 class NotebookWebApplication(web.Application):
117 class NotebookWebApplication(web.Application):
118
118
119 def __init__(self, ipython_app, kernel_manager, notebook_manager,
119 def __init__(self, ipython_app, kernel_manager, notebook_manager,
120 cluster_manager, log,
120 cluster_manager, log,
121 base_project_url, settings_overrides):
121 base_project_url, settings_overrides):
122 handlers = [
122 handlers = [
123 (r"/", ProjectDashboardHandler),
123 (r"/", ProjectDashboardHandler),
124 (r"/login", LoginHandler),
124 (r"/login", LoginHandler),
125 (r"/logout", LogoutHandler),
125 (r"/logout", LogoutHandler),
126 (r"/new", NewHandler),
126 (r"/new", NewHandler),
127 (r"/%s" % _notebook_id_regex, NamedNotebookHandler),
127 (r"/%s" % _notebook_id_regex, NamedNotebookHandler),
128 (r"/%s/copy" % _notebook_id_regex, NotebookCopyHandler),
128 (r"/%s/copy" % _notebook_id_regex, NotebookCopyHandler),
129 (r"/%s/print" % _notebook_id_regex, PrintNotebookHandler),
129 (r"/%s/print" % _notebook_id_regex, PrintNotebookHandler),
130 (r"/kernels", MainKernelHandler),
130 (r"/kernels", MainKernelHandler),
131 (r"/kernels/%s" % _kernel_id_regex, KernelHandler),
131 (r"/kernels/%s" % _kernel_id_regex, KernelHandler),
132 (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler),
132 (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler),
133 (r"/kernels/%s/iopub" % _kernel_id_regex, IOPubHandler),
133 (r"/kernels/%s/iopub" % _kernel_id_regex, IOPubHandler),
134 (r"/kernels/%s/shell" % _kernel_id_regex, ShellHandler),
134 (r"/kernels/%s/shell" % _kernel_id_regex, ShellHandler),
135 (r"/notebooks", NotebookRootHandler),
135 (r"/notebooks", NotebookRootHandler),
136 (r"/notebooks/%s" % _notebook_id_regex, NotebookHandler),
136 (r"/notebooks/%s" % _notebook_id_regex, NotebookHandler),
137 (r"/rstservice/render", RSTHandler),
137 (r"/rstservice/render", RSTHandler),
138 (r"/files/(.*)", AuthenticatedFileHandler, {'path' : notebook_manager.notebook_dir}),
138 (r"/files/(.*)", AuthenticatedFileHandler, {'path' : notebook_manager.notebook_dir}),
139 (r"/clusters", MainClusterHandler),
139 (r"/clusters", MainClusterHandler),
140 (r"/clusters/%s/%s" % (_profile_regex, _cluster_action_regex), ClusterActionHandler),
140 (r"/clusters/%s/%s" % (_profile_regex, _cluster_action_regex), ClusterActionHandler),
141 (r"/clusters/%s" % _profile_regex, ClusterProfileHandler),
141 (r"/clusters/%s" % _profile_regex, ClusterProfileHandler),
142 ]
142 ]
143 settings = dict(
143 settings = dict(
144 template_path=os.path.join(os.path.dirname(__file__), "templates"),
144 template_path=os.path.join(os.path.dirname(__file__), "templates"),
145 static_path=os.path.join(os.path.dirname(__file__), "static"),
145 static_path=os.path.join(os.path.dirname(__file__), "static"),
146 cookie_secret=os.urandom(1024),
146 cookie_secret=os.urandom(1024),
147 login_url="/login",
147 login_url="/login",
148 )
148 )
149
149
150 # allow custom overrides for the tornado web app.
150 # allow custom overrides for the tornado web app.
151 settings.update(settings_overrides)
151 settings.update(settings_overrides)
152
152
153 # Python < 2.6.5 doesn't accept unicode keys in f(**kwargs), and
153 # Python < 2.6.5 doesn't accept unicode keys in f(**kwargs), and
154 # base_project_url will always be unicode, which will in turn
154 # base_project_url will always be unicode, which will in turn
155 # make the patterns unicode, and ultimately result in unicode
155 # make the patterns unicode, and ultimately result in unicode
156 # keys in kwargs to handler._execute(**kwargs) in tornado.
156 # keys in kwargs to handler._execute(**kwargs) in tornado.
157 # This enforces that base_project_url be ascii in that situation.
157 # This enforces that base_project_url be ascii in that situation.
158 #
158 #
159 # Note that the URLs these patterns check against are escaped,
159 # Note that the URLs these patterns check against are escaped,
160 # and thus guaranteed to be ASCII: 'hΓ©llo' is really 'h%C3%A9llo'.
160 # and thus guaranteed to be ASCII: 'hΓ©llo' is really 'h%C3%A9llo'.
161 base_project_url = py3compat.unicode_to_str(base_project_url, 'ascii')
161 base_project_url = py3compat.unicode_to_str(base_project_url, 'ascii')
162
162
163 # prepend base_project_url onto the patterns that we match
163 # prepend base_project_url onto the patterns that we match
164 new_handlers = []
164 new_handlers = []
165 for handler in handlers:
165 for handler in handlers:
166 pattern = url_path_join(base_project_url, handler[0])
166 pattern = url_path_join(base_project_url, handler[0])
167 new_handler = tuple([pattern]+list(handler[1:]))
167 new_handler = tuple([pattern]+list(handler[1:]))
168 new_handlers.append( new_handler )
168 new_handlers.append( new_handler )
169
169
170 super(NotebookWebApplication, self).__init__(new_handlers, **settings)
170 super(NotebookWebApplication, self).__init__(new_handlers, **settings)
171
171
172 self.kernel_manager = kernel_manager
172 self.kernel_manager = kernel_manager
173 self.notebook_manager = notebook_manager
173 self.notebook_manager = notebook_manager
174 self.cluster_manager = cluster_manager
174 self.cluster_manager = cluster_manager
175 self.ipython_app = ipython_app
175 self.ipython_app = ipython_app
176 self.read_only = self.ipython_app.read_only
176 self.read_only = self.ipython_app.read_only
177 self.log = log
177 self.log = log
178
178
179
179
180 #-----------------------------------------------------------------------------
180 #-----------------------------------------------------------------------------
181 # Aliases and Flags
181 # Aliases and Flags
182 #-----------------------------------------------------------------------------
182 #-----------------------------------------------------------------------------
183
183
184 flags = dict(ipkernel_flags)
184 flags = dict(ipkernel_flags)
185 flags['no-browser']=(
185 flags['no-browser']=(
186 {'NotebookApp' : {'open_browser' : False}},
186 {'NotebookApp' : {'open_browser' : False}},
187 "Don't open the notebook in a browser after startup."
187 "Don't open the notebook in a browser after startup."
188 )
188 )
189 flags['no-mathjax']=(
189 flags['no-mathjax']=(
190 {'NotebookApp' : {'enable_mathjax' : False}},
190 {'NotebookApp' : {'enable_mathjax' : False}},
191 """Disable MathJax
191 """Disable MathJax
192
192
193 MathJax is the javascript library IPython uses to render math/LaTeX. It is
193 MathJax is the javascript library IPython uses to render math/LaTeX. It is
194 very large, so you may want to disable it if you have a slow internet
194 very large, so you may want to disable it if you have a slow internet
195 connection, or for offline use of the notebook.
195 connection, or for offline use of the notebook.
196
196
197 When disabled, equations etc. will appear as their untransformed TeX source.
197 When disabled, equations etc. will appear as their untransformed TeX source.
198 """
198 """
199 )
199 )
200 flags['read-only'] = (
200 flags['read-only'] = (
201 {'NotebookApp' : {'read_only' : True}},
201 {'NotebookApp' : {'read_only' : True}},
202 """Allow read-only access to notebooks.
202 """Allow read-only access to notebooks.
203
203
204 When using a password to protect the notebook server, this flag
204 When using a password to protect the notebook server, this flag
205 allows unauthenticated clients to view the notebook list, and
205 allows unauthenticated clients to view the notebook list, and
206 individual notebooks, but not edit them, start kernels, or run
206 individual notebooks, but not edit them, start kernels, or run
207 code.
207 code.
208
208
209 If no password is set, the server will be entirely read-only.
209 If no password is set, the server will be entirely read-only.
210 """
210 """
211 )
211 )
212
212
213 # Add notebook manager flags
213 # Add notebook manager flags
214 flags.update(boolean_flag('script', 'NotebookManager.save_script',
214 flags.update(boolean_flag('script', 'NotebookManager.save_script',
215 'Auto-save a .py script everytime the .ipynb notebook is saved',
215 'Auto-save a .py script everytime the .ipynb notebook is saved',
216 'Do not auto-save .py scripts for every notebook'))
216 'Do not auto-save .py scripts for every notebook'))
217
217
218 # the flags that are specific to the frontend
218 # the flags that are specific to the frontend
219 # these must be scrubbed before being passed to the kernel,
219 # these must be scrubbed before being passed to the kernel,
220 # or it will raise an error on unrecognized flags
220 # or it will raise an error on unrecognized flags
221 notebook_flags = ['no-browser', 'no-mathjax', 'read-only', 'script', 'no-script']
221 notebook_flags = ['no-browser', 'no-mathjax', 'read-only', 'script', 'no-script']
222
222
223 aliases = dict(ipkernel_aliases)
223 aliases = dict(ipkernel_aliases)
224
224
225 aliases.update({
225 aliases.update({
226 'ip': 'NotebookApp.ip',
226 'ip': 'NotebookApp.ip',
227 'port': 'NotebookApp.port',
227 'port': 'NotebookApp.port',
228 'port-retries': 'NotebookApp.port_retries',
228 'port-retries': 'NotebookApp.port_retries',
229 'keyfile': 'NotebookApp.keyfile',
229 'keyfile': 'NotebookApp.keyfile',
230 'certfile': 'NotebookApp.certfile',
230 'certfile': 'NotebookApp.certfile',
231 'notebook-dir': 'NotebookManager.notebook_dir',
231 'notebook-dir': 'NotebookManager.notebook_dir',
232 'browser': 'NotebookApp.browser',
232 'browser': 'NotebookApp.browser',
233 })
233 })
234
234
235 # remove ipkernel flags that are singletons, and don't make sense in
235 # remove ipkernel flags that are singletons, and don't make sense in
236 # multi-kernel evironment:
236 # multi-kernel evironment:
237 aliases.pop('f', None)
237 aliases.pop('f', None)
238
238
239 notebook_aliases = [u'port', u'port-retries', u'ip', u'keyfile', u'certfile',
239 notebook_aliases = [u'port', u'port-retries', u'ip', u'keyfile', u'certfile',
240 u'notebook-dir']
240 u'notebook-dir']
241
241
242 #-----------------------------------------------------------------------------
242 #-----------------------------------------------------------------------------
243 # NotebookApp
243 # NotebookApp
244 #-----------------------------------------------------------------------------
244 #-----------------------------------------------------------------------------
245
245
246 class NotebookApp(BaseIPythonApplication):
246 class NotebookApp(BaseIPythonApplication):
247
247
248 name = 'ipython-notebook'
248 name = 'ipython-notebook'
249 default_config_file_name='ipython_notebook_config.py'
249 default_config_file_name='ipython_notebook_config.py'
250
250
251 description = """
251 description = """
252 The IPython HTML Notebook.
252 The IPython HTML Notebook.
253
253
254 This launches a Tornado based HTML Notebook Server that serves up an
254 This launches a Tornado based HTML Notebook Server that serves up an
255 HTML5/Javascript Notebook client.
255 HTML5/Javascript Notebook client.
256 """
256 """
257 examples = _examples
257 examples = _examples
258
258
259 classes = IPythonConsoleApp.classes + [MappingKernelManager, NotebookManager]
259 classes = IPythonConsoleApp.classes + [MappingKernelManager, NotebookManager]
260 flags = Dict(flags)
260 flags = Dict(flags)
261 aliases = Dict(aliases)
261 aliases = Dict(aliases)
262
262
263 kernel_argv = List(Unicode)
263 kernel_argv = List(Unicode)
264
264
265 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
265 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
266 default_value=logging.INFO,
266 default_value=logging.INFO,
267 config=True,
267 config=True,
268 help="Set the log level by value or name.")
268 help="Set the log level by value or name.")
269
269
270 # create requested profiles by default, if they don't exist:
270 # create requested profiles by default, if they don't exist:
271 auto_create = Bool(True)
271 auto_create = Bool(True)
272
272
273 # file to be opened in the notebook server
273 # file to be opened in the notebook server
274 file_to_run = Unicode('')
274 file_to_run = Unicode('')
275
275
276 # Network related information.
276 # Network related information.
277
277
278 ip = Unicode(LOCALHOST, config=True,
278 ip = Unicode(LOCALHOST, config=True,
279 help="The IP address the notebook server will listen on."
279 help="The IP address the notebook server will listen on."
280 )
280 )
281
281
282 def _ip_changed(self, name, old, new):
282 def _ip_changed(self, name, old, new):
283 if new == u'*': self.ip = u''
283 if new == u'*': self.ip = u''
284
284
285 port = Integer(8888, config=True,
285 port = Integer(8888, config=True,
286 help="The port the notebook server will listen on."
286 help="The port the notebook server will listen on."
287 )
287 )
288 port_retries = Integer(50, config=True,
288 port_retries = Integer(50, config=True,
289 help="The number of additional ports to try if the specified port is not available."
289 help="The number of additional ports to try if the specified port is not available."
290 )
290 )
291
291
292 certfile = Unicode(u'', config=True,
292 certfile = Unicode(u'', config=True,
293 help="""The full path to an SSL/TLS certificate file."""
293 help="""The full path to an SSL/TLS certificate file."""
294 )
294 )
295
295
296 keyfile = Unicode(u'', config=True,
296 keyfile = Unicode(u'', config=True,
297 help="""The full path to a private key file for usage with SSL/TLS."""
297 help="""The full path to a private key file for usage with SSL/TLS."""
298 )
298 )
299
299
300 password = Unicode(u'', config=True,
300 password = Unicode(u'', config=True,
301 help="""Hashed password to use for web authentication.
301 help="""Hashed password to use for web authentication.
302
302
303 To generate, type in a python/IPython shell:
303 To generate, type in a python/IPython shell:
304
304
305 from IPython.lib import passwd; passwd()
305 from IPython.lib import passwd; passwd()
306
306
307 The string should be of the form type:salt:hashed-password.
307 The string should be of the form type:salt:hashed-password.
308 """
308 """
309 )
309 )
310
310
311 open_browser = Bool(True, config=True,
311 open_browser = Bool(True, config=True,
312 help="""Whether to open in a browser after starting.
312 help="""Whether to open in a browser after starting.
313 The specific browser used is platform dependent and
313 The specific browser used is platform dependent and
314 determined by the python standard library `webbrowser`
314 determined by the python standard library `webbrowser`
315 module, unless it is overridden using the --browser
315 module, unless it is overridden using the --browser
316 (NotebookApp.browser) configuration option.
316 (NotebookApp.browser) configuration option.
317 """)
317 """)
318
318
319 browser = Unicode(u'', config=True,
319 browser = Unicode(u'', config=True,
320 help="""Specify what command to use to invoke a web
320 help="""Specify what command to use to invoke a web
321 browser when opening the notebook. If not specified, the
321 browser when opening the notebook. If not specified, the
322 default browser will be determined by the `webbrowser`
322 default browser will be determined by the `webbrowser`
323 standard library module, which allows setting of the
323 standard library module, which allows setting of the
324 BROWSER environment variable to override it.
324 BROWSER environment variable to override it.
325 """)
325 """)
326
326
327 read_only = Bool(False, config=True,
327 read_only = Bool(False, config=True,
328 help="Whether to prevent editing/execution of notebooks."
328 help="Whether to prevent editing/execution of notebooks."
329 )
329 )
330
330
331 webapp_settings = Dict(config=True,
331 webapp_settings = Dict(config=True,
332 help="Supply overrides for the tornado.web.Application that the "
332 help="Supply overrides for the tornado.web.Application that the "
333 "IPython notebook uses.")
333 "IPython notebook uses.")
334
334
335 enable_mathjax = Bool(True, config=True,
335 enable_mathjax = Bool(True, config=True,
336 help="""Whether to enable MathJax for typesetting math/TeX
336 help="""Whether to enable MathJax for typesetting math/TeX
337
337
338 MathJax is the javascript library IPython uses to render math/LaTeX. It is
338 MathJax is the javascript library IPython uses to render math/LaTeX. It is
339 very large, so you may want to disable it if you have a slow internet
339 very large, so you may want to disable it if you have a slow internet
340 connection, or for offline use of the notebook.
340 connection, or for offline use of the notebook.
341
341
342 When disabled, equations etc. will appear as their untransformed TeX source.
342 When disabled, equations etc. will appear as their untransformed TeX source.
343 """
343 """
344 )
344 )
345 def _enable_mathjax_changed(self, name, old, new):
345 def _enable_mathjax_changed(self, name, old, new):
346 """set mathjax url to empty if mathjax is disabled"""
346 """set mathjax url to empty if mathjax is disabled"""
347 if not new:
347 if not new:
348 self.mathjax_url = u''
348 self.mathjax_url = u''
349
349
350 base_project_url = Unicode('/', config=True,
350 base_project_url = Unicode('/', config=True,
351 help='''The base URL for the notebook server''')
351 help='''The base URL for the notebook server''')
352 base_kernel_url = Unicode('/', config=True,
352 base_kernel_url = Unicode('/', config=True,
353 help='''The base URL for the kernel server''')
353 help='''The base URL for the kernel server''')
354 websocket_host = Unicode("", config=True,
354 websocket_host = Unicode("", config=True,
355 help="""The hostname for the websocket server."""
355 help="""The hostname for the websocket server."""
356 )
356 )
357
357
358 mathjax_url = Unicode("", config=True,
358 mathjax_url = Unicode("", config=True,
359 help="""The url for MathJax.js."""
359 help="""The url for MathJax.js."""
360 )
360 )
361 def _mathjax_url_default(self):
361 def _mathjax_url_default(self):
362 if not self.enable_mathjax:
362 if not self.enable_mathjax:
363 return u''
363 return u''
364 static_path = self.webapp_settings.get("static_path", os.path.join(os.path.dirname(__file__), "static"))
364 static_path = self.webapp_settings.get("static_path", os.path.join(os.path.dirname(__file__), "static"))
365 static_url_prefix = self.webapp_settings.get("static_url_prefix",
365 static_url_prefix = self.webapp_settings.get("static_url_prefix",
366 "/static/")
366 "/static/")
367 if os.path.exists(os.path.join(static_path, 'mathjax', "MathJax.js")):
367 if os.path.exists(os.path.join(static_path, 'mathjax', "MathJax.js")):
368 self.log.info("Using local MathJax")
368 self.log.info("Using local MathJax")
369 return static_url_prefix+u"mathjax/MathJax.js"
369 return static_url_prefix+u"mathjax/MathJax.js"
370 else:
370 else:
371 if self.certfile:
371 if self.certfile:
372 # HTTPS: load from Rackspace CDN, because SSL certificate requires it
372 # HTTPS: load from Rackspace CDN, because SSL certificate requires it
373 base = u"https://c328740.ssl.cf1.rackcdn.com"
373 base = u"https://c328740.ssl.cf1.rackcdn.com"
374 else:
374 else:
375 base = u"http://cdn.mathjax.org"
375 base = u"http://cdn.mathjax.org"
376
376
377 url = base + u"/mathjax/latest/MathJax.js"
377 url = base + u"/mathjax/latest/MathJax.js"
378 self.log.info("Using MathJax from CDN: %s", url)
378 self.log.info("Using MathJax from CDN: %s", url)
379 return url
379 return url
380
380
381 def _mathjax_url_changed(self, name, old, new):
381 def _mathjax_url_changed(self, name, old, new):
382 if new and not self.enable_mathjax:
382 if new and not self.enable_mathjax:
383 # enable_mathjax=False overrides mathjax_url
383 # enable_mathjax=False overrides mathjax_url
384 self.mathjax_url = u''
384 self.mathjax_url = u''
385 else:
385 else:
386 self.log.info("Using MathJax: %s", new)
386 self.log.info("Using MathJax: %s", new)
387
387
388 def parse_command_line(self, argv=None):
388 def parse_command_line(self, argv=None):
389 super(NotebookApp, self).parse_command_line(argv)
389 super(NotebookApp, self).parse_command_line(argv)
390 if argv is None:
390 if argv is None:
391 argv = sys.argv[1:]
391 argv = sys.argv[1:]
392
392
393 # Scrub frontend-specific flags
393 # Scrub frontend-specific flags
394 self.kernel_argv = swallow_argv(argv, notebook_aliases, notebook_flags)
394 self.kernel_argv = swallow_argv(argv, notebook_aliases, notebook_flags)
395 # Kernel should inherit default config file from frontend
395 # Kernel should inherit default config file from frontend
396 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
396 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
397
397
398 if self.extra_args:
398 if self.extra_args:
399 f = os.path.abspath(self.extra_args[0])
399 f = os.path.abspath(self.extra_args[0])
400 if os.path.isdir(f):
400 if os.path.isdir(f):
401 nbdir = f
401 nbdir = f
402 else:
402 else:
403 self.file_to_run = f
403 self.file_to_run = f
404 nbdir = os.path.dirname(f)
404 nbdir = os.path.dirname(f)
405 self.config.NotebookManager.notebook_dir = nbdir
405 self.config.NotebookManager.notebook_dir = nbdir
406
406
407 def init_configurables(self):
407 def init_configurables(self):
408 # force Session default to be secure
408 # force Session default to be secure
409 default_secure(self.config)
409 default_secure(self.config)
410 self.kernel_manager = MappingKernelManager(
410 self.kernel_manager = MappingKernelManager(
411 config=self.config, log=self.log, kernel_argv=self.kernel_argv,
411 config=self.config, log=self.log, kernel_argv=self.kernel_argv,
412 connection_dir = self.profile_dir.security_dir,
412 connection_dir = self.profile_dir.security_dir,
413 )
413 )
414 self.notebook_manager = NotebookManager(config=self.config, log=self.log)
414 self.notebook_manager = NotebookManager(config=self.config, log=self.log)
415 self.log.info("Serving notebooks from %s", self.notebook_manager.notebook_dir)
415 self.log.info("Serving notebooks from %s", self.notebook_manager.notebook_dir)
416 self.notebook_manager.list_notebooks()
416 self.notebook_manager.list_notebooks()
417 self.cluster_manager = ClusterManager(config=self.config, log=self.log)
417 self.cluster_manager = ClusterManager(config=self.config, log=self.log)
418 self.cluster_manager.update_profiles()
418 self.cluster_manager.update_profiles()
419
419
420 def init_logging(self):
420 def init_logging(self):
421 # This prevents double log messages because tornado use a root logger that
421 # This prevents double log messages because tornado use a root logger that
422 # self.log is a child of. The logging module dipatches log messages to a log
422 # self.log is a child of. The logging module dipatches log messages to a log
423 # and all of its ancenstors until propagate is set to False.
423 # and all of its ancenstors until propagate is set to False.
424 self.log.propagate = False
424 self.log.propagate = False
425
425
426 def init_webapp(self):
426 def init_webapp(self):
427 """initialize tornado webapp and httpserver"""
427 """initialize tornado webapp and httpserver"""
428 self.web_app = NotebookWebApplication(
428 self.web_app = NotebookWebApplication(
429 self, self.kernel_manager, self.notebook_manager,
429 self, self.kernel_manager, self.notebook_manager,
430 self.cluster_manager, self.log,
430 self.cluster_manager, self.log,
431 self.base_project_url, self.webapp_settings
431 self.base_project_url, self.webapp_settings
432 )
432 )
433 if self.certfile:
433 if self.certfile:
434 ssl_options = dict(certfile=self.certfile)
434 ssl_options = dict(certfile=self.certfile)
435 if self.keyfile:
435 if self.keyfile:
436 ssl_options['keyfile'] = self.keyfile
436 ssl_options['keyfile'] = self.keyfile
437 else:
437 else:
438 ssl_options = None
438 ssl_options = None
439 self.web_app.password = self.password
439 self.web_app.password = self.password
440 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options)
440 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options)
441 if ssl_options is None and not self.ip and not (self.read_only and not self.password):
441 if ssl_options is None and not self.ip and not (self.read_only and not self.password):
442 self.log.critical('WARNING: the notebook server is listening on all IP addresses '
442 self.log.critical('WARNING: the notebook server is listening on all IP addresses '
443 'but not using any encryption or authentication. This is highly '
443 'but not using any encryption or authentication. This is highly '
444 'insecure and not recommended.')
444 'insecure and not recommended.')
445
445
446 success = None
446 success = None
447 for port in random_ports(self.port, self.port_retries+1):
447 for port in random_ports(self.port, self.port_retries+1):
448 try:
448 try:
449 self.http_server.listen(port, self.ip)
449 self.http_server.listen(port, self.ip)
450 except socket.error, e:
450 except socket.error as e:
451 if e.errno != errno.EADDRINUSE:
451 if e.errno != errno.EADDRINUSE:
452 raise
452 raise
453 self.log.info('The port %i is already in use, trying another random port.' % port)
453 self.log.info('The port %i is already in use, trying another random port.' % port)
454 else:
454 else:
455 self.port = port
455 self.port = port
456 success = True
456 success = True
457 break
457 break
458 if not success:
458 if not success:
459 self.log.critical('ERROR: the notebook server could not be started because '
459 self.log.critical('ERROR: the notebook server could not be started because '
460 'no available port could be found.')
460 'no available port could be found.')
461 self.exit(1)
461 self.exit(1)
462
462
463 def init_signal(self):
463 def init_signal(self):
464 # FIXME: remove this check when pyzmq dependency is >= 2.1.11
464 # FIXME: remove this check when pyzmq dependency is >= 2.1.11
465 # safely extract zmq version info:
465 # safely extract zmq version info:
466 try:
466 try:
467 zmq_v = zmq.pyzmq_version_info()
467 zmq_v = zmq.pyzmq_version_info()
468 except AttributeError:
468 except AttributeError:
469 zmq_v = [ int(n) for n in re.findall(r'\d+', zmq.__version__) ]
469 zmq_v = [ int(n) for n in re.findall(r'\d+', zmq.__version__) ]
470 if 'dev' in zmq.__version__:
470 if 'dev' in zmq.__version__:
471 zmq_v.append(999)
471 zmq_v.append(999)
472 zmq_v = tuple(zmq_v)
472 zmq_v = tuple(zmq_v)
473 if zmq_v >= (2,1,9) and not sys.platform.startswith('win'):
473 if zmq_v >= (2,1,9) and not sys.platform.startswith('win'):
474 # This won't work with 2.1.7 and
474 # This won't work with 2.1.7 and
475 # 2.1.9-10 will log ugly 'Interrupted system call' messages,
475 # 2.1.9-10 will log ugly 'Interrupted system call' messages,
476 # but it will work
476 # but it will work
477 signal.signal(signal.SIGINT, self._handle_sigint)
477 signal.signal(signal.SIGINT, self._handle_sigint)
478 signal.signal(signal.SIGTERM, self._signal_stop)
478 signal.signal(signal.SIGTERM, self._signal_stop)
479
479
480 def _handle_sigint(self, sig, frame):
480 def _handle_sigint(self, sig, frame):
481 """SIGINT handler spawns confirmation dialog"""
481 """SIGINT handler spawns confirmation dialog"""
482 # register more forceful signal handler for ^C^C case
482 # register more forceful signal handler for ^C^C case
483 signal.signal(signal.SIGINT, self._signal_stop)
483 signal.signal(signal.SIGINT, self._signal_stop)
484 # request confirmation dialog in bg thread, to avoid
484 # request confirmation dialog in bg thread, to avoid
485 # blocking the App
485 # blocking the App
486 thread = threading.Thread(target=self._confirm_exit)
486 thread = threading.Thread(target=self._confirm_exit)
487 thread.daemon = True
487 thread.daemon = True
488 thread.start()
488 thread.start()
489
489
490 def _restore_sigint_handler(self):
490 def _restore_sigint_handler(self):
491 """callback for restoring original SIGINT handler"""
491 """callback for restoring original SIGINT handler"""
492 signal.signal(signal.SIGINT, self._handle_sigint)
492 signal.signal(signal.SIGINT, self._handle_sigint)
493
493
494 def _confirm_exit(self):
494 def _confirm_exit(self):
495 """confirm shutdown on ^C
495 """confirm shutdown on ^C
496
496
497 A second ^C, or answering 'y' within 5s will cause shutdown,
497 A second ^C, or answering 'y' within 5s will cause shutdown,
498 otherwise original SIGINT handler will be restored.
498 otherwise original SIGINT handler will be restored.
499
499
500 This doesn't work on Windows.
500 This doesn't work on Windows.
501 """
501 """
502 # FIXME: remove this delay when pyzmq dependency is >= 2.1.11
502 # FIXME: remove this delay when pyzmq dependency is >= 2.1.11
503 time.sleep(0.1)
503 time.sleep(0.1)
504 sys.stdout.write("Shutdown Notebook Server (y/[n])? ")
504 sys.stdout.write("Shutdown Notebook Server (y/[n])? ")
505 sys.stdout.flush()
505 sys.stdout.flush()
506 r,w,x = select.select([sys.stdin], [], [], 5)
506 r,w,x = select.select([sys.stdin], [], [], 5)
507 if r:
507 if r:
508 line = sys.stdin.readline()
508 line = sys.stdin.readline()
509 if line.lower().startswith('y'):
509 if line.lower().startswith('y'):
510 self.log.critical("Shutdown confirmed")
510 self.log.critical("Shutdown confirmed")
511 ioloop.IOLoop.instance().stop()
511 ioloop.IOLoop.instance().stop()
512 return
512 return
513 else:
513 else:
514 print "No answer for 5s:",
514 print "No answer for 5s:",
515 print "resuming operation..."
515 print "resuming operation..."
516 # no answer, or answer is no:
516 # no answer, or answer is no:
517 # set it back to original SIGINT handler
517 # set it back to original SIGINT handler
518 # use IOLoop.add_callback because signal.signal must be called
518 # use IOLoop.add_callback because signal.signal must be called
519 # from main thread
519 # from main thread
520 ioloop.IOLoop.instance().add_callback(self._restore_sigint_handler)
520 ioloop.IOLoop.instance().add_callback(self._restore_sigint_handler)
521
521
522 def _signal_stop(self, sig, frame):
522 def _signal_stop(self, sig, frame):
523 self.log.critical("received signal %s, stopping", sig)
523 self.log.critical("received signal %s, stopping", sig)
524 ioloop.IOLoop.instance().stop()
524 ioloop.IOLoop.instance().stop()
525
525
526 @catch_config_error
526 @catch_config_error
527 def initialize(self, argv=None):
527 def initialize(self, argv=None):
528 self.init_logging()
528 self.init_logging()
529 super(NotebookApp, self).initialize(argv)
529 super(NotebookApp, self).initialize(argv)
530 self.init_configurables()
530 self.init_configurables()
531 self.init_webapp()
531 self.init_webapp()
532 self.init_signal()
532 self.init_signal()
533
533
534 def cleanup_kernels(self):
534 def cleanup_kernels(self):
535 """shutdown all kernels
535 """shutdown all kernels
536
536
537 The kernels will shutdown themselves when this process no longer exists,
537 The kernels will shutdown themselves when this process no longer exists,
538 but explicit shutdown allows the KernelManagers to cleanup the connection files.
538 but explicit shutdown allows the KernelManagers to cleanup the connection files.
539 """
539 """
540 self.log.info('Shutting down kernels')
540 self.log.info('Shutting down kernels')
541 km = self.kernel_manager
541 km = self.kernel_manager
542 # copy list, since shutdown_kernel deletes keys
542 # copy list, since shutdown_kernel deletes keys
543 for kid in list(km.kernel_ids):
543 for kid in list(km.kernel_ids):
544 km.shutdown_kernel(kid)
544 km.shutdown_kernel(kid)
545
545
546 def start(self):
546 def start(self):
547 ip = self.ip if self.ip else '[all ip addresses on your system]'
547 ip = self.ip if self.ip else '[all ip addresses on your system]'
548 proto = 'https' if self.certfile else 'http'
548 proto = 'https' if self.certfile else 'http'
549 info = self.log.info
549 info = self.log.info
550 info("The IPython Notebook is running at: %s://%s:%i%s" %
550 info("The IPython Notebook is running at: %s://%s:%i%s" %
551 (proto, ip, self.port,self.base_project_url) )
551 (proto, ip, self.port,self.base_project_url) )
552 info("Use Control-C to stop this server and shut down all kernels.")
552 info("Use Control-C to stop this server and shut down all kernels.")
553
553
554 if self.open_browser or self.file_to_run:
554 if self.open_browser or self.file_to_run:
555 ip = self.ip or '127.0.0.1'
555 ip = self.ip or '127.0.0.1'
556 try:
556 try:
557 browser = webbrowser.get(self.browser or None)
557 browser = webbrowser.get(self.browser or None)
558 except webbrowser.Error as e:
558 except webbrowser.Error as e:
559 self.log.warn('No web browser found: %s.' % e)
559 self.log.warn('No web browser found: %s.' % e)
560 browser = None
560 browser = None
561
561
562 if self.file_to_run:
562 if self.file_to_run:
563 filename, _ = os.path.splitext(os.path.basename(self.file_to_run))
563 filename, _ = os.path.splitext(os.path.basename(self.file_to_run))
564 for nb in self.notebook_manager.list_notebooks():
564 for nb in self.notebook_manager.list_notebooks():
565 if filename == nb['name']:
565 if filename == nb['name']:
566 url = nb['notebook_id']
566 url = nb['notebook_id']
567 break
567 break
568 else:
568 else:
569 url = ''
569 url = ''
570 else:
570 else:
571 url = ''
571 url = ''
572 if browser:
572 if browser:
573 b = lambda : browser.open("%s://%s:%i%s%s" % (proto, ip,
573 b = lambda : browser.open("%s://%s:%i%s%s" % (proto, ip,
574 self.port, self.base_project_url, url), new=2)
574 self.port, self.base_project_url, url), new=2)
575 threading.Thread(target=b).start()
575 threading.Thread(target=b).start()
576 try:
576 try:
577 ioloop.IOLoop.instance().start()
577 ioloop.IOLoop.instance().start()
578 except KeyboardInterrupt:
578 except KeyboardInterrupt:
579 info("Interrupted...")
579 info("Interrupted...")
580 finally:
580 finally:
581 self.cleanup_kernels()
581 self.cleanup_kernels()
582
582
583
583
584 #-----------------------------------------------------------------------------
584 #-----------------------------------------------------------------------------
585 # Main entry point
585 # Main entry point
586 #-----------------------------------------------------------------------------
586 #-----------------------------------------------------------------------------
587
587
588 def launch_new_instance():
588 def launch_new_instance():
589 app = NotebookApp.instance()
589 app = NotebookApp.instance()
590 app.initialize()
590 app.initialize()
591 app.start()
591 app.start()
592
592
@@ -1,255 +1,255 b''
1 """ Defines classes and functions for working with Qt's rich text system.
1 """ Defines classes and functions for working with Qt's rich text system.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Imports
4 # Imports
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6
6
7 # Standard library imports.
7 # Standard library imports.
8 import os
8 import os
9 import re
9 import re
10
10
11 # System library imports.
11 # System library imports.
12 from IPython.external.qt import QtGui
12 from IPython.external.qt import QtGui
13
13
14 # IPython imports
14 # IPython imports
15 from IPython.utils import py3compat
15 from IPython.utils import py3compat
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Constants
18 # Constants
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 # A regular expression for an HTML paragraph with no content.
21 # A regular expression for an HTML paragraph with no content.
22 EMPTY_P_RE = re.compile(r'<p[^/>]*>\s*</p>')
22 EMPTY_P_RE = re.compile(r'<p[^/>]*>\s*</p>')
23
23
24 # A regular expression for matching images in rich text HTML.
24 # A regular expression for matching images in rich text HTML.
25 # Note that this is overly restrictive, but Qt's output is predictable...
25 # Note that this is overly restrictive, but Qt's output is predictable...
26 IMG_RE = re.compile(r'<img src="(?P<name>[\d]+)" />')
26 IMG_RE = re.compile(r'<img src="(?P<name>[\d]+)" />')
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Classes
29 # Classes
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 class HtmlExporter(object):
32 class HtmlExporter(object):
33 """ A stateful HTML exporter for a Q(Plain)TextEdit.
33 """ A stateful HTML exporter for a Q(Plain)TextEdit.
34
34
35 This class is designed for convenient user interaction.
35 This class is designed for convenient user interaction.
36 """
36 """
37
37
38 def __init__(self, control):
38 def __init__(self, control):
39 """ Creates an HtmlExporter for the given Q(Plain)TextEdit.
39 """ Creates an HtmlExporter for the given Q(Plain)TextEdit.
40 """
40 """
41 assert isinstance(control, (QtGui.QPlainTextEdit, QtGui.QTextEdit))
41 assert isinstance(control, (QtGui.QPlainTextEdit, QtGui.QTextEdit))
42 self.control = control
42 self.control = control
43 self.filename = 'ipython.html'
43 self.filename = 'ipython.html'
44 self.image_tag = None
44 self.image_tag = None
45 self.inline_png = None
45 self.inline_png = None
46
46
47 def export(self):
47 def export(self):
48 """ Displays a dialog for exporting HTML generated by Qt's rich text
48 """ Displays a dialog for exporting HTML generated by Qt's rich text
49 system.
49 system.
50
50
51 Returns
51 Returns
52 -------
52 -------
53 The name of the file that was saved, or None if no file was saved.
53 The name of the file that was saved, or None if no file was saved.
54 """
54 """
55 parent = self.control.window()
55 parent = self.control.window()
56 dialog = QtGui.QFileDialog(parent, 'Save as...')
56 dialog = QtGui.QFileDialog(parent, 'Save as...')
57 dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
57 dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
58 filters = [
58 filters = [
59 'HTML with PNG figures (*.html *.htm)',
59 'HTML with PNG figures (*.html *.htm)',
60 'XHTML with inline SVG figures (*.xhtml *.xml)'
60 'XHTML with inline SVG figures (*.xhtml *.xml)'
61 ]
61 ]
62 dialog.setNameFilters(filters)
62 dialog.setNameFilters(filters)
63 if self.filename:
63 if self.filename:
64 dialog.selectFile(self.filename)
64 dialog.selectFile(self.filename)
65 root,ext = os.path.splitext(self.filename)
65 root,ext = os.path.splitext(self.filename)
66 if ext.lower() in ('.xml', '.xhtml'):
66 if ext.lower() in ('.xml', '.xhtml'):
67 dialog.selectNameFilter(filters[-1])
67 dialog.selectNameFilter(filters[-1])
68
68
69 if dialog.exec_():
69 if dialog.exec_():
70 self.filename = dialog.selectedFiles()[0]
70 self.filename = dialog.selectedFiles()[0]
71 choice = dialog.selectedNameFilter()
71 choice = dialog.selectedNameFilter()
72 html = self.control.document().toHtml().encode('utf-8')
72 html = self.control.document().toHtml().encode('utf-8')
73
73
74 # Configure the exporter.
74 # Configure the exporter.
75 if choice.startswith('XHTML'):
75 if choice.startswith('XHTML'):
76 exporter = export_xhtml
76 exporter = export_xhtml
77 else:
77 else:
78 # If there are PNGs, decide how to export them.
78 # If there are PNGs, decide how to export them.
79 inline = self.inline_png
79 inline = self.inline_png
80 if inline is None and IMG_RE.search(html):
80 if inline is None and IMG_RE.search(html):
81 dialog = QtGui.QDialog(parent)
81 dialog = QtGui.QDialog(parent)
82 dialog.setWindowTitle('Save as...')
82 dialog.setWindowTitle('Save as...')
83 layout = QtGui.QVBoxLayout(dialog)
83 layout = QtGui.QVBoxLayout(dialog)
84 msg = "Exporting HTML with PNGs"
84 msg = "Exporting HTML with PNGs"
85 info = "Would you like inline PNGs (single large html " \
85 info = "Would you like inline PNGs (single large html " \
86 "file) or external image files?"
86 "file) or external image files?"
87 checkbox = QtGui.QCheckBox("&Don't ask again")
87 checkbox = QtGui.QCheckBox("&Don't ask again")
88 checkbox.setShortcut('D')
88 checkbox.setShortcut('D')
89 ib = QtGui.QPushButton("&Inline")
89 ib = QtGui.QPushButton("&Inline")
90 ib.setShortcut('I')
90 ib.setShortcut('I')
91 eb = QtGui.QPushButton("&External")
91 eb = QtGui.QPushButton("&External")
92 eb.setShortcut('E')
92 eb.setShortcut('E')
93 box = QtGui.QMessageBox(QtGui.QMessageBox.Question,
93 box = QtGui.QMessageBox(QtGui.QMessageBox.Question,
94 dialog.windowTitle(), msg)
94 dialog.windowTitle(), msg)
95 box.setInformativeText(info)
95 box.setInformativeText(info)
96 box.addButton(ib, QtGui.QMessageBox.NoRole)
96 box.addButton(ib, QtGui.QMessageBox.NoRole)
97 box.addButton(eb, QtGui.QMessageBox.YesRole)
97 box.addButton(eb, QtGui.QMessageBox.YesRole)
98 layout.setSpacing(0)
98 layout.setSpacing(0)
99 layout.addWidget(box)
99 layout.addWidget(box)
100 layout.addWidget(checkbox)
100 layout.addWidget(checkbox)
101 dialog.setLayout(layout)
101 dialog.setLayout(layout)
102 dialog.show()
102 dialog.show()
103 reply = box.exec_()
103 reply = box.exec_()
104 dialog.hide()
104 dialog.hide()
105 inline = (reply == 0)
105 inline = (reply == 0)
106 if checkbox.checkState():
106 if checkbox.checkState():
107 # Don't ask anymore; always use this choice.
107 # Don't ask anymore; always use this choice.
108 self.inline_png = inline
108 self.inline_png = inline
109 exporter = lambda h, f, i: export_html(h, f, i, inline)
109 exporter = lambda h, f, i: export_html(h, f, i, inline)
110
110
111 # Perform the export!
111 # Perform the export!
112 try:
112 try:
113 return exporter(html, self.filename, self.image_tag)
113 return exporter(html, self.filename, self.image_tag)
114 except Exception, e:
114 except Exception as e:
115 msg = "Error exporting HTML to %s\n" % self.filename + str(e)
115 msg = "Error exporting HTML to %s\n" % self.filename + str(e)
116 reply = QtGui.QMessageBox.warning(parent, 'Error', msg,
116 reply = QtGui.QMessageBox.warning(parent, 'Error', msg,
117 QtGui.QMessageBox.Ok, QtGui.QMessageBox.Ok)
117 QtGui.QMessageBox.Ok, QtGui.QMessageBox.Ok)
118
118
119 return None
119 return None
120
120
121 #-----------------------------------------------------------------------------
121 #-----------------------------------------------------------------------------
122 # Functions
122 # Functions
123 #-----------------------------------------------------------------------------
123 #-----------------------------------------------------------------------------
124
124
125 def export_html(html, filename, image_tag = None, inline = True):
125 def export_html(html, filename, image_tag = None, inline = True):
126 """ Export the contents of the ConsoleWidget as HTML.
126 """ Export the contents of the ConsoleWidget as HTML.
127
127
128 Parameters:
128 Parameters:
129 -----------
129 -----------
130 html : str,
130 html : str,
131 A utf-8 encoded Python string containing the Qt HTML to export.
131 A utf-8 encoded Python string containing the Qt HTML to export.
132
132
133 filename : str
133 filename : str
134 The file to be saved.
134 The file to be saved.
135
135
136 image_tag : callable, optional (default None)
136 image_tag : callable, optional (default None)
137 Used to convert images. See ``default_image_tag()`` for information.
137 Used to convert images. See ``default_image_tag()`` for information.
138
138
139 inline : bool, optional [default True]
139 inline : bool, optional [default True]
140 If True, include images as inline PNGs. Otherwise, include them as
140 If True, include images as inline PNGs. Otherwise, include them as
141 links to external PNG files, mimicking web browsers' "Web Page,
141 links to external PNG files, mimicking web browsers' "Web Page,
142 Complete" behavior.
142 Complete" behavior.
143 """
143 """
144 if image_tag is None:
144 if image_tag is None:
145 image_tag = default_image_tag
145 image_tag = default_image_tag
146 else:
146 else:
147 image_tag = ensure_utf8(image_tag)
147 image_tag = ensure_utf8(image_tag)
148
148
149 if inline:
149 if inline:
150 path = None
150 path = None
151 else:
151 else:
152 root,ext = os.path.splitext(filename)
152 root,ext = os.path.splitext(filename)
153 path = root + "_files"
153 path = root + "_files"
154 if os.path.isfile(path):
154 if os.path.isfile(path):
155 raise OSError("%s exists, but is not a directory." % path)
155 raise OSError("%s exists, but is not a directory." % path)
156
156
157 with open(filename, 'w') as f:
157 with open(filename, 'w') as f:
158 html = fix_html(html)
158 html = fix_html(html)
159 f.write(IMG_RE.sub(lambda x: image_tag(x, path = path, format = "png"),
159 f.write(IMG_RE.sub(lambda x: image_tag(x, path = path, format = "png"),
160 html))
160 html))
161
161
162
162
163 def export_xhtml(html, filename, image_tag=None):
163 def export_xhtml(html, filename, image_tag=None):
164 """ Export the contents of the ConsoleWidget as XHTML with inline SVGs.
164 """ Export the contents of the ConsoleWidget as XHTML with inline SVGs.
165
165
166 Parameters:
166 Parameters:
167 -----------
167 -----------
168 html : str,
168 html : str,
169 A utf-8 encoded Python string containing the Qt HTML to export.
169 A utf-8 encoded Python string containing the Qt HTML to export.
170
170
171 filename : str
171 filename : str
172 The file to be saved.
172 The file to be saved.
173
173
174 image_tag : callable, optional (default None)
174 image_tag : callable, optional (default None)
175 Used to convert images. See ``default_image_tag()`` for information.
175 Used to convert images. See ``default_image_tag()`` for information.
176 """
176 """
177 if image_tag is None:
177 if image_tag is None:
178 image_tag = default_image_tag
178 image_tag = default_image_tag
179 else:
179 else:
180 image_tag = ensure_utf8(image_tag)
180 image_tag = ensure_utf8(image_tag)
181
181
182 with open(filename, 'w') as f:
182 with open(filename, 'w') as f:
183 # Hack to make xhtml header -- note that we are not doing any check for
183 # Hack to make xhtml header -- note that we are not doing any check for
184 # valid XML.
184 # valid XML.
185 offset = html.find("<html>")
185 offset = html.find("<html>")
186 assert offset > -1, 'Invalid HTML string: no <html> tag.'
186 assert offset > -1, 'Invalid HTML string: no <html> tag.'
187 html = ('<html xmlns="http://www.w3.org/1999/xhtml">\n'+
187 html = ('<html xmlns="http://www.w3.org/1999/xhtml">\n'+
188 html[offset+6:])
188 html[offset+6:])
189
189
190 html = fix_html(html)
190 html = fix_html(html)
191 f.write(IMG_RE.sub(lambda x: image_tag(x, path = None, format = "svg"),
191 f.write(IMG_RE.sub(lambda x: image_tag(x, path = None, format = "svg"),
192 html))
192 html))
193
193
194
194
195 def default_image_tag(match, path = None, format = "png"):
195 def default_image_tag(match, path = None, format = "png"):
196 """ Return (X)HTML mark-up for the image-tag given by match.
196 """ Return (X)HTML mark-up for the image-tag given by match.
197
197
198 This default implementation merely removes the image, and exists mostly
198 This default implementation merely removes the image, and exists mostly
199 for documentation purposes. More information than is present in the Qt
199 for documentation purposes. More information than is present in the Qt
200 HTML is required to supply the images.
200 HTML is required to supply the images.
201
201
202 Parameters
202 Parameters
203 ----------
203 ----------
204 match : re.SRE_Match
204 match : re.SRE_Match
205 A match to an HTML image tag as exported by Qt, with match.group("Name")
205 A match to an HTML image tag as exported by Qt, with match.group("Name")
206 containing the matched image ID.
206 containing the matched image ID.
207
207
208 path : string|None, optional [default None]
208 path : string|None, optional [default None]
209 If not None, specifies a path to which supporting files may be written
209 If not None, specifies a path to which supporting files may be written
210 (e.g., for linked images). If None, all images are to be included
210 (e.g., for linked images). If None, all images are to be included
211 inline.
211 inline.
212
212
213 format : "png"|"svg", optional [default "png"]
213 format : "png"|"svg", optional [default "png"]
214 Format for returned or referenced images.
214 Format for returned or referenced images.
215 """
215 """
216 return ''
216 return ''
217
217
218
218
219 def ensure_utf8(image_tag):
219 def ensure_utf8(image_tag):
220 """wrapper for ensuring image_tag returns utf8-encoded str on Python 2"""
220 """wrapper for ensuring image_tag returns utf8-encoded str on Python 2"""
221 if py3compat.PY3:
221 if py3compat.PY3:
222 # nothing to do on Python 3
222 # nothing to do on Python 3
223 return image_tag
223 return image_tag
224
224
225 def utf8_image_tag(*args, **kwargs):
225 def utf8_image_tag(*args, **kwargs):
226 s = image_tag(*args, **kwargs)
226 s = image_tag(*args, **kwargs)
227 if isinstance(s, unicode):
227 if isinstance(s, unicode):
228 s = s.encode('utf8')
228 s = s.encode('utf8')
229 return s
229 return s
230 return utf8_image_tag
230 return utf8_image_tag
231
231
232
232
233 def fix_html(html):
233 def fix_html(html):
234 """ Transforms a Qt-generated HTML string into a standards-compliant one.
234 """ Transforms a Qt-generated HTML string into a standards-compliant one.
235
235
236 Parameters:
236 Parameters:
237 -----------
237 -----------
238 html : str,
238 html : str,
239 A utf-8 encoded Python string containing the Qt HTML.
239 A utf-8 encoded Python string containing the Qt HTML.
240 """
240 """
241 # A UTF-8 declaration is needed for proper rendering of some characters
241 # A UTF-8 declaration is needed for proper rendering of some characters
242 # (e.g., indented commands) when viewing exported HTML on a local system
242 # (e.g., indented commands) when viewing exported HTML on a local system
243 # (i.e., without seeing an encoding declaration in an HTTP header).
243 # (i.e., without seeing an encoding declaration in an HTTP header).
244 # C.f. http://www.w3.org/International/O-charset for details.
244 # C.f. http://www.w3.org/International/O-charset for details.
245 offset = html.find('<head>')
245 offset = html.find('<head>')
246 if offset > -1:
246 if offset > -1:
247 html = (html[:offset+6]+
247 html = (html[:offset+6]+
248 '\n<meta http-equiv="Content-Type" '+
248 '\n<meta http-equiv="Content-Type" '+
249 'content="text/html; charset=utf-8" />\n'+
249 'content="text/html; charset=utf-8" />\n'+
250 html[offset+6:])
250 html[offset+6:])
251
251
252 # Replace empty paragraphs tags with line breaks.
252 # Replace empty paragraphs tags with line breaks.
253 html = re.sub(EMPTY_P_RE, '<br/>', html)
253 html = re.sub(EMPTY_P_RE, '<br/>', html)
254
254
255 return html
255 return html
@@ -1,734 +1,734 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 pretty
3 pretty
4 ~~
4 ~~
5
5
6 Python advanced pretty printer. This pretty printer is intended to
6 Python advanced pretty printer. This pretty printer is intended to
7 replace the old `pprint` python module which does not allow developers
7 replace the old `pprint` python module which does not allow developers
8 to provide their own pretty print callbacks.
8 to provide their own pretty print callbacks.
9
9
10 This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`.
10 This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`.
11
11
12
12
13 Example Usage
13 Example Usage
14 =============
14 =============
15
15
16 To directly print the representation of an object use `pprint`::
16 To directly print the representation of an object use `pprint`::
17
17
18 from pretty import pprint
18 from pretty import pprint
19 pprint(complex_object)
19 pprint(complex_object)
20
20
21 To get a string of the output use `pretty`::
21 To get a string of the output use `pretty`::
22
22
23 from pretty import pretty
23 from pretty import pretty
24 string = pretty(complex_object)
24 string = pretty(complex_object)
25
25
26
26
27 Extending
27 Extending
28 =========
28 =========
29
29
30 The pretty library allows developers to add pretty printing rules for their
30 The pretty library allows developers to add pretty printing rules for their
31 own objects. This process is straightforward. All you have to do is to
31 own objects. This process is straightforward. All you have to do is to
32 add a `_repr_pretty_` method to your object and call the methods on the
32 add a `_repr_pretty_` method to your object and call the methods on the
33 pretty printer passed::
33 pretty printer passed::
34
34
35 class MyObject(object):
35 class MyObject(object):
36
36
37 def _repr_pretty_(self, p, cycle):
37 def _repr_pretty_(self, p, cycle):
38 ...
38 ...
39
39
40 Depending on the python version you want to support you have two
40 Depending on the python version you want to support you have two
41 possibilities. The following list shows the python 2.5 version and the
41 possibilities. The following list shows the python 2.5 version and the
42 compatibility one.
42 compatibility one.
43
43
44
44
45 Here the example implementation of a `_repr_pretty_` method for a list
45 Here the example implementation of a `_repr_pretty_` method for a list
46 subclass for python 2.5 and higher (python 2.5 requires the with statement
46 subclass for python 2.5 and higher (python 2.5 requires the with statement
47 __future__ import)::
47 __future__ import)::
48
48
49 class MyList(list):
49 class MyList(list):
50
50
51 def _repr_pretty_(self, p, cycle):
51 def _repr_pretty_(self, p, cycle):
52 if cycle:
52 if cycle:
53 p.text('MyList(...)')
53 p.text('MyList(...)')
54 else:
54 else:
55 with p.group(8, 'MyList([', '])'):
55 with p.group(8, 'MyList([', '])'):
56 for idx, item in enumerate(self):
56 for idx, item in enumerate(self):
57 if idx:
57 if idx:
58 p.text(',')
58 p.text(',')
59 p.breakable()
59 p.breakable()
60 p.pretty(item)
60 p.pretty(item)
61
61
62 The `cycle` parameter is `True` if pretty detected a cycle. You *have* to
62 The `cycle` parameter is `True` if pretty detected a cycle. You *have* to
63 react to that or the result is an infinite loop. `p.text()` just adds
63 react to that or the result is an infinite loop. `p.text()` just adds
64 non breaking text to the output, `p.breakable()` either adds a whitespace
64 non breaking text to the output, `p.breakable()` either adds a whitespace
65 or breaks here. If you pass it an argument it's used instead of the
65 or breaks here. If you pass it an argument it's used instead of the
66 default space. `p.pretty` prettyprints another object using the pretty print
66 default space. `p.pretty` prettyprints another object using the pretty print
67 method.
67 method.
68
68
69 The first parameter to the `group` function specifies the extra indentation
69 The first parameter to the `group` function specifies the extra indentation
70 of the next line. In this example the next item will either be not
70 of the next line. In this example the next item will either be not
71 breaked (if the items are short enough) or aligned with the right edge of
71 breaked (if the items are short enough) or aligned with the right edge of
72 the opening bracked of `MyList`.
72 the opening bracked of `MyList`.
73
73
74 If you want to support python 2.4 and lower you can use this code::
74 If you want to support python 2.4 and lower you can use this code::
75
75
76 class MyList(list):
76 class MyList(list):
77
77
78 def _repr_pretty_(self, p, cycle):
78 def _repr_pretty_(self, p, cycle):
79 if cycle:
79 if cycle:
80 p.text('MyList(...)')
80 p.text('MyList(...)')
81 else:
81 else:
82 p.begin_group(8, 'MyList([')
82 p.begin_group(8, 'MyList([')
83 for idx, item in enumerate(self):
83 for idx, item in enumerate(self):
84 if idx:
84 if idx:
85 p.text(',')
85 p.text(',')
86 p.breakable()
86 p.breakable()
87 p.pretty(item)
87 p.pretty(item)
88 p.end_group(8, '])')
88 p.end_group(8, '])')
89
89
90 If you just want to indent something you can use the group function
90 If you just want to indent something you can use the group function
91 without open / close parameters. Under python 2.5 you can also use this
91 without open / close parameters. Under python 2.5 you can also use this
92 code::
92 code::
93
93
94 with p.indent(2):
94 with p.indent(2):
95 ...
95 ...
96
96
97 Or under python2.4 you might want to modify ``p.indentation`` by hand but
97 Or under python2.4 you might want to modify ``p.indentation`` by hand but
98 this is rather ugly.
98 this is rather ugly.
99
99
100 :copyright: 2007 by Armin Ronacher.
100 :copyright: 2007 by Armin Ronacher.
101 Portions (c) 2009 by Robert Kern.
101 Portions (c) 2009 by Robert Kern.
102 :license: BSD License.
102 :license: BSD License.
103 """
103 """
104 from __future__ import with_statement
104 from __future__ import with_statement
105 from contextlib import contextmanager
105 from contextlib import contextmanager
106 import sys
106 import sys
107 import types
107 import types
108 import re
108 import re
109 import datetime
109 import datetime
110 from StringIO import StringIO
110 from StringIO import StringIO
111 from collections import deque
111 from collections import deque
112
112
113
113
114 __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
114 __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
115 'for_type', 'for_type_by_name']
115 'for_type', 'for_type_by_name']
116
116
117
117
118 _re_pattern_type = type(re.compile(''))
118 _re_pattern_type = type(re.compile(''))
119
119
120
120
121 def pretty(obj, verbose=False, max_width=79, newline='\n'):
121 def pretty(obj, verbose=False, max_width=79, newline='\n'):
122 """
122 """
123 Pretty print the object's representation.
123 Pretty print the object's representation.
124 """
124 """
125 stream = StringIO()
125 stream = StringIO()
126 printer = RepresentationPrinter(stream, verbose, max_width, newline)
126 printer = RepresentationPrinter(stream, verbose, max_width, newline)
127 printer.pretty(obj)
127 printer.pretty(obj)
128 printer.flush()
128 printer.flush()
129 return stream.getvalue()
129 return stream.getvalue()
130
130
131
131
132 def pprint(obj, verbose=False, max_width=79, newline='\n'):
132 def pprint(obj, verbose=False, max_width=79, newline='\n'):
133 """
133 """
134 Like `pretty` but print to stdout.
134 Like `pretty` but print to stdout.
135 """
135 """
136 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline)
136 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline)
137 printer.pretty(obj)
137 printer.pretty(obj)
138 printer.flush()
138 printer.flush()
139 sys.stdout.write(newline)
139 sys.stdout.write(newline)
140 sys.stdout.flush()
140 sys.stdout.flush()
141
141
142 class _PrettyPrinterBase(object):
142 class _PrettyPrinterBase(object):
143
143
144 @contextmanager
144 @contextmanager
145 def indent(self, indent):
145 def indent(self, indent):
146 """with statement support for indenting/dedenting."""
146 """with statement support for indenting/dedenting."""
147 self.indentation += indent
147 self.indentation += indent
148 try:
148 try:
149 yield
149 yield
150 finally:
150 finally:
151 self.indentation -= indent
151 self.indentation -= indent
152
152
153 @contextmanager
153 @contextmanager
154 def group(self, indent=0, open='', close=''):
154 def group(self, indent=0, open='', close=''):
155 """like begin_group / end_group but for the with statement."""
155 """like begin_group / end_group but for the with statement."""
156 self.begin_group(indent, open)
156 self.begin_group(indent, open)
157 try:
157 try:
158 yield
158 yield
159 finally:
159 finally:
160 self.end_group(indent, close)
160 self.end_group(indent, close)
161
161
162 class PrettyPrinter(_PrettyPrinterBase):
162 class PrettyPrinter(_PrettyPrinterBase):
163 """
163 """
164 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
164 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
165 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
165 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
166 this printer knows nothing about the default pprinters or the `_repr_pretty_`
166 this printer knows nothing about the default pprinters or the `_repr_pretty_`
167 callback method.
167 callback method.
168 """
168 """
169
169
170 def __init__(self, output, max_width=79, newline='\n'):
170 def __init__(self, output, max_width=79, newline='\n'):
171 self.output = output
171 self.output = output
172 self.max_width = max_width
172 self.max_width = max_width
173 self.newline = newline
173 self.newline = newline
174 self.output_width = 0
174 self.output_width = 0
175 self.buffer_width = 0
175 self.buffer_width = 0
176 self.buffer = deque()
176 self.buffer = deque()
177
177
178 root_group = Group(0)
178 root_group = Group(0)
179 self.group_stack = [root_group]
179 self.group_stack = [root_group]
180 self.group_queue = GroupQueue(root_group)
180 self.group_queue = GroupQueue(root_group)
181 self.indentation = 0
181 self.indentation = 0
182
182
183 def _break_outer_groups(self):
183 def _break_outer_groups(self):
184 while self.max_width < self.output_width + self.buffer_width:
184 while self.max_width < self.output_width + self.buffer_width:
185 group = self.group_queue.deq()
185 group = self.group_queue.deq()
186 if not group:
186 if not group:
187 return
187 return
188 while group.breakables:
188 while group.breakables:
189 x = self.buffer.popleft()
189 x = self.buffer.popleft()
190 self.output_width = x.output(self.output, self.output_width)
190 self.output_width = x.output(self.output, self.output_width)
191 self.buffer_width -= x.width
191 self.buffer_width -= x.width
192 while self.buffer and isinstance(self.buffer[0], Text):
192 while self.buffer and isinstance(self.buffer[0], Text):
193 x = self.buffer.popleft()
193 x = self.buffer.popleft()
194 self.output_width = x.output(self.output, self.output_width)
194 self.output_width = x.output(self.output, self.output_width)
195 self.buffer_width -= x.width
195 self.buffer_width -= x.width
196
196
197 def text(self, obj):
197 def text(self, obj):
198 """Add literal text to the output."""
198 """Add literal text to the output."""
199 width = len(obj)
199 width = len(obj)
200 if self.buffer:
200 if self.buffer:
201 text = self.buffer[-1]
201 text = self.buffer[-1]
202 if not isinstance(text, Text):
202 if not isinstance(text, Text):
203 text = Text()
203 text = Text()
204 self.buffer.append(text)
204 self.buffer.append(text)
205 text.add(obj, width)
205 text.add(obj, width)
206 self.buffer_width += width
206 self.buffer_width += width
207 self._break_outer_groups()
207 self._break_outer_groups()
208 else:
208 else:
209 self.output.write(obj)
209 self.output.write(obj)
210 self.output_width += width
210 self.output_width += width
211
211
212 def breakable(self, sep=' '):
212 def breakable(self, sep=' '):
213 """
213 """
214 Add a breakable separator to the output. This does not mean that it
214 Add a breakable separator to the output. This does not mean that it
215 will automatically break here. If no breaking on this position takes
215 will automatically break here. If no breaking on this position takes
216 place the `sep` is inserted which default to one space.
216 place the `sep` is inserted which default to one space.
217 """
217 """
218 width = len(sep)
218 width = len(sep)
219 group = self.group_stack[-1]
219 group = self.group_stack[-1]
220 if group.want_break:
220 if group.want_break:
221 self.flush()
221 self.flush()
222 self.output.write(self.newline)
222 self.output.write(self.newline)
223 self.output.write(' ' * self.indentation)
223 self.output.write(' ' * self.indentation)
224 self.output_width = self.indentation
224 self.output_width = self.indentation
225 self.buffer_width = 0
225 self.buffer_width = 0
226 else:
226 else:
227 self.buffer.append(Breakable(sep, width, self))
227 self.buffer.append(Breakable(sep, width, self))
228 self.buffer_width += width
228 self.buffer_width += width
229 self._break_outer_groups()
229 self._break_outer_groups()
230
230
231
231
232 def begin_group(self, indent=0, open=''):
232 def begin_group(self, indent=0, open=''):
233 """
233 """
234 Begin a group. If you want support for python < 2.5 which doesn't has
234 Begin a group. If you want support for python < 2.5 which doesn't has
235 the with statement this is the preferred way:
235 the with statement this is the preferred way:
236
236
237 p.begin_group(1, '{')
237 p.begin_group(1, '{')
238 ...
238 ...
239 p.end_group(1, '}')
239 p.end_group(1, '}')
240
240
241 The python 2.5 expression would be this:
241 The python 2.5 expression would be this:
242
242
243 with p.group(1, '{', '}'):
243 with p.group(1, '{', '}'):
244 ...
244 ...
245
245
246 The first parameter specifies the indentation for the next line (usually
246 The first parameter specifies the indentation for the next line (usually
247 the width of the opening text), the second the opening text. All
247 the width of the opening text), the second the opening text. All
248 parameters are optional.
248 parameters are optional.
249 """
249 """
250 if open:
250 if open:
251 self.text(open)
251 self.text(open)
252 group = Group(self.group_stack[-1].depth + 1)
252 group = Group(self.group_stack[-1].depth + 1)
253 self.group_stack.append(group)
253 self.group_stack.append(group)
254 self.group_queue.enq(group)
254 self.group_queue.enq(group)
255 self.indentation += indent
255 self.indentation += indent
256
256
257 def end_group(self, dedent=0, close=''):
257 def end_group(self, dedent=0, close=''):
258 """End a group. See `begin_group` for more details."""
258 """End a group. See `begin_group` for more details."""
259 self.indentation -= dedent
259 self.indentation -= dedent
260 group = self.group_stack.pop()
260 group = self.group_stack.pop()
261 if not group.breakables:
261 if not group.breakables:
262 self.group_queue.remove(group)
262 self.group_queue.remove(group)
263 if close:
263 if close:
264 self.text(close)
264 self.text(close)
265
265
266 def flush(self):
266 def flush(self):
267 """Flush data that is left in the buffer."""
267 """Flush data that is left in the buffer."""
268 for data in self.buffer:
268 for data in self.buffer:
269 self.output_width += data.output(self.output, self.output_width)
269 self.output_width += data.output(self.output, self.output_width)
270 self.buffer.clear()
270 self.buffer.clear()
271 self.buffer_width = 0
271 self.buffer_width = 0
272
272
273
273
274 def _get_mro(obj_class):
274 def _get_mro(obj_class):
275 """ Get a reasonable method resolution order of a class and its superclasses
275 """ Get a reasonable method resolution order of a class and its superclasses
276 for both old-style and new-style classes.
276 for both old-style and new-style classes.
277 """
277 """
278 if not hasattr(obj_class, '__mro__'):
278 if not hasattr(obj_class, '__mro__'):
279 # Old-style class. Mix in object to make a fake new-style class.
279 # Old-style class. Mix in object to make a fake new-style class.
280 try:
280 try:
281 obj_class = type(obj_class.__name__, (obj_class, object), {})
281 obj_class = type(obj_class.__name__, (obj_class, object), {})
282 except TypeError:
282 except TypeError:
283 # Old-style extension type that does not descend from object.
283 # Old-style extension type that does not descend from object.
284 # FIXME: try to construct a more thorough MRO.
284 # FIXME: try to construct a more thorough MRO.
285 mro = [obj_class]
285 mro = [obj_class]
286 else:
286 else:
287 mro = obj_class.__mro__[1:-1]
287 mro = obj_class.__mro__[1:-1]
288 else:
288 else:
289 mro = obj_class.__mro__
289 mro = obj_class.__mro__
290 return mro
290 return mro
291
291
292
292
293 class RepresentationPrinter(PrettyPrinter):
293 class RepresentationPrinter(PrettyPrinter):
294 """
294 """
295 Special pretty printer that has a `pretty` method that calls the pretty
295 Special pretty printer that has a `pretty` method that calls the pretty
296 printer for a python object.
296 printer for a python object.
297
297
298 This class stores processing data on `self` so you must *never* use
298 This class stores processing data on `self` so you must *never* use
299 this class in a threaded environment. Always lock it or reinstanciate
299 this class in a threaded environment. Always lock it or reinstanciate
300 it.
300 it.
301
301
302 Instances also have a verbose flag callbacks can access to control their
302 Instances also have a verbose flag callbacks can access to control their
303 output. For example the default instance repr prints all attributes and
303 output. For example the default instance repr prints all attributes and
304 methods that are not prefixed by an underscore if the printer is in
304 methods that are not prefixed by an underscore if the printer is in
305 verbose mode.
305 verbose mode.
306 """
306 """
307
307
308 def __init__(self, output, verbose=False, max_width=79, newline='\n',
308 def __init__(self, output, verbose=False, max_width=79, newline='\n',
309 singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None):
309 singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None):
310
310
311 PrettyPrinter.__init__(self, output, max_width, newline)
311 PrettyPrinter.__init__(self, output, max_width, newline)
312 self.verbose = verbose
312 self.verbose = verbose
313 self.stack = []
313 self.stack = []
314 if singleton_pprinters is None:
314 if singleton_pprinters is None:
315 singleton_pprinters = _singleton_pprinters.copy()
315 singleton_pprinters = _singleton_pprinters.copy()
316 self.singleton_pprinters = singleton_pprinters
316 self.singleton_pprinters = singleton_pprinters
317 if type_pprinters is None:
317 if type_pprinters is None:
318 type_pprinters = _type_pprinters.copy()
318 type_pprinters = _type_pprinters.copy()
319 self.type_pprinters = type_pprinters
319 self.type_pprinters = type_pprinters
320 if deferred_pprinters is None:
320 if deferred_pprinters is None:
321 deferred_pprinters = _deferred_type_pprinters.copy()
321 deferred_pprinters = _deferred_type_pprinters.copy()
322 self.deferred_pprinters = deferred_pprinters
322 self.deferred_pprinters = deferred_pprinters
323
323
324 def pretty(self, obj):
324 def pretty(self, obj):
325 """Pretty print the given object."""
325 """Pretty print the given object."""
326 obj_id = id(obj)
326 obj_id = id(obj)
327 cycle = obj_id in self.stack
327 cycle = obj_id in self.stack
328 self.stack.append(obj_id)
328 self.stack.append(obj_id)
329 self.begin_group()
329 self.begin_group()
330 try:
330 try:
331 obj_class = getattr(obj, '__class__', None) or type(obj)
331 obj_class = getattr(obj, '__class__', None) or type(obj)
332 # First try to find registered singleton printers for the type.
332 # First try to find registered singleton printers for the type.
333 try:
333 try:
334 printer = self.singleton_pprinters[obj_id]
334 printer = self.singleton_pprinters[obj_id]
335 except (TypeError, KeyError):
335 except (TypeError, KeyError):
336 pass
336 pass
337 else:
337 else:
338 return printer(obj, self, cycle)
338 return printer(obj, self, cycle)
339 # Next walk the mro and check for either:
339 # Next walk the mro and check for either:
340 # 1) a registered printer
340 # 1) a registered printer
341 # 2) a _repr_pretty_ method
341 # 2) a _repr_pretty_ method
342 for cls in _get_mro(obj_class):
342 for cls in _get_mro(obj_class):
343 if cls in self.type_pprinters:
343 if cls in self.type_pprinters:
344 # printer registered in self.type_pprinters
344 # printer registered in self.type_pprinters
345 return self.type_pprinters[cls](obj, self, cycle)
345 return self.type_pprinters[cls](obj, self, cycle)
346 else:
346 else:
347 # deferred printer
347 # deferred printer
348 printer = self._in_deferred_types(cls)
348 printer = self._in_deferred_types(cls)
349 if printer is not None:
349 if printer is not None:
350 return printer(obj, self, cycle)
350 return printer(obj, self, cycle)
351 else:
351 else:
352 # Finally look for special method names.
352 # Finally look for special method names.
353 # Some objects automatically create any requested
353 # Some objects automatically create any requested
354 # attribute. Try to ignore most of them by checking for
354 # attribute. Try to ignore most of them by checking for
355 # callability.
355 # callability.
356 if '_repr_pretty_' in obj_class.__dict__:
356 if '_repr_pretty_' in obj_class.__dict__:
357 meth = obj_class._repr_pretty_
357 meth = obj_class._repr_pretty_
358 if callable(meth):
358 if callable(meth):
359 return meth(obj, self, cycle)
359 return meth(obj, self, cycle)
360 return _default_pprint(obj, self, cycle)
360 return _default_pprint(obj, self, cycle)
361 finally:
361 finally:
362 self.end_group()
362 self.end_group()
363 self.stack.pop()
363 self.stack.pop()
364
364
365 def _in_deferred_types(self, cls):
365 def _in_deferred_types(self, cls):
366 """
366 """
367 Check if the given class is specified in the deferred type registry.
367 Check if the given class is specified in the deferred type registry.
368
368
369 Returns the printer from the registry if it exists, and None if the
369 Returns the printer from the registry if it exists, and None if the
370 class is not in the registry. Successful matches will be moved to the
370 class is not in the registry. Successful matches will be moved to the
371 regular type registry for future use.
371 regular type registry for future use.
372 """
372 """
373 mod = getattr(cls, '__module__', None)
373 mod = getattr(cls, '__module__', None)
374 name = getattr(cls, '__name__', None)
374 name = getattr(cls, '__name__', None)
375 key = (mod, name)
375 key = (mod, name)
376 printer = None
376 printer = None
377 if key in self.deferred_pprinters:
377 if key in self.deferred_pprinters:
378 # Move the printer over to the regular registry.
378 # Move the printer over to the regular registry.
379 printer = self.deferred_pprinters.pop(key)
379 printer = self.deferred_pprinters.pop(key)
380 self.type_pprinters[cls] = printer
380 self.type_pprinters[cls] = printer
381 return printer
381 return printer
382
382
383
383
384 class Printable(object):
384 class Printable(object):
385
385
386 def output(self, stream, output_width):
386 def output(self, stream, output_width):
387 return output_width
387 return output_width
388
388
389
389
390 class Text(Printable):
390 class Text(Printable):
391
391
392 def __init__(self):
392 def __init__(self):
393 self.objs = []
393 self.objs = []
394 self.width = 0
394 self.width = 0
395
395
396 def output(self, stream, output_width):
396 def output(self, stream, output_width):
397 for obj in self.objs:
397 for obj in self.objs:
398 stream.write(obj)
398 stream.write(obj)
399 return output_width + self.width
399 return output_width + self.width
400
400
401 def add(self, obj, width):
401 def add(self, obj, width):
402 self.objs.append(obj)
402 self.objs.append(obj)
403 self.width += width
403 self.width += width
404
404
405
405
406 class Breakable(Printable):
406 class Breakable(Printable):
407
407
408 def __init__(self, seq, width, pretty):
408 def __init__(self, seq, width, pretty):
409 self.obj = seq
409 self.obj = seq
410 self.width = width
410 self.width = width
411 self.pretty = pretty
411 self.pretty = pretty
412 self.indentation = pretty.indentation
412 self.indentation = pretty.indentation
413 self.group = pretty.group_stack[-1]
413 self.group = pretty.group_stack[-1]
414 self.group.breakables.append(self)
414 self.group.breakables.append(self)
415
415
416 def output(self, stream, output_width):
416 def output(self, stream, output_width):
417 self.group.breakables.popleft()
417 self.group.breakables.popleft()
418 if self.group.want_break:
418 if self.group.want_break:
419 stream.write(self.pretty.newline)
419 stream.write(self.pretty.newline)
420 stream.write(' ' * self.indentation)
420 stream.write(' ' * self.indentation)
421 return self.indentation
421 return self.indentation
422 if not self.group.breakables:
422 if not self.group.breakables:
423 self.pretty.group_queue.remove(self.group)
423 self.pretty.group_queue.remove(self.group)
424 stream.write(self.obj)
424 stream.write(self.obj)
425 return output_width + self.width
425 return output_width + self.width
426
426
427
427
428 class Group(Printable):
428 class Group(Printable):
429
429
430 def __init__(self, depth):
430 def __init__(self, depth):
431 self.depth = depth
431 self.depth = depth
432 self.breakables = deque()
432 self.breakables = deque()
433 self.want_break = False
433 self.want_break = False
434
434
435
435
436 class GroupQueue(object):
436 class GroupQueue(object):
437
437
438 def __init__(self, *groups):
438 def __init__(self, *groups):
439 self.queue = []
439 self.queue = []
440 for group in groups:
440 for group in groups:
441 self.enq(group)
441 self.enq(group)
442
442
443 def enq(self, group):
443 def enq(self, group):
444 depth = group.depth
444 depth = group.depth
445 while depth > len(self.queue) - 1:
445 while depth > len(self.queue) - 1:
446 self.queue.append([])
446 self.queue.append([])
447 self.queue[depth].append(group)
447 self.queue[depth].append(group)
448
448
449 def deq(self):
449 def deq(self):
450 for stack in self.queue:
450 for stack in self.queue:
451 for idx, group in enumerate(reversed(stack)):
451 for idx, group in enumerate(reversed(stack)):
452 if group.breakables:
452 if group.breakables:
453 del stack[idx]
453 del stack[idx]
454 group.want_break = True
454 group.want_break = True
455 return group
455 return group
456 for group in stack:
456 for group in stack:
457 group.want_break = True
457 group.want_break = True
458 del stack[:]
458 del stack[:]
459
459
460 def remove(self, group):
460 def remove(self, group):
461 try:
461 try:
462 self.queue[group.depth].remove(group)
462 self.queue[group.depth].remove(group)
463 except ValueError:
463 except ValueError:
464 pass
464 pass
465
465
466 try:
466 try:
467 _baseclass_reprs = (object.__repr__, types.InstanceType.__repr__)
467 _baseclass_reprs = (object.__repr__, types.InstanceType.__repr__)
468 except AttributeError: # Python 3
468 except AttributeError: # Python 3
469 _baseclass_reprs = (object.__repr__,)
469 _baseclass_reprs = (object.__repr__,)
470
470
471
471
472 def _default_pprint(obj, p, cycle):
472 def _default_pprint(obj, p, cycle):
473 """
473 """
474 The default print function. Used if an object does not provide one and
474 The default print function. Used if an object does not provide one and
475 it's none of the builtin objects.
475 it's none of the builtin objects.
476 """
476 """
477 klass = getattr(obj, '__class__', None) or type(obj)
477 klass = getattr(obj, '__class__', None) or type(obj)
478 if getattr(klass, '__repr__', None) not in _baseclass_reprs:
478 if getattr(klass, '__repr__', None) not in _baseclass_reprs:
479 # A user-provided repr.
479 # A user-provided repr.
480 p.text(repr(obj))
480 p.text(repr(obj))
481 return
481 return
482 p.begin_group(1, '<')
482 p.begin_group(1, '<')
483 p.pretty(klass)
483 p.pretty(klass)
484 p.text(' at 0x%x' % id(obj))
484 p.text(' at 0x%x' % id(obj))
485 if cycle:
485 if cycle:
486 p.text(' ...')
486 p.text(' ...')
487 elif p.verbose:
487 elif p.verbose:
488 first = True
488 first = True
489 for key in dir(obj):
489 for key in dir(obj):
490 if not key.startswith('_'):
490 if not key.startswith('_'):
491 try:
491 try:
492 value = getattr(obj, key)
492 value = getattr(obj, key)
493 except AttributeError:
493 except AttributeError:
494 continue
494 continue
495 if isinstance(value, types.MethodType):
495 if isinstance(value, types.MethodType):
496 continue
496 continue
497 if not first:
497 if not first:
498 p.text(',')
498 p.text(',')
499 p.breakable()
499 p.breakable()
500 p.text(key)
500 p.text(key)
501 p.text('=')
501 p.text('=')
502 step = len(key) + 1
502 step = len(key) + 1
503 p.indentation += step
503 p.indentation += step
504 p.pretty(value)
504 p.pretty(value)
505 p.indentation -= step
505 p.indentation -= step
506 first = False
506 first = False
507 p.end_group(1, '>')
507 p.end_group(1, '>')
508
508
509
509
510 def _seq_pprinter_factory(start, end, basetype):
510 def _seq_pprinter_factory(start, end, basetype):
511 """
511 """
512 Factory that returns a pprint function useful for sequences. Used by
512 Factory that returns a pprint function useful for sequences. Used by
513 the default pprint for tuples, dicts, lists, sets and frozensets.
513 the default pprint for tuples, dicts, lists, sets and frozensets.
514 """
514 """
515 def inner(obj, p, cycle):
515 def inner(obj, p, cycle):
516 typ = type(obj)
516 typ = type(obj)
517 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
517 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
518 # If the subclass provides its own repr, use it instead.
518 # If the subclass provides its own repr, use it instead.
519 return p.text(typ.__repr__(obj))
519 return p.text(typ.__repr__(obj))
520
520
521 if cycle:
521 if cycle:
522 return p.text(start + '...' + end)
522 return p.text(start + '...' + end)
523 step = len(start)
523 step = len(start)
524 p.begin_group(step, start)
524 p.begin_group(step, start)
525 for idx, x in enumerate(obj):
525 for idx, x in enumerate(obj):
526 if idx:
526 if idx:
527 p.text(',')
527 p.text(',')
528 p.breakable()
528 p.breakable()
529 p.pretty(x)
529 p.pretty(x)
530 if len(obj) == 1 and type(obj) is tuple:
530 if len(obj) == 1 and type(obj) is tuple:
531 # Special case for 1-item tuples.
531 # Special case for 1-item tuples.
532 p.text(',')
532 p.text(',')
533 p.end_group(step, end)
533 p.end_group(step, end)
534 return inner
534 return inner
535
535
536
536
537 def _dict_pprinter_factory(start, end, basetype=None):
537 def _dict_pprinter_factory(start, end, basetype=None):
538 """
538 """
539 Factory that returns a pprint function used by the default pprint of
539 Factory that returns a pprint function used by the default pprint of
540 dicts and dict proxies.
540 dicts and dict proxies.
541 """
541 """
542 def inner(obj, p, cycle):
542 def inner(obj, p, cycle):
543 typ = type(obj)
543 typ = type(obj)
544 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
544 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
545 # If the subclass provides its own repr, use it instead.
545 # If the subclass provides its own repr, use it instead.
546 return p.text(typ.__repr__(obj))
546 return p.text(typ.__repr__(obj))
547
547
548 if cycle:
548 if cycle:
549 return p.text('{...}')
549 return p.text('{...}')
550 p.begin_group(1, start)
550 p.begin_group(1, start)
551 keys = obj.keys()
551 keys = obj.keys()
552 try:
552 try:
553 keys.sort()
553 keys.sort()
554 except Exception, e:
554 except Exception as e:
555 # Sometimes the keys don't sort.
555 # Sometimes the keys don't sort.
556 pass
556 pass
557 for idx, key in enumerate(keys):
557 for idx, key in enumerate(keys):
558 if idx:
558 if idx:
559 p.text(',')
559 p.text(',')
560 p.breakable()
560 p.breakable()
561 p.pretty(key)
561 p.pretty(key)
562 p.text(': ')
562 p.text(': ')
563 p.pretty(obj[key])
563 p.pretty(obj[key])
564 p.end_group(1, end)
564 p.end_group(1, end)
565 return inner
565 return inner
566
566
567
567
568 def _super_pprint(obj, p, cycle):
568 def _super_pprint(obj, p, cycle):
569 """The pprint for the super type."""
569 """The pprint for the super type."""
570 p.begin_group(8, '<super: ')
570 p.begin_group(8, '<super: ')
571 p.pretty(obj.__self_class__)
571 p.pretty(obj.__self_class__)
572 p.text(',')
572 p.text(',')
573 p.breakable()
573 p.breakable()
574 p.pretty(obj.__self__)
574 p.pretty(obj.__self__)
575 p.end_group(8, '>')
575 p.end_group(8, '>')
576
576
577
577
578 def _re_pattern_pprint(obj, p, cycle):
578 def _re_pattern_pprint(obj, p, cycle):
579 """The pprint function for regular expression patterns."""
579 """The pprint function for regular expression patterns."""
580 p.text('re.compile(')
580 p.text('re.compile(')
581 pattern = repr(obj.pattern)
581 pattern = repr(obj.pattern)
582 if pattern[:1] in 'uU':
582 if pattern[:1] in 'uU':
583 pattern = pattern[1:]
583 pattern = pattern[1:]
584 prefix = 'ur'
584 prefix = 'ur'
585 else:
585 else:
586 prefix = 'r'
586 prefix = 'r'
587 pattern = prefix + pattern.replace('\\\\', '\\')
587 pattern = prefix + pattern.replace('\\\\', '\\')
588 p.text(pattern)
588 p.text(pattern)
589 if obj.flags:
589 if obj.flags:
590 p.text(',')
590 p.text(',')
591 p.breakable()
591 p.breakable()
592 done_one = False
592 done_one = False
593 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
593 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
594 'UNICODE', 'VERBOSE', 'DEBUG'):
594 'UNICODE', 'VERBOSE', 'DEBUG'):
595 if obj.flags & getattr(re, flag):
595 if obj.flags & getattr(re, flag):
596 if done_one:
596 if done_one:
597 p.text('|')
597 p.text('|')
598 p.text('re.' + flag)
598 p.text('re.' + flag)
599 done_one = True
599 done_one = True
600 p.text(')')
600 p.text(')')
601
601
602
602
603 def _type_pprint(obj, p, cycle):
603 def _type_pprint(obj, p, cycle):
604 """The pprint for classes and types."""
604 """The pprint for classes and types."""
605 if obj.__module__ in ('__builtin__', 'exceptions'):
605 if obj.__module__ in ('__builtin__', 'exceptions'):
606 name = obj.__name__
606 name = obj.__name__
607 else:
607 else:
608 name = obj.__module__ + '.' + obj.__name__
608 name = obj.__module__ + '.' + obj.__name__
609 p.text(name)
609 p.text(name)
610
610
611
611
612 def _repr_pprint(obj, p, cycle):
612 def _repr_pprint(obj, p, cycle):
613 """A pprint that just redirects to the normal repr function."""
613 """A pprint that just redirects to the normal repr function."""
614 p.text(repr(obj))
614 p.text(repr(obj))
615
615
616
616
617 def _function_pprint(obj, p, cycle):
617 def _function_pprint(obj, p, cycle):
618 """Base pprint for all functions and builtin functions."""
618 """Base pprint for all functions and builtin functions."""
619 if obj.__module__ in ('__builtin__', 'exceptions') or not obj.__module__:
619 if obj.__module__ in ('__builtin__', 'exceptions') or not obj.__module__:
620 name = obj.__name__
620 name = obj.__name__
621 else:
621 else:
622 name = obj.__module__ + '.' + obj.__name__
622 name = obj.__module__ + '.' + obj.__name__
623 p.text('<function %s>' % name)
623 p.text('<function %s>' % name)
624
624
625
625
626 def _exception_pprint(obj, p, cycle):
626 def _exception_pprint(obj, p, cycle):
627 """Base pprint for all exceptions."""
627 """Base pprint for all exceptions."""
628 if obj.__class__.__module__ in ('exceptions', 'builtins'):
628 if obj.__class__.__module__ in ('exceptions', 'builtins'):
629 name = obj.__class__.__name__
629 name = obj.__class__.__name__
630 else:
630 else:
631 name = '%s.%s' % (
631 name = '%s.%s' % (
632 obj.__class__.__module__,
632 obj.__class__.__module__,
633 obj.__class__.__name__
633 obj.__class__.__name__
634 )
634 )
635 step = len(name) + 1
635 step = len(name) + 1
636 p.begin_group(step, name + '(')
636 p.begin_group(step, name + '(')
637 for idx, arg in enumerate(getattr(obj, 'args', ())):
637 for idx, arg in enumerate(getattr(obj, 'args', ())):
638 if idx:
638 if idx:
639 p.text(',')
639 p.text(',')
640 p.breakable()
640 p.breakable()
641 p.pretty(arg)
641 p.pretty(arg)
642 p.end_group(step, ')')
642 p.end_group(step, ')')
643
643
644
644
645 #: the exception base
645 #: the exception base
646 try:
646 try:
647 _exception_base = BaseException
647 _exception_base = BaseException
648 except NameError:
648 except NameError:
649 _exception_base = Exception
649 _exception_base = Exception
650
650
651
651
652 #: printers for builtin types
652 #: printers for builtin types
653 _type_pprinters = {
653 _type_pprinters = {
654 int: _repr_pprint,
654 int: _repr_pprint,
655 long: _repr_pprint,
655 long: _repr_pprint,
656 float: _repr_pprint,
656 float: _repr_pprint,
657 str: _repr_pprint,
657 str: _repr_pprint,
658 unicode: _repr_pprint,
658 unicode: _repr_pprint,
659 tuple: _seq_pprinter_factory('(', ')', tuple),
659 tuple: _seq_pprinter_factory('(', ')', tuple),
660 list: _seq_pprinter_factory('[', ']', list),
660 list: _seq_pprinter_factory('[', ']', list),
661 dict: _dict_pprinter_factory('{', '}', dict),
661 dict: _dict_pprinter_factory('{', '}', dict),
662
662
663 set: _seq_pprinter_factory('set([', '])', set),
663 set: _seq_pprinter_factory('set([', '])', set),
664 frozenset: _seq_pprinter_factory('frozenset([', '])', frozenset),
664 frozenset: _seq_pprinter_factory('frozenset([', '])', frozenset),
665 super: _super_pprint,
665 super: _super_pprint,
666 _re_pattern_type: _re_pattern_pprint,
666 _re_pattern_type: _re_pattern_pprint,
667 type: _type_pprint,
667 type: _type_pprint,
668 types.FunctionType: _function_pprint,
668 types.FunctionType: _function_pprint,
669 types.BuiltinFunctionType: _function_pprint,
669 types.BuiltinFunctionType: _function_pprint,
670 types.SliceType: _repr_pprint,
670 types.SliceType: _repr_pprint,
671 types.MethodType: _repr_pprint,
671 types.MethodType: _repr_pprint,
672
672
673 datetime.datetime: _repr_pprint,
673 datetime.datetime: _repr_pprint,
674 datetime.timedelta: _repr_pprint,
674 datetime.timedelta: _repr_pprint,
675 _exception_base: _exception_pprint
675 _exception_base: _exception_pprint
676 }
676 }
677
677
678 try:
678 try:
679 _type_pprinters[types.DictProxyType] = _dict_pprinter_factory('<dictproxy {', '}>')
679 _type_pprinters[types.DictProxyType] = _dict_pprinter_factory('<dictproxy {', '}>')
680 _type_pprinters[types.ClassType] = _type_pprint
680 _type_pprinters[types.ClassType] = _type_pprint
681 except AttributeError: # Python 3
681 except AttributeError: # Python 3
682 pass
682 pass
683
683
684 try:
684 try:
685 _type_pprinters[xrange] = _repr_pprint
685 _type_pprinters[xrange] = _repr_pprint
686 except NameError:
686 except NameError:
687 _type_pprinters[range] = _repr_pprint
687 _type_pprinters[range] = _repr_pprint
688
688
689 #: printers for types specified by name
689 #: printers for types specified by name
690 _deferred_type_pprinters = {
690 _deferred_type_pprinters = {
691 }
691 }
692
692
693 def for_type(typ, func):
693 def for_type(typ, func):
694 """
694 """
695 Add a pretty printer for a given type.
695 Add a pretty printer for a given type.
696 """
696 """
697 oldfunc = _type_pprinters.get(typ, None)
697 oldfunc = _type_pprinters.get(typ, None)
698 if func is not None:
698 if func is not None:
699 # To support easy restoration of old pprinters, we need to ignore Nones.
699 # To support easy restoration of old pprinters, we need to ignore Nones.
700 _type_pprinters[typ] = func
700 _type_pprinters[typ] = func
701 return oldfunc
701 return oldfunc
702
702
703 def for_type_by_name(type_module, type_name, func):
703 def for_type_by_name(type_module, type_name, func):
704 """
704 """
705 Add a pretty printer for a type specified by the module and name of a type
705 Add a pretty printer for a type specified by the module and name of a type
706 rather than the type object itself.
706 rather than the type object itself.
707 """
707 """
708 key = (type_module, type_name)
708 key = (type_module, type_name)
709 oldfunc = _deferred_type_pprinters.get(key, None)
709 oldfunc = _deferred_type_pprinters.get(key, None)
710 if func is not None:
710 if func is not None:
711 # To support easy restoration of old pprinters, we need to ignore Nones.
711 # To support easy restoration of old pprinters, we need to ignore Nones.
712 _deferred_type_pprinters[key] = func
712 _deferred_type_pprinters[key] = func
713 return oldfunc
713 return oldfunc
714
714
715
715
716 #: printers for the default singletons
716 #: printers for the default singletons
717 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
717 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
718 NotImplemented]), _repr_pprint)
718 NotImplemented]), _repr_pprint)
719
719
720
720
721 if __name__ == '__main__':
721 if __name__ == '__main__':
722 from random import randrange
722 from random import randrange
723 class Foo(object):
723 class Foo(object):
724 def __init__(self):
724 def __init__(self):
725 self.foo = 1
725 self.foo = 1
726 self.bar = re.compile(r'\s+')
726 self.bar = re.compile(r'\s+')
727 self.blub = dict.fromkeys(range(30), randrange(1, 40))
727 self.blub = dict.fromkeys(range(30), randrange(1, 40))
728 self.hehe = 23424.234234
728 self.hehe = 23424.234234
729 self.list = ["blub", "blah", self]
729 self.list = ["blub", "blah", self]
730
730
731 def get_foo(self):
731 def get_foo(self):
732 print "foo"
732 print "foo"
733
733
734 pprint(Foo(), verbose=True)
734 pprint(Foo(), verbose=True)
@@ -1,686 +1,686 b''
1 """AsyncResult objects for the client
1 """AsyncResult objects for the client
2
2
3 Authors:
3 Authors:
4
4
5 * MinRK
5 * MinRK
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 from __future__ import print_function
18 from __future__ import print_function
19
19
20 import sys
20 import sys
21 import time
21 import time
22 from datetime import datetime
22 from datetime import datetime
23
23
24 from zmq import MessageTracker
24 from zmq import MessageTracker
25
25
26 from IPython.core.display import clear_output, display, display_pretty
26 from IPython.core.display import clear_output, display, display_pretty
27 from IPython.external.decorator import decorator
27 from IPython.external.decorator import decorator
28 from IPython.parallel import error
28 from IPython.parallel import error
29
29
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31 # Functions
31 # Functions
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33
33
34 def _total_seconds(td):
34 def _total_seconds(td):
35 """timedelta.total_seconds was added in 2.7"""
35 """timedelta.total_seconds was added in 2.7"""
36 try:
36 try:
37 # Python >= 2.7
37 # Python >= 2.7
38 return td.total_seconds()
38 return td.total_seconds()
39 except AttributeError:
39 except AttributeError:
40 # Python 2.6
40 # Python 2.6
41 return 1e-6 * (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6)
41 return 1e-6 * (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6)
42
42
43 def _raw_text(s):
43 def _raw_text(s):
44 display_pretty(s, raw=True)
44 display_pretty(s, raw=True)
45
45
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47 # Classes
47 # Classes
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49
49
50 # global empty tracker that's always done:
50 # global empty tracker that's always done:
51 finished_tracker = MessageTracker()
51 finished_tracker = MessageTracker()
52
52
53 @decorator
53 @decorator
54 def check_ready(f, self, *args, **kwargs):
54 def check_ready(f, self, *args, **kwargs):
55 """Call spin() to sync state prior to calling the method."""
55 """Call spin() to sync state prior to calling the method."""
56 self.wait(0)
56 self.wait(0)
57 if not self._ready:
57 if not self._ready:
58 raise error.TimeoutError("result not ready")
58 raise error.TimeoutError("result not ready")
59 return f(self, *args, **kwargs)
59 return f(self, *args, **kwargs)
60
60
61 class AsyncResult(object):
61 class AsyncResult(object):
62 """Class for representing results of non-blocking calls.
62 """Class for representing results of non-blocking calls.
63
63
64 Provides the same interface as :py:class:`multiprocessing.pool.AsyncResult`.
64 Provides the same interface as :py:class:`multiprocessing.pool.AsyncResult`.
65 """
65 """
66
66
67 msg_ids = None
67 msg_ids = None
68 _targets = None
68 _targets = None
69 _tracker = None
69 _tracker = None
70 _single_result = False
70 _single_result = False
71
71
72 def __init__(self, client, msg_ids, fname='unknown', targets=None, tracker=None):
72 def __init__(self, client, msg_ids, fname='unknown', targets=None, tracker=None):
73 if isinstance(msg_ids, basestring):
73 if isinstance(msg_ids, basestring):
74 # always a list
74 # always a list
75 msg_ids = [msg_ids]
75 msg_ids = [msg_ids]
76 if tracker is None:
76 if tracker is None:
77 # default to always done
77 # default to always done
78 tracker = finished_tracker
78 tracker = finished_tracker
79 self._client = client
79 self._client = client
80 self.msg_ids = msg_ids
80 self.msg_ids = msg_ids
81 self._fname=fname
81 self._fname=fname
82 self._targets = targets
82 self._targets = targets
83 self._tracker = tracker
83 self._tracker = tracker
84 self._ready = False
84 self._ready = False
85 self._success = None
85 self._success = None
86 self._metadata = None
86 self._metadata = None
87 if len(msg_ids) == 1:
87 if len(msg_ids) == 1:
88 self._single_result = not isinstance(targets, (list, tuple))
88 self._single_result = not isinstance(targets, (list, tuple))
89 else:
89 else:
90 self._single_result = False
90 self._single_result = False
91
91
92 def __repr__(self):
92 def __repr__(self):
93 if self._ready:
93 if self._ready:
94 return "<%s: finished>"%(self.__class__.__name__)
94 return "<%s: finished>"%(self.__class__.__name__)
95 else:
95 else:
96 return "<%s: %s>"%(self.__class__.__name__,self._fname)
96 return "<%s: %s>"%(self.__class__.__name__,self._fname)
97
97
98
98
99 def _reconstruct_result(self, res):
99 def _reconstruct_result(self, res):
100 """Reconstruct our result from actual result list (always a list)
100 """Reconstruct our result from actual result list (always a list)
101
101
102 Override me in subclasses for turning a list of results
102 Override me in subclasses for turning a list of results
103 into the expected form.
103 into the expected form.
104 """
104 """
105 if self._single_result:
105 if self._single_result:
106 return res[0]
106 return res[0]
107 else:
107 else:
108 return res
108 return res
109
109
110 def get(self, timeout=-1):
110 def get(self, timeout=-1):
111 """Return the result when it arrives.
111 """Return the result when it arrives.
112
112
113 If `timeout` is not ``None`` and the result does not arrive within
113 If `timeout` is not ``None`` and the result does not arrive within
114 `timeout` seconds then ``TimeoutError`` is raised. If the
114 `timeout` seconds then ``TimeoutError`` is raised. If the
115 remote call raised an exception then that exception will be reraised
115 remote call raised an exception then that exception will be reraised
116 by get() inside a `RemoteError`.
116 by get() inside a `RemoteError`.
117 """
117 """
118 if not self.ready():
118 if not self.ready():
119 self.wait(timeout)
119 self.wait(timeout)
120
120
121 if self._ready:
121 if self._ready:
122 if self._success:
122 if self._success:
123 return self._result
123 return self._result
124 else:
124 else:
125 raise self._exception
125 raise self._exception
126 else:
126 else:
127 raise error.TimeoutError("Result not ready.")
127 raise error.TimeoutError("Result not ready.")
128
128
129 def ready(self):
129 def ready(self):
130 """Return whether the call has completed."""
130 """Return whether the call has completed."""
131 if not self._ready:
131 if not self._ready:
132 self.wait(0)
132 self.wait(0)
133 return self._ready
133 return self._ready
134
134
135 def wait(self, timeout=-1):
135 def wait(self, timeout=-1):
136 """Wait until the result is available or until `timeout` seconds pass.
136 """Wait until the result is available or until `timeout` seconds pass.
137
137
138 This method always returns None.
138 This method always returns None.
139 """
139 """
140 if self._ready:
140 if self._ready:
141 return
141 return
142 self._ready = self._client.wait(self.msg_ids, timeout)
142 self._ready = self._client.wait(self.msg_ids, timeout)
143 if self._ready:
143 if self._ready:
144 try:
144 try:
145 results = map(self._client.results.get, self.msg_ids)
145 results = map(self._client.results.get, self.msg_ids)
146 self._result = results
146 self._result = results
147 if self._single_result:
147 if self._single_result:
148 r = results[0]
148 r = results[0]
149 if isinstance(r, Exception):
149 if isinstance(r, Exception):
150 raise r
150 raise r
151 else:
151 else:
152 results = error.collect_exceptions(results, self._fname)
152 results = error.collect_exceptions(results, self._fname)
153 self._result = self._reconstruct_result(results)
153 self._result = self._reconstruct_result(results)
154 except Exception, e:
154 except Exception as e:
155 self._exception = e
155 self._exception = e
156 self._success = False
156 self._success = False
157 else:
157 else:
158 self._success = True
158 self._success = True
159 finally:
159 finally:
160 self._metadata = map(self._client.metadata.get, self.msg_ids)
160 self._metadata = map(self._client.metadata.get, self.msg_ids)
161 self._wait_for_outputs(10)
161 self._wait_for_outputs(10)
162
162
163
163
164
164
165 def successful(self):
165 def successful(self):
166 """Return whether the call completed without raising an exception.
166 """Return whether the call completed without raising an exception.
167
167
168 Will raise ``AssertionError`` if the result is not ready.
168 Will raise ``AssertionError`` if the result is not ready.
169 """
169 """
170 assert self.ready()
170 assert self.ready()
171 return self._success
171 return self._success
172
172
173 #----------------------------------------------------------------
173 #----------------------------------------------------------------
174 # Extra methods not in mp.pool.AsyncResult
174 # Extra methods not in mp.pool.AsyncResult
175 #----------------------------------------------------------------
175 #----------------------------------------------------------------
176
176
177 def get_dict(self, timeout=-1):
177 def get_dict(self, timeout=-1):
178 """Get the results as a dict, keyed by engine_id.
178 """Get the results as a dict, keyed by engine_id.
179
179
180 timeout behavior is described in `get()`.
180 timeout behavior is described in `get()`.
181 """
181 """
182
182
183 results = self.get(timeout)
183 results = self.get(timeout)
184 engine_ids = [ md['engine_id'] for md in self._metadata ]
184 engine_ids = [ md['engine_id'] for md in self._metadata ]
185 bycount = sorted(engine_ids, key=lambda k: engine_ids.count(k))
185 bycount = sorted(engine_ids, key=lambda k: engine_ids.count(k))
186 maxcount = bycount.count(bycount[-1])
186 maxcount = bycount.count(bycount[-1])
187 if maxcount > 1:
187 if maxcount > 1:
188 raise ValueError("Cannot build dict, %i jobs ran on engine #%i"%(
188 raise ValueError("Cannot build dict, %i jobs ran on engine #%i"%(
189 maxcount, bycount[-1]))
189 maxcount, bycount[-1]))
190
190
191 return dict(zip(engine_ids,results))
191 return dict(zip(engine_ids,results))
192
192
193 @property
193 @property
194 def result(self):
194 def result(self):
195 """result property wrapper for `get(timeout=0)`."""
195 """result property wrapper for `get(timeout=0)`."""
196 return self.get()
196 return self.get()
197
197
198 # abbreviated alias:
198 # abbreviated alias:
199 r = result
199 r = result
200
200
201 @property
201 @property
202 @check_ready
202 @check_ready
203 def metadata(self):
203 def metadata(self):
204 """property for accessing execution metadata."""
204 """property for accessing execution metadata."""
205 if self._single_result:
205 if self._single_result:
206 return self._metadata[0]
206 return self._metadata[0]
207 else:
207 else:
208 return self._metadata
208 return self._metadata
209
209
210 @property
210 @property
211 def result_dict(self):
211 def result_dict(self):
212 """result property as a dict."""
212 """result property as a dict."""
213 return self.get_dict()
213 return self.get_dict()
214
214
215 def __dict__(self):
215 def __dict__(self):
216 return self.get_dict(0)
216 return self.get_dict(0)
217
217
218 def abort(self):
218 def abort(self):
219 """abort my tasks."""
219 """abort my tasks."""
220 assert not self.ready(), "Can't abort, I am already done!"
220 assert not self.ready(), "Can't abort, I am already done!"
221 return self._client.abort(self.msg_ids, targets=self._targets, block=True)
221 return self._client.abort(self.msg_ids, targets=self._targets, block=True)
222
222
223 @property
223 @property
224 def sent(self):
224 def sent(self):
225 """check whether my messages have been sent."""
225 """check whether my messages have been sent."""
226 return self._tracker.done
226 return self._tracker.done
227
227
228 def wait_for_send(self, timeout=-1):
228 def wait_for_send(self, timeout=-1):
229 """wait for pyzmq send to complete.
229 """wait for pyzmq send to complete.
230
230
231 This is necessary when sending arrays that you intend to edit in-place.
231 This is necessary when sending arrays that you intend to edit in-place.
232 `timeout` is in seconds, and will raise TimeoutError if it is reached
232 `timeout` is in seconds, and will raise TimeoutError if it is reached
233 before the send completes.
233 before the send completes.
234 """
234 """
235 return self._tracker.wait(timeout)
235 return self._tracker.wait(timeout)
236
236
237 #-------------------------------------
237 #-------------------------------------
238 # dict-access
238 # dict-access
239 #-------------------------------------
239 #-------------------------------------
240
240
241 @check_ready
241 @check_ready
242 def __getitem__(self, key):
242 def __getitem__(self, key):
243 """getitem returns result value(s) if keyed by int/slice, or metadata if key is str.
243 """getitem returns result value(s) if keyed by int/slice, or metadata if key is str.
244 """
244 """
245 if isinstance(key, int):
245 if isinstance(key, int):
246 return error.collect_exceptions([self._result[key]], self._fname)[0]
246 return error.collect_exceptions([self._result[key]], self._fname)[0]
247 elif isinstance(key, slice):
247 elif isinstance(key, slice):
248 return error.collect_exceptions(self._result[key], self._fname)
248 return error.collect_exceptions(self._result[key], self._fname)
249 elif isinstance(key, basestring):
249 elif isinstance(key, basestring):
250 values = [ md[key] for md in self._metadata ]
250 values = [ md[key] for md in self._metadata ]
251 if self._single_result:
251 if self._single_result:
252 return values[0]
252 return values[0]
253 else:
253 else:
254 return values
254 return values
255 else:
255 else:
256 raise TypeError("Invalid key type %r, must be 'int','slice', or 'str'"%type(key))
256 raise TypeError("Invalid key type %r, must be 'int','slice', or 'str'"%type(key))
257
257
258 def __getattr__(self, key):
258 def __getattr__(self, key):
259 """getattr maps to getitem for convenient attr access to metadata."""
259 """getattr maps to getitem for convenient attr access to metadata."""
260 try:
260 try:
261 return self.__getitem__(key)
261 return self.__getitem__(key)
262 except (error.TimeoutError, KeyError):
262 except (error.TimeoutError, KeyError):
263 raise AttributeError("%r object has no attribute %r"%(
263 raise AttributeError("%r object has no attribute %r"%(
264 self.__class__.__name__, key))
264 self.__class__.__name__, key))
265
265
266 # asynchronous iterator:
266 # asynchronous iterator:
267 def __iter__(self):
267 def __iter__(self):
268 if self._single_result:
268 if self._single_result:
269 raise TypeError("AsyncResults with a single result are not iterable.")
269 raise TypeError("AsyncResults with a single result are not iterable.")
270 try:
270 try:
271 rlist = self.get(0)
271 rlist = self.get(0)
272 except error.TimeoutError:
272 except error.TimeoutError:
273 # wait for each result individually
273 # wait for each result individually
274 for msg_id in self.msg_ids:
274 for msg_id in self.msg_ids:
275 ar = AsyncResult(self._client, msg_id, self._fname)
275 ar = AsyncResult(self._client, msg_id, self._fname)
276 yield ar.get()
276 yield ar.get()
277 else:
277 else:
278 # already done
278 # already done
279 for r in rlist:
279 for r in rlist:
280 yield r
280 yield r
281
281
282 def __len__(self):
282 def __len__(self):
283 return len(self.msg_ids)
283 return len(self.msg_ids)
284
284
285 #-------------------------------------
285 #-------------------------------------
286 # Sugar methods and attributes
286 # Sugar methods and attributes
287 #-------------------------------------
287 #-------------------------------------
288
288
289 def timedelta(self, start, end, start_key=min, end_key=max):
289 def timedelta(self, start, end, start_key=min, end_key=max):
290 """compute the difference between two sets of timestamps
290 """compute the difference between two sets of timestamps
291
291
292 The default behavior is to use the earliest of the first
292 The default behavior is to use the earliest of the first
293 and the latest of the second list, but this can be changed
293 and the latest of the second list, but this can be changed
294 by passing a different
294 by passing a different
295
295
296 Parameters
296 Parameters
297 ----------
297 ----------
298
298
299 start : one or more datetime objects (e.g. ar.submitted)
299 start : one or more datetime objects (e.g. ar.submitted)
300 end : one or more datetime objects (e.g. ar.received)
300 end : one or more datetime objects (e.g. ar.received)
301 start_key : callable
301 start_key : callable
302 Function to call on `start` to extract the relevant
302 Function to call on `start` to extract the relevant
303 entry [defalt: min]
303 entry [defalt: min]
304 end_key : callable
304 end_key : callable
305 Function to call on `end` to extract the relevant
305 Function to call on `end` to extract the relevant
306 entry [default: max]
306 entry [default: max]
307
307
308 Returns
308 Returns
309 -------
309 -------
310
310
311 dt : float
311 dt : float
312 The time elapsed (in seconds) between the two selected timestamps.
312 The time elapsed (in seconds) between the two selected timestamps.
313 """
313 """
314 if not isinstance(start, datetime):
314 if not isinstance(start, datetime):
315 # handle single_result AsyncResults, where ar.stamp is single object,
315 # handle single_result AsyncResults, where ar.stamp is single object,
316 # not a list
316 # not a list
317 start = start_key(start)
317 start = start_key(start)
318 if not isinstance(end, datetime):
318 if not isinstance(end, datetime):
319 # handle single_result AsyncResults, where ar.stamp is single object,
319 # handle single_result AsyncResults, where ar.stamp is single object,
320 # not a list
320 # not a list
321 end = end_key(end)
321 end = end_key(end)
322 return _total_seconds(end - start)
322 return _total_seconds(end - start)
323
323
324 @property
324 @property
325 def progress(self):
325 def progress(self):
326 """the number of tasks which have been completed at this point.
326 """the number of tasks which have been completed at this point.
327
327
328 Fractional progress would be given by 1.0 * ar.progress / len(ar)
328 Fractional progress would be given by 1.0 * ar.progress / len(ar)
329 """
329 """
330 self.wait(0)
330 self.wait(0)
331 return len(self) - len(set(self.msg_ids).intersection(self._client.outstanding))
331 return len(self) - len(set(self.msg_ids).intersection(self._client.outstanding))
332
332
333 @property
333 @property
334 def elapsed(self):
334 def elapsed(self):
335 """elapsed time since initial submission"""
335 """elapsed time since initial submission"""
336 if self.ready():
336 if self.ready():
337 return self.wall_time
337 return self.wall_time
338
338
339 now = submitted = datetime.now()
339 now = submitted = datetime.now()
340 for msg_id in self.msg_ids:
340 for msg_id in self.msg_ids:
341 if msg_id in self._client.metadata:
341 if msg_id in self._client.metadata:
342 stamp = self._client.metadata[msg_id]['submitted']
342 stamp = self._client.metadata[msg_id]['submitted']
343 if stamp and stamp < submitted:
343 if stamp and stamp < submitted:
344 submitted = stamp
344 submitted = stamp
345 return _total_seconds(now-submitted)
345 return _total_seconds(now-submitted)
346
346
347 @property
347 @property
348 @check_ready
348 @check_ready
349 def serial_time(self):
349 def serial_time(self):
350 """serial computation time of a parallel calculation
350 """serial computation time of a parallel calculation
351
351
352 Computed as the sum of (completed-started) of each task
352 Computed as the sum of (completed-started) of each task
353 """
353 """
354 t = 0
354 t = 0
355 for md in self._metadata:
355 for md in self._metadata:
356 t += _total_seconds(md['completed'] - md['started'])
356 t += _total_seconds(md['completed'] - md['started'])
357 return t
357 return t
358
358
359 @property
359 @property
360 @check_ready
360 @check_ready
361 def wall_time(self):
361 def wall_time(self):
362 """actual computation time of a parallel calculation
362 """actual computation time of a parallel calculation
363
363
364 Computed as the time between the latest `received` stamp
364 Computed as the time between the latest `received` stamp
365 and the earliest `submitted`.
365 and the earliest `submitted`.
366
366
367 Only reliable if Client was spinning/waiting when the task finished, because
367 Only reliable if Client was spinning/waiting when the task finished, because
368 the `received` timestamp is created when a result is pulled off of the zmq queue,
368 the `received` timestamp is created when a result is pulled off of the zmq queue,
369 which happens as a result of `client.spin()`.
369 which happens as a result of `client.spin()`.
370
370
371 For similar comparison of other timestamp pairs, check out AsyncResult.timedelta.
371 For similar comparison of other timestamp pairs, check out AsyncResult.timedelta.
372
372
373 """
373 """
374 return self.timedelta(self.submitted, self.received)
374 return self.timedelta(self.submitted, self.received)
375
375
376 def wait_interactive(self, interval=1., timeout=None):
376 def wait_interactive(self, interval=1., timeout=None):
377 """interactive wait, printing progress at regular intervals"""
377 """interactive wait, printing progress at regular intervals"""
378 N = len(self)
378 N = len(self)
379 tic = time.time()
379 tic = time.time()
380 while not self.ready() and (timeout is None or time.time() - tic <= timeout):
380 while not self.ready() and (timeout is None or time.time() - tic <= timeout):
381 self.wait(interval)
381 self.wait(interval)
382 clear_output()
382 clear_output()
383 print("%4i/%i tasks finished after %4i s" % (self.progress, N, self.elapsed), end="")
383 print("%4i/%i tasks finished after %4i s" % (self.progress, N, self.elapsed), end="")
384 sys.stdout.flush()
384 sys.stdout.flush()
385 print()
385 print()
386 print("done")
386 print("done")
387
387
388 def _republish_displaypub(self, content, eid):
388 def _republish_displaypub(self, content, eid):
389 """republish individual displaypub content dicts"""
389 """republish individual displaypub content dicts"""
390 try:
390 try:
391 ip = get_ipython()
391 ip = get_ipython()
392 except NameError:
392 except NameError:
393 # displaypub is meaningless outside IPython
393 # displaypub is meaningless outside IPython
394 return
394 return
395 md = content['metadata'] or {}
395 md = content['metadata'] or {}
396 md['engine'] = eid
396 md['engine'] = eid
397 ip.display_pub.publish(content['source'], content['data'], md)
397 ip.display_pub.publish(content['source'], content['data'], md)
398
398
399 def _display_stream(self, text, prefix='', file=None):
399 def _display_stream(self, text, prefix='', file=None):
400 if not text:
400 if not text:
401 # nothing to display
401 # nothing to display
402 return
402 return
403 if file is None:
403 if file is None:
404 file = sys.stdout
404 file = sys.stdout
405 end = '' if text.endswith('\n') else '\n'
405 end = '' if text.endswith('\n') else '\n'
406
406
407 multiline = text.count('\n') > int(text.endswith('\n'))
407 multiline = text.count('\n') > int(text.endswith('\n'))
408 if prefix and multiline and not text.startswith('\n'):
408 if prefix and multiline and not text.startswith('\n'):
409 prefix = prefix + '\n'
409 prefix = prefix + '\n'
410 print("%s%s" % (prefix, text), file=file, end=end)
410 print("%s%s" % (prefix, text), file=file, end=end)
411
411
412
412
413 def _display_single_result(self):
413 def _display_single_result(self):
414 self._display_stream(self.stdout)
414 self._display_stream(self.stdout)
415 self._display_stream(self.stderr, file=sys.stderr)
415 self._display_stream(self.stderr, file=sys.stderr)
416
416
417 try:
417 try:
418 get_ipython()
418 get_ipython()
419 except NameError:
419 except NameError:
420 # displaypub is meaningless outside IPython
420 # displaypub is meaningless outside IPython
421 return
421 return
422
422
423 for output in self.outputs:
423 for output in self.outputs:
424 self._republish_displaypub(output, self.engine_id)
424 self._republish_displaypub(output, self.engine_id)
425
425
426 if self.pyout is not None:
426 if self.pyout is not None:
427 display(self.get())
427 display(self.get())
428
428
429 def _wait_for_outputs(self, timeout=-1):
429 def _wait_for_outputs(self, timeout=-1):
430 """wait for the 'status=idle' message that indicates we have all outputs
430 """wait for the 'status=idle' message that indicates we have all outputs
431 """
431 """
432 if not self._success:
432 if not self._success:
433 # don't wait on errors
433 # don't wait on errors
434 return
434 return
435 tic = time.time()
435 tic = time.time()
436 while not all(md['outputs_ready'] for md in self._metadata):
436 while not all(md['outputs_ready'] for md in self._metadata):
437 time.sleep(0.01)
437 time.sleep(0.01)
438 self._client._flush_iopub(self._client._iopub_socket)
438 self._client._flush_iopub(self._client._iopub_socket)
439 if timeout >= 0 and time.time() > tic + timeout:
439 if timeout >= 0 and time.time() > tic + timeout:
440 break
440 break
441
441
442 @check_ready
442 @check_ready
443 def display_outputs(self, groupby="type"):
443 def display_outputs(self, groupby="type"):
444 """republish the outputs of the computation
444 """republish the outputs of the computation
445
445
446 Parameters
446 Parameters
447 ----------
447 ----------
448
448
449 groupby : str [default: type]
449 groupby : str [default: type]
450 if 'type':
450 if 'type':
451 Group outputs by type (show all stdout, then all stderr, etc.):
451 Group outputs by type (show all stdout, then all stderr, etc.):
452
452
453 [stdout:1] foo
453 [stdout:1] foo
454 [stdout:2] foo
454 [stdout:2] foo
455 [stderr:1] bar
455 [stderr:1] bar
456 [stderr:2] bar
456 [stderr:2] bar
457 if 'engine':
457 if 'engine':
458 Display outputs for each engine before moving on to the next:
458 Display outputs for each engine before moving on to the next:
459
459
460 [stdout:1] foo
460 [stdout:1] foo
461 [stderr:1] bar
461 [stderr:1] bar
462 [stdout:2] foo
462 [stdout:2] foo
463 [stderr:2] bar
463 [stderr:2] bar
464
464
465 if 'order':
465 if 'order':
466 Like 'type', but further collate individual displaypub
466 Like 'type', but further collate individual displaypub
467 outputs. This is meant for cases of each command producing
467 outputs. This is meant for cases of each command producing
468 several plots, and you would like to see all of the first
468 several plots, and you would like to see all of the first
469 plots together, then all of the second plots, and so on.
469 plots together, then all of the second plots, and so on.
470 """
470 """
471 if self._single_result:
471 if self._single_result:
472 self._display_single_result()
472 self._display_single_result()
473 return
473 return
474
474
475 stdouts = self.stdout
475 stdouts = self.stdout
476 stderrs = self.stderr
476 stderrs = self.stderr
477 pyouts = self.pyout
477 pyouts = self.pyout
478 output_lists = self.outputs
478 output_lists = self.outputs
479 results = self.get()
479 results = self.get()
480
480
481 targets = self.engine_id
481 targets = self.engine_id
482
482
483 if groupby == "engine":
483 if groupby == "engine":
484 for eid,stdout,stderr,outputs,r,pyout in zip(
484 for eid,stdout,stderr,outputs,r,pyout in zip(
485 targets, stdouts, stderrs, output_lists, results, pyouts
485 targets, stdouts, stderrs, output_lists, results, pyouts
486 ):
486 ):
487 self._display_stream(stdout, '[stdout:%i] ' % eid)
487 self._display_stream(stdout, '[stdout:%i] ' % eid)
488 self._display_stream(stderr, '[stderr:%i] ' % eid, file=sys.stderr)
488 self._display_stream(stderr, '[stderr:%i] ' % eid, file=sys.stderr)
489
489
490 try:
490 try:
491 get_ipython()
491 get_ipython()
492 except NameError:
492 except NameError:
493 # displaypub is meaningless outside IPython
493 # displaypub is meaningless outside IPython
494 return
494 return
495
495
496 if outputs or pyout is not None:
496 if outputs or pyout is not None:
497 _raw_text('[output:%i]' % eid)
497 _raw_text('[output:%i]' % eid)
498
498
499 for output in outputs:
499 for output in outputs:
500 self._republish_displaypub(output, eid)
500 self._republish_displaypub(output, eid)
501
501
502 if pyout is not None:
502 if pyout is not None:
503 display(r)
503 display(r)
504
504
505 elif groupby in ('type', 'order'):
505 elif groupby in ('type', 'order'):
506 # republish stdout:
506 # republish stdout:
507 for eid,stdout in zip(targets, stdouts):
507 for eid,stdout in zip(targets, stdouts):
508 self._display_stream(stdout, '[stdout:%i] ' % eid)
508 self._display_stream(stdout, '[stdout:%i] ' % eid)
509
509
510 # republish stderr:
510 # republish stderr:
511 for eid,stderr in zip(targets, stderrs):
511 for eid,stderr in zip(targets, stderrs):
512 self._display_stream(stderr, '[stderr:%i] ' % eid, file=sys.stderr)
512 self._display_stream(stderr, '[stderr:%i] ' % eid, file=sys.stderr)
513
513
514 try:
514 try:
515 get_ipython()
515 get_ipython()
516 except NameError:
516 except NameError:
517 # displaypub is meaningless outside IPython
517 # displaypub is meaningless outside IPython
518 return
518 return
519
519
520 if groupby == 'order':
520 if groupby == 'order':
521 output_dict = dict((eid, outputs) for eid,outputs in zip(targets, output_lists))
521 output_dict = dict((eid, outputs) for eid,outputs in zip(targets, output_lists))
522 N = max(len(outputs) for outputs in output_lists)
522 N = max(len(outputs) for outputs in output_lists)
523 for i in range(N):
523 for i in range(N):
524 for eid in targets:
524 for eid in targets:
525 outputs = output_dict[eid]
525 outputs = output_dict[eid]
526 if len(outputs) >= N:
526 if len(outputs) >= N:
527 _raw_text('[output:%i]' % eid)
527 _raw_text('[output:%i]' % eid)
528 self._republish_displaypub(outputs[i], eid)
528 self._republish_displaypub(outputs[i], eid)
529 else:
529 else:
530 # republish displaypub output
530 # republish displaypub output
531 for eid,outputs in zip(targets, output_lists):
531 for eid,outputs in zip(targets, output_lists):
532 if outputs:
532 if outputs:
533 _raw_text('[output:%i]' % eid)
533 _raw_text('[output:%i]' % eid)
534 for output in outputs:
534 for output in outputs:
535 self._republish_displaypub(output, eid)
535 self._republish_displaypub(output, eid)
536
536
537 # finally, add pyout:
537 # finally, add pyout:
538 for eid,r,pyout in zip(targets, results, pyouts):
538 for eid,r,pyout in zip(targets, results, pyouts):
539 if pyout is not None:
539 if pyout is not None:
540 display(r)
540 display(r)
541
541
542 else:
542 else:
543 raise ValueError("groupby must be one of 'type', 'engine', 'collate', not %r" % groupby)
543 raise ValueError("groupby must be one of 'type', 'engine', 'collate', not %r" % groupby)
544
544
545
545
546
546
547
547
548 class AsyncMapResult(AsyncResult):
548 class AsyncMapResult(AsyncResult):
549 """Class for representing results of non-blocking gathers.
549 """Class for representing results of non-blocking gathers.
550
550
551 This will properly reconstruct the gather.
551 This will properly reconstruct the gather.
552
552
553 This class is iterable at any time, and will wait on results as they come.
553 This class is iterable at any time, and will wait on results as they come.
554
554
555 If ordered=False, then the first results to arrive will come first, otherwise
555 If ordered=False, then the first results to arrive will come first, otherwise
556 results will be yielded in the order they were submitted.
556 results will be yielded in the order they were submitted.
557
557
558 """
558 """
559
559
560 def __init__(self, client, msg_ids, mapObject, fname='', ordered=True):
560 def __init__(self, client, msg_ids, mapObject, fname='', ordered=True):
561 AsyncResult.__init__(self, client, msg_ids, fname=fname)
561 AsyncResult.__init__(self, client, msg_ids, fname=fname)
562 self._mapObject = mapObject
562 self._mapObject = mapObject
563 self._single_result = False
563 self._single_result = False
564 self.ordered = ordered
564 self.ordered = ordered
565
565
566 def _reconstruct_result(self, res):
566 def _reconstruct_result(self, res):
567 """Perform the gather on the actual results."""
567 """Perform the gather on the actual results."""
568 return self._mapObject.joinPartitions(res)
568 return self._mapObject.joinPartitions(res)
569
569
570 # asynchronous iterator:
570 # asynchronous iterator:
571 def __iter__(self):
571 def __iter__(self):
572 it = self._ordered_iter if self.ordered else self._unordered_iter
572 it = self._ordered_iter if self.ordered else self._unordered_iter
573 for r in it():
573 for r in it():
574 yield r
574 yield r
575
575
576 # asynchronous ordered iterator:
576 # asynchronous ordered iterator:
577 def _ordered_iter(self):
577 def _ordered_iter(self):
578 """iterator for results *as they arrive*, preserving submission order."""
578 """iterator for results *as they arrive*, preserving submission order."""
579 try:
579 try:
580 rlist = self.get(0)
580 rlist = self.get(0)
581 except error.TimeoutError:
581 except error.TimeoutError:
582 # wait for each result individually
582 # wait for each result individually
583 for msg_id in self.msg_ids:
583 for msg_id in self.msg_ids:
584 ar = AsyncResult(self._client, msg_id, self._fname)
584 ar = AsyncResult(self._client, msg_id, self._fname)
585 rlist = ar.get()
585 rlist = ar.get()
586 try:
586 try:
587 for r in rlist:
587 for r in rlist:
588 yield r
588 yield r
589 except TypeError:
589 except TypeError:
590 # flattened, not a list
590 # flattened, not a list
591 # this could get broken by flattened data that returns iterables
591 # this could get broken by flattened data that returns iterables
592 # but most calls to map do not expose the `flatten` argument
592 # but most calls to map do not expose the `flatten` argument
593 yield rlist
593 yield rlist
594 else:
594 else:
595 # already done
595 # already done
596 for r in rlist:
596 for r in rlist:
597 yield r
597 yield r
598
598
599 # asynchronous unordered iterator:
599 # asynchronous unordered iterator:
600 def _unordered_iter(self):
600 def _unordered_iter(self):
601 """iterator for results *as they arrive*, on FCFS basis, ignoring submission order."""
601 """iterator for results *as they arrive*, on FCFS basis, ignoring submission order."""
602 try:
602 try:
603 rlist = self.get(0)
603 rlist = self.get(0)
604 except error.TimeoutError:
604 except error.TimeoutError:
605 pending = set(self.msg_ids)
605 pending = set(self.msg_ids)
606 while pending:
606 while pending:
607 try:
607 try:
608 self._client.wait(pending, 1e-3)
608 self._client.wait(pending, 1e-3)
609 except error.TimeoutError:
609 except error.TimeoutError:
610 # ignore timeout error, because that only means
610 # ignore timeout error, because that only means
611 # *some* jobs are outstanding
611 # *some* jobs are outstanding
612 pass
612 pass
613 # update ready set with those no longer outstanding:
613 # update ready set with those no longer outstanding:
614 ready = pending.difference(self._client.outstanding)
614 ready = pending.difference(self._client.outstanding)
615 # update pending to exclude those that are finished
615 # update pending to exclude those that are finished
616 pending = pending.difference(ready)
616 pending = pending.difference(ready)
617 while ready:
617 while ready:
618 msg_id = ready.pop()
618 msg_id = ready.pop()
619 ar = AsyncResult(self._client, msg_id, self._fname)
619 ar = AsyncResult(self._client, msg_id, self._fname)
620 rlist = ar.get()
620 rlist = ar.get()
621 try:
621 try:
622 for r in rlist:
622 for r in rlist:
623 yield r
623 yield r
624 except TypeError:
624 except TypeError:
625 # flattened, not a list
625 # flattened, not a list
626 # this could get broken by flattened data that returns iterables
626 # this could get broken by flattened data that returns iterables
627 # but most calls to map do not expose the `flatten` argument
627 # but most calls to map do not expose the `flatten` argument
628 yield rlist
628 yield rlist
629 else:
629 else:
630 # already done
630 # already done
631 for r in rlist:
631 for r in rlist:
632 yield r
632 yield r
633
633
634
634
635 class AsyncHubResult(AsyncResult):
635 class AsyncHubResult(AsyncResult):
636 """Class to wrap pending results that must be requested from the Hub.
636 """Class to wrap pending results that must be requested from the Hub.
637
637
638 Note that waiting/polling on these objects requires polling the Hubover the network,
638 Note that waiting/polling on these objects requires polling the Hubover the network,
639 so use `AsyncHubResult.wait()` sparingly.
639 so use `AsyncHubResult.wait()` sparingly.
640 """
640 """
641
641
642 def _wait_for_outputs(self, timeout=None):
642 def _wait_for_outputs(self, timeout=None):
643 """no-op, because HubResults are never incomplete"""
643 """no-op, because HubResults are never incomplete"""
644 return
644 return
645
645
646 def wait(self, timeout=-1):
646 def wait(self, timeout=-1):
647 """wait for result to complete."""
647 """wait for result to complete."""
648 start = time.time()
648 start = time.time()
649 if self._ready:
649 if self._ready:
650 return
650 return
651 local_ids = filter(lambda msg_id: msg_id in self._client.outstanding, self.msg_ids)
651 local_ids = filter(lambda msg_id: msg_id in self._client.outstanding, self.msg_ids)
652 local_ready = self._client.wait(local_ids, timeout)
652 local_ready = self._client.wait(local_ids, timeout)
653 if local_ready:
653 if local_ready:
654 remote_ids = filter(lambda msg_id: msg_id not in self._client.results, self.msg_ids)
654 remote_ids = filter(lambda msg_id: msg_id not in self._client.results, self.msg_ids)
655 if not remote_ids:
655 if not remote_ids:
656 self._ready = True
656 self._ready = True
657 else:
657 else:
658 rdict = self._client.result_status(remote_ids, status_only=False)
658 rdict = self._client.result_status(remote_ids, status_only=False)
659 pending = rdict['pending']
659 pending = rdict['pending']
660 while pending and (timeout < 0 or time.time() < start+timeout):
660 while pending and (timeout < 0 or time.time() < start+timeout):
661 rdict = self._client.result_status(remote_ids, status_only=False)
661 rdict = self._client.result_status(remote_ids, status_only=False)
662 pending = rdict['pending']
662 pending = rdict['pending']
663 if pending:
663 if pending:
664 time.sleep(0.1)
664 time.sleep(0.1)
665 if not pending:
665 if not pending:
666 self._ready = True
666 self._ready = True
667 if self._ready:
667 if self._ready:
668 try:
668 try:
669 results = map(self._client.results.get, self.msg_ids)
669 results = map(self._client.results.get, self.msg_ids)
670 self._result = results
670 self._result = results
671 if self._single_result:
671 if self._single_result:
672 r = results[0]
672 r = results[0]
673 if isinstance(r, Exception):
673 if isinstance(r, Exception):
674 raise r
674 raise r
675 else:
675 else:
676 results = error.collect_exceptions(results, self._fname)
676 results = error.collect_exceptions(results, self._fname)
677 self._result = self._reconstruct_result(results)
677 self._result = self._reconstruct_result(results)
678 except Exception, e:
678 except Exception as e:
679 self._exception = e
679 self._exception = e
680 self._success = False
680 self._success = False
681 else:
681 else:
682 self._success = True
682 self._success = True
683 finally:
683 finally:
684 self._metadata = map(self._client.metadata.get, self.msg_ids)
684 self._metadata = map(self._client.metadata.get, self.msg_ids)
685
685
686 __all__ = ['AsyncResult', 'AsyncMapResult', 'AsyncHubResult'] No newline at end of file
686 __all__ = ['AsyncResult', 'AsyncMapResult', 'AsyncHubResult']
@@ -1,122 +1,122 b''
1 """toplevel setup/teardown for parallel tests."""
1 """toplevel setup/teardown for parallel tests."""
2
2
3 #-------------------------------------------------------------------------------
3 #-------------------------------------------------------------------------------
4 # Copyright (C) 2011 The IPython Development Team
4 # Copyright (C) 2011 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
7 # the file COPYING, distributed as part of this software.
8 #-------------------------------------------------------------------------------
8 #-------------------------------------------------------------------------------
9
9
10 #-------------------------------------------------------------------------------
10 #-------------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-------------------------------------------------------------------------------
12 #-------------------------------------------------------------------------------
13
13
14 import os
14 import os
15 import tempfile
15 import tempfile
16 import time
16 import time
17 from subprocess import Popen
17 from subprocess import Popen
18
18
19 from IPython.utils.path import get_ipython_dir
19 from IPython.utils.path import get_ipython_dir
20 from IPython.parallel import Client
20 from IPython.parallel import Client
21 from IPython.parallel.apps.launcher import (LocalProcessLauncher,
21 from IPython.parallel.apps.launcher import (LocalProcessLauncher,
22 ipengine_cmd_argv,
22 ipengine_cmd_argv,
23 ipcontroller_cmd_argv,
23 ipcontroller_cmd_argv,
24 SIGKILL,
24 SIGKILL,
25 ProcessStateError,
25 ProcessStateError,
26 )
26 )
27
27
28 # globals
28 # globals
29 launchers = []
29 launchers = []
30 blackhole = open(os.devnull, 'w')
30 blackhole = open(os.devnull, 'w')
31
31
32 # Launcher class
32 # Launcher class
33 class TestProcessLauncher(LocalProcessLauncher):
33 class TestProcessLauncher(LocalProcessLauncher):
34 """subclass LocalProcessLauncher, to prevent extra sockets and threads being created on Windows"""
34 """subclass LocalProcessLauncher, to prevent extra sockets and threads being created on Windows"""
35 def start(self):
35 def start(self):
36 if self.state == 'before':
36 if self.state == 'before':
37 self.process = Popen(self.args,
37 self.process = Popen(self.args,
38 stdout=blackhole, stderr=blackhole,
38 stdout=blackhole, stderr=blackhole,
39 env=os.environ,
39 env=os.environ,
40 cwd=self.work_dir
40 cwd=self.work_dir
41 )
41 )
42 self.notify_start(self.process.pid)
42 self.notify_start(self.process.pid)
43 self.poll = self.process.poll
43 self.poll = self.process.poll
44 else:
44 else:
45 s = 'The process was already started and has state: %r' % self.state
45 s = 'The process was already started and has state: %r' % self.state
46 raise ProcessStateError(s)
46 raise ProcessStateError(s)
47
47
48 # nose setup/teardown
48 # nose setup/teardown
49
49
50 def setup():
50 def setup():
51 cluster_dir = os.path.join(get_ipython_dir(), 'profile_iptest')
51 cluster_dir = os.path.join(get_ipython_dir(), 'profile_iptest')
52 engine_json = os.path.join(cluster_dir, 'security', 'ipcontroller-engine.json')
52 engine_json = os.path.join(cluster_dir, 'security', 'ipcontroller-engine.json')
53 client_json = os.path.join(cluster_dir, 'security', 'ipcontroller-client.json')
53 client_json = os.path.join(cluster_dir, 'security', 'ipcontroller-client.json')
54 for json in (engine_json, client_json):
54 for json in (engine_json, client_json):
55 if os.path.exists(json):
55 if os.path.exists(json):
56 os.remove(json)
56 os.remove(json)
57
57
58 cp = TestProcessLauncher()
58 cp = TestProcessLauncher()
59 cp.cmd_and_args = ipcontroller_cmd_argv + \
59 cp.cmd_and_args = ipcontroller_cmd_argv + \
60 ['--profile=iptest', '--log-level=50', '--ping=250', '--dictdb']
60 ['--profile=iptest', '--log-level=50', '--ping=250', '--dictdb']
61 cp.start()
61 cp.start()
62 launchers.append(cp)
62 launchers.append(cp)
63 tic = time.time()
63 tic = time.time()
64 while not os.path.exists(engine_json) or not os.path.exists(client_json):
64 while not os.path.exists(engine_json) or not os.path.exists(client_json):
65 if cp.poll() is not None:
65 if cp.poll() is not None:
66 print cp.poll()
66 print cp.poll()
67 raise RuntimeError("The test controller failed to start.")
67 raise RuntimeError("The test controller failed to start.")
68 elif time.time()-tic > 15:
68 elif time.time()-tic > 15:
69 raise RuntimeError("Timeout waiting for the test controller to start.")
69 raise RuntimeError("Timeout waiting for the test controller to start.")
70 time.sleep(0.1)
70 time.sleep(0.1)
71 add_engines(1)
71 add_engines(1)
72
72
73 def add_engines(n=1, profile='iptest', total=False):
73 def add_engines(n=1, profile='iptest', total=False):
74 """add a number of engines to a given profile.
74 """add a number of engines to a given profile.
75
75
76 If total is True, then already running engines are counted, and only
76 If total is True, then already running engines are counted, and only
77 the additional engines necessary (if any) are started.
77 the additional engines necessary (if any) are started.
78 """
78 """
79 rc = Client(profile=profile)
79 rc = Client(profile=profile)
80 base = len(rc)
80 base = len(rc)
81
81
82 if total:
82 if total:
83 n = max(n - base, 0)
83 n = max(n - base, 0)
84
84
85 eps = []
85 eps = []
86 for i in range(n):
86 for i in range(n):
87 ep = TestProcessLauncher()
87 ep = TestProcessLauncher()
88 ep.cmd_and_args = ipengine_cmd_argv + ['--profile=%s'%profile, '--log-level=50']
88 ep.cmd_and_args = ipengine_cmd_argv + ['--profile=%s'%profile, '--log-level=50']
89 ep.start()
89 ep.start()
90 launchers.append(ep)
90 launchers.append(ep)
91 eps.append(ep)
91 eps.append(ep)
92 tic = time.time()
92 tic = time.time()
93 while len(rc) < base+n:
93 while len(rc) < base+n:
94 if any([ ep.poll() is not None for ep in eps ]):
94 if any([ ep.poll() is not None for ep in eps ]):
95 raise RuntimeError("A test engine failed to start.")
95 raise RuntimeError("A test engine failed to start.")
96 elif time.time()-tic > 15:
96 elif time.time()-tic > 15:
97 raise RuntimeError("Timeout waiting for engines to connect.")
97 raise RuntimeError("Timeout waiting for engines to connect.")
98 time.sleep(.1)
98 time.sleep(.1)
99 rc.spin()
99 rc.spin()
100 rc.close()
100 rc.close()
101 return eps
101 return eps
102
102
103 def teardown():
103 def teardown():
104 time.sleep(1)
104 time.sleep(1)
105 while launchers:
105 while launchers:
106 p = launchers.pop()
106 p = launchers.pop()
107 if p.poll() is None:
107 if p.poll() is None:
108 try:
108 try:
109 p.stop()
109 p.stop()
110 except Exception, e:
110 except Exception as e:
111 print e
111 print e
112 pass
112 pass
113 if p.poll() is None:
113 if p.poll() is None:
114 time.sleep(.25)
114 time.sleep(.25)
115 if p.poll() is None:
115 if p.poll() is None:
116 try:
116 try:
117 print 'cleaning up test process...'
117 print 'cleaning up test process...'
118 p.signal(SIGKILL)
118 p.signal(SIGKILL)
119 except:
119 except:
120 print "couldn't shutdown process: ", p
120 print "couldn't shutdown process: ", p
121 blackhole.close()
121 blackhole.close()
122
122
@@ -1,98 +1,98 b''
1 """ Fun magic line editor for ipython
1 """ Fun magic line editor for ipython
2
2
3 Use this to easily edit lists of strings gradually without crafting long
3 Use this to easily edit lists of strings gradually without crafting long
4 list comprehensions.
4 list comprehensions.
5
5
6 'l' is the magic variable name for every line (array element). Save the current
6 'l' is the magic variable name for every line (array element). Save the current
7 result (or more exactly, retrieve the last ipython computation result into
7 result (or more exactly, retrieve the last ipython computation result into
8 %led work area) by running '%led s'. Just run '%led' to show the current work
8 %led work area) by running '%led s'. Just run '%led' to show the current work
9 area data.
9 area data.
10
10
11 Example use:
11 Example use:
12
12
13 [ipython]|25> setups = !ls *setup*.py
13 [ipython]|25> setups = !ls *setup*.py
14 ==
14 ==
15 ['eggsetup.py', 'setup.py', 'setup_bdist_egg.py']
15 ['eggsetup.py', 'setup.py', 'setup_bdist_egg.py']
16 [ipython]|26> setups
16 [ipython]|26> setups
17 <26> ['eggsetup.py', 'setup.py', 'setup_bdist_egg.py']
17 <26> ['eggsetup.py', 'setup.py', 'setup_bdist_egg.py']
18 [ipython]|27> %led s
18 [ipython]|27> %led s
19 Data set from last result (_)
19 Data set from last result (_)
20 <27> ['eggsetup.py', 'setup.py', 'setup_bdist_egg.py']
20 <27> ['eggsetup.py', 'setup.py', 'setup_bdist_egg.py']
21 [ipython]|28> %led upper
21 [ipython]|28> %led upper
22 cmd translated => l.upper()
22 cmd translated => l.upper()
23 <28> ['EGGSETUP.PY', 'SETUP.PY', 'SETUP_BDIST_EGG.PY']
23 <28> ['EGGSETUP.PY', 'SETUP.PY', 'SETUP_BDIST_EGG.PY']
24 [ipython]|29> %led
24 [ipython]|29> %led
25 Magic line editor (for lists of strings)
25 Magic line editor (for lists of strings)
26 current data is:
26 current data is:
27 ['eggsetup.py', 'setup.py', 'setup_bdist_egg.py']
27 ['eggsetup.py', 'setup.py', 'setup_bdist_egg.py']
28 [ipython]|30> %led upper
28 [ipython]|30> %led upper
29 cmd translated => l.upper()
29 cmd translated => l.upper()
30 <30> ['EGGSETUP.PY', 'SETUP.PY', 'SETUP_BDIST_EGG.PY']
30 <30> ['EGGSETUP.PY', 'SETUP.PY', 'SETUP_BDIST_EGG.PY']
31 [ipython]|31> %led s
31 [ipython]|31> %led s
32 Data set from last result (_)
32 Data set from last result (_)
33 <31> ['EGGSETUP.PY', 'SETUP.PY', 'SETUP_BDIST_EGG.PY']
33 <31> ['EGGSETUP.PY', 'SETUP.PY', 'SETUP_BDIST_EGG.PY']
34 [ipython]|32> %led "n:" + l
34 [ipython]|32> %led "n:" + l
35 <32> ['n:EGGSETUP.PY', 'n:SETUP.PY', 'n:SETUP_BDIST_EGG.PY']
35 <32> ['n:EGGSETUP.PY', 'n:SETUP.PY', 'n:SETUP_BDIST_EGG.PY']
36 [ipython]|33> %led s
36 [ipython]|33> %led s
37 Data set from last result (_)
37 Data set from last result (_)
38 <33> ['n:EGGSETUP.PY', 'n:SETUP.PY', 'n:SETUP_BDIST_EGG.PY']
38 <33> ['n:EGGSETUP.PY', 'n:SETUP.PY', 'n:SETUP_BDIST_EGG.PY']
39 [ipython]|34> %led l.
39 [ipython]|34> %led l.
40 l.__add__ l.__gt__ l.__reduce_ex__ l.endswith l.join l.rstrip
40 l.__add__ l.__gt__ l.__reduce_ex__ l.endswith l.join l.rstrip
41 l.__class__ l.__hash__ l.__repr__ l.expandtabs l.ljust l.split
41 l.__class__ l.__hash__ l.__repr__ l.expandtabs l.ljust l.split
42
42
43 ... (completions for string variable shown ) ...
43 ... (completions for string variable shown ) ...
44
44
45 """
45 """
46 from IPython.core import ipapi
46 from IPython.core import ipapi
47 import pprint
47 import pprint
48 ip = ipapi.get()
48 ip = ipapi.get()
49
49
50 curdata = []
50 curdata = []
51
51
52 def line_edit_f(self, cmd ):
52 def line_edit_f(self, cmd ):
53 global curdata
53 global curdata
54
54
55 if not cmd:
55 if not cmd:
56
56
57 print "Magic line editor (for lists of strings)"
57 print "Magic line editor (for lists of strings)"
58 if curdata:
58 if curdata:
59 print "current data is:"
59 print "current data is:"
60 pprint.pprint(curdata)
60 pprint.pprint(curdata)
61 else:
61 else:
62 print "No current data, you should set it by running '%led s'"
62 print "No current data, you should set it by running '%led s'"
63 print "When you have your data in _ (result of last computation)."
63 print "When you have your data in _ (result of last computation)."
64 return
64 return
65
65
66 if cmd == 's':
66 if cmd == 's':
67 curdata = ip.ev('_')
67 curdata = ip.ev('_')
68 print "Data set from last result (_)"
68 print "Data set from last result (_)"
69 newlines = curdata
69 newlines = curdata
70
70
71 else:
71 else:
72 # simple method call, e.g. upper
72 # simple method call, e.g. upper
73 if cmd.isalpha():
73 if cmd.isalpha():
74 cmd = 'l.' + cmd + '()'
74 cmd = 'l.' + cmd + '()'
75 print "cmd translated =>",cmd
75 print "cmd translated =>",cmd
76
76
77 newlines = []
77 newlines = []
78 for l in curdata:
78 for l in curdata:
79 try:
79 try:
80 l2 = eval(cmd)
80 l2 = eval(cmd)
81 except Exception,e:
81 except Exception as e:
82 print "Dropping exception",e,"on line:",l
82 print "Dropping exception",e,"on line:",l
83 continue
83 continue
84 newlines.append(l2)
84 newlines.append(l2)
85
85
86
86
87 return newlines
87 return newlines
88
88
89 def line_edit_complete_f(self,event):
89 def line_edit_complete_f(self,event):
90 """ Show all string methods in completions """
90 """ Show all string methods in completions """
91 if event.symbol.startswith('l.'):
91 if event.symbol.startswith('l.'):
92 return ['l.' + func for func in dir('')]
92 return ['l.' + func for func in dir('')]
93
93
94 return dir('') + ['l.' + func for func in dir('')]
94 return dir('') + ['l.' + func for func in dir('')]
95
95
96 ip.set_hook('complete_command', line_edit_complete_f , str_key = '%led')
96 ip.set_hook('complete_command', line_edit_complete_f , str_key = '%led')
97
97
98 ip.define_magic('led', line_edit_f) No newline at end of file
98 ip.define_magic('led', line_edit_f)
@@ -1,811 +1,811 b''
1 """Nose Plugin that supports IPython doctests.
1 """Nose Plugin that supports IPython doctests.
2
2
3 Limitations:
3 Limitations:
4
4
5 - When generating examples for use as doctests, make sure that you have
5 - When generating examples for use as doctests, make sure that you have
6 pretty-printing OFF. This can be done either by setting the
6 pretty-printing OFF. This can be done either by setting the
7 ``PlainTextFormatter.pprint`` option in your configuration file to False, or
7 ``PlainTextFormatter.pprint`` option in your configuration file to False, or
8 by interactively disabling it with %Pprint. This is required so that IPython
8 by interactively disabling it with %Pprint. This is required so that IPython
9 output matches that of normal Python, which is used by doctest for internal
9 output matches that of normal Python, which is used by doctest for internal
10 execution.
10 execution.
11
11
12 - Do not rely on specific prompt numbers for results (such as using
12 - Do not rely on specific prompt numbers for results (such as using
13 '_34==True', for example). For IPython tests run via an external process the
13 '_34==True', for example). For IPython tests run via an external process the
14 prompt numbers may be different, and IPython tests run as normal python code
14 prompt numbers may be different, and IPython tests run as normal python code
15 won't even have these special _NN variables set at all.
15 won't even have these special _NN variables set at all.
16 """
16 """
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Module imports
19 # Module imports
20
20
21 # From the standard library
21 # From the standard library
22 import __builtin__ as builtin_mod
22 import __builtin__ as builtin_mod
23 import commands
23 import commands
24 import doctest
24 import doctest
25 import inspect
25 import inspect
26 import logging
26 import logging
27 import os
27 import os
28 import re
28 import re
29 import sys
29 import sys
30 import traceback
30 import traceback
31 import unittest
31 import unittest
32
32
33 from inspect import getmodule
33 from inspect import getmodule
34 from StringIO import StringIO
34 from StringIO import StringIO
35
35
36 # We are overriding the default doctest runner, so we need to import a few
36 # We are overriding the default doctest runner, so we need to import a few
37 # things from doctest directly
37 # things from doctest directly
38 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
38 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
39 _unittest_reportflags, DocTestRunner,
39 _unittest_reportflags, DocTestRunner,
40 _extract_future_flags, pdb, _OutputRedirectingPdb,
40 _extract_future_flags, pdb, _OutputRedirectingPdb,
41 _exception_traceback,
41 _exception_traceback,
42 linecache)
42 linecache)
43
43
44 # Third-party modules
44 # Third-party modules
45 import nose.core
45 import nose.core
46
46
47 from nose.plugins import doctests, Plugin
47 from nose.plugins import doctests, Plugin
48 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
48 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
49
49
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51 # Module globals and other constants
51 # Module globals and other constants
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53
53
54 log = logging.getLogger(__name__)
54 log = logging.getLogger(__name__)
55
55
56
56
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58 # Classes and functions
58 # Classes and functions
59 #-----------------------------------------------------------------------------
59 #-----------------------------------------------------------------------------
60
60
61 def is_extension_module(filename):
61 def is_extension_module(filename):
62 """Return whether the given filename is an extension module.
62 """Return whether the given filename is an extension module.
63
63
64 This simply checks that the extension is either .so or .pyd.
64 This simply checks that the extension is either .so or .pyd.
65 """
65 """
66 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
66 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
67
67
68
68
69 class DocTestSkip(object):
69 class DocTestSkip(object):
70 """Object wrapper for doctests to be skipped."""
70 """Object wrapper for doctests to be skipped."""
71
71
72 ds_skip = """Doctest to skip.
72 ds_skip = """Doctest to skip.
73 >>> 1 #doctest: +SKIP
73 >>> 1 #doctest: +SKIP
74 """
74 """
75
75
76 def __init__(self,obj):
76 def __init__(self,obj):
77 self.obj = obj
77 self.obj = obj
78
78
79 def __getattribute__(self,key):
79 def __getattribute__(self,key):
80 if key == '__doc__':
80 if key == '__doc__':
81 return DocTestSkip.ds_skip
81 return DocTestSkip.ds_skip
82 else:
82 else:
83 return getattr(object.__getattribute__(self,'obj'),key)
83 return getattr(object.__getattribute__(self,'obj'),key)
84
84
85 # Modified version of the one in the stdlib, that fixes a python bug (doctests
85 # Modified version of the one in the stdlib, that fixes a python bug (doctests
86 # not found in extension modules, http://bugs.python.org/issue3158)
86 # not found in extension modules, http://bugs.python.org/issue3158)
87 class DocTestFinder(doctest.DocTestFinder):
87 class DocTestFinder(doctest.DocTestFinder):
88
88
89 def _from_module(self, module, object):
89 def _from_module(self, module, object):
90 """
90 """
91 Return true if the given object is defined in the given
91 Return true if the given object is defined in the given
92 module.
92 module.
93 """
93 """
94 if module is None:
94 if module is None:
95 return True
95 return True
96 elif inspect.isfunction(object):
96 elif inspect.isfunction(object):
97 return module.__dict__ is object.func_globals
97 return module.__dict__ is object.func_globals
98 elif inspect.isbuiltin(object):
98 elif inspect.isbuiltin(object):
99 return module.__name__ == object.__module__
99 return module.__name__ == object.__module__
100 elif inspect.isclass(object):
100 elif inspect.isclass(object):
101 return module.__name__ == object.__module__
101 return module.__name__ == object.__module__
102 elif inspect.ismethod(object):
102 elif inspect.ismethod(object):
103 # This one may be a bug in cython that fails to correctly set the
103 # This one may be a bug in cython that fails to correctly set the
104 # __module__ attribute of methods, but since the same error is easy
104 # __module__ attribute of methods, but since the same error is easy
105 # to make by extension code writers, having this safety in place
105 # to make by extension code writers, having this safety in place
106 # isn't such a bad idea
106 # isn't such a bad idea
107 return module.__name__ == object.im_class.__module__
107 return module.__name__ == object.im_class.__module__
108 elif inspect.getmodule(object) is not None:
108 elif inspect.getmodule(object) is not None:
109 return module is inspect.getmodule(object)
109 return module is inspect.getmodule(object)
110 elif hasattr(object, '__module__'):
110 elif hasattr(object, '__module__'):
111 return module.__name__ == object.__module__
111 return module.__name__ == object.__module__
112 elif isinstance(object, property):
112 elif isinstance(object, property):
113 return True # [XX] no way not be sure.
113 return True # [XX] no way not be sure.
114 else:
114 else:
115 raise ValueError("object must be a class or function")
115 raise ValueError("object must be a class or function")
116
116
117 def _find(self, tests, obj, name, module, source_lines, globs, seen):
117 def _find(self, tests, obj, name, module, source_lines, globs, seen):
118 """
118 """
119 Find tests for the given object and any contained objects, and
119 Find tests for the given object and any contained objects, and
120 add them to `tests`.
120 add them to `tests`.
121 """
121 """
122 #print '_find for:', obj, name, module # dbg
122 #print '_find for:', obj, name, module # dbg
123 if hasattr(obj,"skip_doctest"):
123 if hasattr(obj,"skip_doctest"):
124 #print 'SKIPPING DOCTEST FOR:',obj # dbg
124 #print 'SKIPPING DOCTEST FOR:',obj # dbg
125 obj = DocTestSkip(obj)
125 obj = DocTestSkip(obj)
126
126
127 doctest.DocTestFinder._find(self,tests, obj, name, module,
127 doctest.DocTestFinder._find(self,tests, obj, name, module,
128 source_lines, globs, seen)
128 source_lines, globs, seen)
129
129
130 # Below we re-run pieces of the above method with manual modifications,
130 # Below we re-run pieces of the above method with manual modifications,
131 # because the original code is buggy and fails to correctly identify
131 # because the original code is buggy and fails to correctly identify
132 # doctests in extension modules.
132 # doctests in extension modules.
133
133
134 # Local shorthands
134 # Local shorthands
135 from inspect import isroutine, isclass, ismodule
135 from inspect import isroutine, isclass, ismodule
136
136
137 # Look for tests in a module's contained objects.
137 # Look for tests in a module's contained objects.
138 if inspect.ismodule(obj) and self._recurse:
138 if inspect.ismodule(obj) and self._recurse:
139 for valname, val in obj.__dict__.items():
139 for valname, val in obj.__dict__.items():
140 valname1 = '%s.%s' % (name, valname)
140 valname1 = '%s.%s' % (name, valname)
141 if ( (isroutine(val) or isclass(val))
141 if ( (isroutine(val) or isclass(val))
142 and self._from_module(module, val) ):
142 and self._from_module(module, val) ):
143
143
144 self._find(tests, val, valname1, module, source_lines,
144 self._find(tests, val, valname1, module, source_lines,
145 globs, seen)
145 globs, seen)
146
146
147 # Look for tests in a class's contained objects.
147 # Look for tests in a class's contained objects.
148 if inspect.isclass(obj) and self._recurse:
148 if inspect.isclass(obj) and self._recurse:
149 #print 'RECURSE into class:',obj # dbg
149 #print 'RECURSE into class:',obj # dbg
150 for valname, val in obj.__dict__.items():
150 for valname, val in obj.__dict__.items():
151 # Special handling for staticmethod/classmethod.
151 # Special handling for staticmethod/classmethod.
152 if isinstance(val, staticmethod):
152 if isinstance(val, staticmethod):
153 val = getattr(obj, valname)
153 val = getattr(obj, valname)
154 if isinstance(val, classmethod):
154 if isinstance(val, classmethod):
155 val = getattr(obj, valname).im_func
155 val = getattr(obj, valname).im_func
156
156
157 # Recurse to methods, properties, and nested classes.
157 # Recurse to methods, properties, and nested classes.
158 if ((inspect.isfunction(val) or inspect.isclass(val) or
158 if ((inspect.isfunction(val) or inspect.isclass(val) or
159 inspect.ismethod(val) or
159 inspect.ismethod(val) or
160 isinstance(val, property)) and
160 isinstance(val, property)) and
161 self._from_module(module, val)):
161 self._from_module(module, val)):
162 valname = '%s.%s' % (name, valname)
162 valname = '%s.%s' % (name, valname)
163 self._find(tests, val, valname, module, source_lines,
163 self._find(tests, val, valname, module, source_lines,
164 globs, seen)
164 globs, seen)
165
165
166
166
167 class IPDoctestOutputChecker(doctest.OutputChecker):
167 class IPDoctestOutputChecker(doctest.OutputChecker):
168 """Second-chance checker with support for random tests.
168 """Second-chance checker with support for random tests.
169
169
170 If the default comparison doesn't pass, this checker looks in the expected
170 If the default comparison doesn't pass, this checker looks in the expected
171 output string for flags that tell us to ignore the output.
171 output string for flags that tell us to ignore the output.
172 """
172 """
173
173
174 random_re = re.compile(r'#\s*random\s+')
174 random_re = re.compile(r'#\s*random\s+')
175
175
176 def check_output(self, want, got, optionflags):
176 def check_output(self, want, got, optionflags):
177 """Check output, accepting special markers embedded in the output.
177 """Check output, accepting special markers embedded in the output.
178
178
179 If the output didn't pass the default validation but the special string
179 If the output didn't pass the default validation but the special string
180 '#random' is included, we accept it."""
180 '#random' is included, we accept it."""
181
181
182 # Let the original tester verify first, in case people have valid tests
182 # Let the original tester verify first, in case people have valid tests
183 # that happen to have a comment saying '#random' embedded in.
183 # that happen to have a comment saying '#random' embedded in.
184 ret = doctest.OutputChecker.check_output(self, want, got,
184 ret = doctest.OutputChecker.check_output(self, want, got,
185 optionflags)
185 optionflags)
186 if not ret and self.random_re.search(want):
186 if not ret and self.random_re.search(want):
187 #print >> sys.stderr, 'RANDOM OK:',want # dbg
187 #print >> sys.stderr, 'RANDOM OK:',want # dbg
188 return True
188 return True
189
189
190 return ret
190 return ret
191
191
192
192
193 class DocTestCase(doctests.DocTestCase):
193 class DocTestCase(doctests.DocTestCase):
194 """Proxy for DocTestCase: provides an address() method that
194 """Proxy for DocTestCase: provides an address() method that
195 returns the correct address for the doctest case. Otherwise
195 returns the correct address for the doctest case. Otherwise
196 acts as a proxy to the test case. To provide hints for address(),
196 acts as a proxy to the test case. To provide hints for address(),
197 an obj may also be passed -- this will be used as the test object
197 an obj may also be passed -- this will be used as the test object
198 for purposes of determining the test address, if it is provided.
198 for purposes of determining the test address, if it is provided.
199 """
199 """
200
200
201 # Note: this method was taken from numpy's nosetester module.
201 # Note: this method was taken from numpy's nosetester module.
202
202
203 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
203 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
204 # its constructor that blocks non-default arguments from being passed
204 # its constructor that blocks non-default arguments from being passed
205 # down into doctest.DocTestCase
205 # down into doctest.DocTestCase
206
206
207 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
207 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
208 checker=None, obj=None, result_var='_'):
208 checker=None, obj=None, result_var='_'):
209 self._result_var = result_var
209 self._result_var = result_var
210 doctests.DocTestCase.__init__(self, test,
210 doctests.DocTestCase.__init__(self, test,
211 optionflags=optionflags,
211 optionflags=optionflags,
212 setUp=setUp, tearDown=tearDown,
212 setUp=setUp, tearDown=tearDown,
213 checker=checker)
213 checker=checker)
214 # Now we must actually copy the original constructor from the stdlib
214 # Now we must actually copy the original constructor from the stdlib
215 # doctest class, because we can't call it directly and a bug in nose
215 # doctest class, because we can't call it directly and a bug in nose
216 # means it never gets passed the right arguments.
216 # means it never gets passed the right arguments.
217
217
218 self._dt_optionflags = optionflags
218 self._dt_optionflags = optionflags
219 self._dt_checker = checker
219 self._dt_checker = checker
220 self._dt_test = test
220 self._dt_test = test
221 self._dt_test_globs_ori = test.globs
221 self._dt_test_globs_ori = test.globs
222 self._dt_setUp = setUp
222 self._dt_setUp = setUp
223 self._dt_tearDown = tearDown
223 self._dt_tearDown = tearDown
224
224
225 # XXX - store this runner once in the object!
225 # XXX - store this runner once in the object!
226 runner = IPDocTestRunner(optionflags=optionflags,
226 runner = IPDocTestRunner(optionflags=optionflags,
227 checker=checker, verbose=False)
227 checker=checker, verbose=False)
228 self._dt_runner = runner
228 self._dt_runner = runner
229
229
230
230
231 # Each doctest should remember the directory it was loaded from, so
231 # Each doctest should remember the directory it was loaded from, so
232 # things like %run work without too many contortions
232 # things like %run work without too many contortions
233 self._ori_dir = os.path.dirname(test.filename)
233 self._ori_dir = os.path.dirname(test.filename)
234
234
235 # Modified runTest from the default stdlib
235 # Modified runTest from the default stdlib
236 def runTest(self):
236 def runTest(self):
237 test = self._dt_test
237 test = self._dt_test
238 runner = self._dt_runner
238 runner = self._dt_runner
239
239
240 old = sys.stdout
240 old = sys.stdout
241 new = StringIO()
241 new = StringIO()
242 optionflags = self._dt_optionflags
242 optionflags = self._dt_optionflags
243
243
244 if not (optionflags & REPORTING_FLAGS):
244 if not (optionflags & REPORTING_FLAGS):
245 # The option flags don't include any reporting flags,
245 # The option flags don't include any reporting flags,
246 # so add the default reporting flags
246 # so add the default reporting flags
247 optionflags |= _unittest_reportflags
247 optionflags |= _unittest_reportflags
248
248
249 try:
249 try:
250 # Save our current directory and switch out to the one where the
250 # Save our current directory and switch out to the one where the
251 # test was originally created, in case another doctest did a
251 # test was originally created, in case another doctest did a
252 # directory change. We'll restore this in the finally clause.
252 # directory change. We'll restore this in the finally clause.
253 curdir = os.getcwdu()
253 curdir = os.getcwdu()
254 #print 'runTest in dir:', self._ori_dir # dbg
254 #print 'runTest in dir:', self._ori_dir # dbg
255 os.chdir(self._ori_dir)
255 os.chdir(self._ori_dir)
256
256
257 runner.DIVIDER = "-"*70
257 runner.DIVIDER = "-"*70
258 failures, tries = runner.run(test,out=new.write,
258 failures, tries = runner.run(test,out=new.write,
259 clear_globs=False)
259 clear_globs=False)
260 finally:
260 finally:
261 sys.stdout = old
261 sys.stdout = old
262 os.chdir(curdir)
262 os.chdir(curdir)
263
263
264 if failures:
264 if failures:
265 raise self.failureException(self.format_failure(new.getvalue()))
265 raise self.failureException(self.format_failure(new.getvalue()))
266
266
267 def setUp(self):
267 def setUp(self):
268 """Modified test setup that syncs with ipython namespace"""
268 """Modified test setup that syncs with ipython namespace"""
269 #print "setUp test", self._dt_test.examples # dbg
269 #print "setUp test", self._dt_test.examples # dbg
270 if isinstance(self._dt_test.examples[0], IPExample):
270 if isinstance(self._dt_test.examples[0], IPExample):
271 # for IPython examples *only*, we swap the globals with the ipython
271 # for IPython examples *only*, we swap the globals with the ipython
272 # namespace, after updating it with the globals (which doctest
272 # namespace, after updating it with the globals (which doctest
273 # fills with the necessary info from the module being tested).
273 # fills with the necessary info from the module being tested).
274 self.user_ns_orig = {}
274 self.user_ns_orig = {}
275 self.user_ns_orig.update(_ip.user_ns)
275 self.user_ns_orig.update(_ip.user_ns)
276 _ip.user_ns.update(self._dt_test.globs)
276 _ip.user_ns.update(self._dt_test.globs)
277 # We must remove the _ key in the namespace, so that Python's
277 # We must remove the _ key in the namespace, so that Python's
278 # doctest code sets it naturally
278 # doctest code sets it naturally
279 _ip.user_ns.pop('_', None)
279 _ip.user_ns.pop('_', None)
280 _ip.user_ns['__builtins__'] = builtin_mod
280 _ip.user_ns['__builtins__'] = builtin_mod
281 self._dt_test.globs = _ip.user_ns
281 self._dt_test.globs = _ip.user_ns
282
282
283 super(DocTestCase, self).setUp()
283 super(DocTestCase, self).setUp()
284
284
285 def tearDown(self):
285 def tearDown(self):
286
286
287 # Undo the test.globs reassignment we made, so that the parent class
287 # Undo the test.globs reassignment we made, so that the parent class
288 # teardown doesn't destroy the ipython namespace
288 # teardown doesn't destroy the ipython namespace
289 if isinstance(self._dt_test.examples[0], IPExample):
289 if isinstance(self._dt_test.examples[0], IPExample):
290 self._dt_test.globs = self._dt_test_globs_ori
290 self._dt_test.globs = self._dt_test_globs_ori
291 _ip.user_ns.clear()
291 _ip.user_ns.clear()
292 _ip.user_ns.update(self.user_ns_orig)
292 _ip.user_ns.update(self.user_ns_orig)
293
293
294 # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
294 # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
295 # it does look like one to me: its tearDown method tries to run
295 # it does look like one to me: its tearDown method tries to run
296 #
296 #
297 # delattr(__builtin__, self._result_var)
297 # delattr(__builtin__, self._result_var)
298 #
298 #
299 # without checking that the attribute really is there; it implicitly
299 # without checking that the attribute really is there; it implicitly
300 # assumes it should have been set via displayhook. But if the
300 # assumes it should have been set via displayhook. But if the
301 # displayhook was never called, this doesn't necessarily happen. I
301 # displayhook was never called, this doesn't necessarily happen. I
302 # haven't been able to find a little self-contained example outside of
302 # haven't been able to find a little self-contained example outside of
303 # ipython that would show the problem so I can report it to the nose
303 # ipython that would show the problem so I can report it to the nose
304 # team, but it does happen a lot in our code.
304 # team, but it does happen a lot in our code.
305 #
305 #
306 # So here, we just protect as narrowly as possible by trapping an
306 # So here, we just protect as narrowly as possible by trapping an
307 # attribute error whose message would be the name of self._result_var,
307 # attribute error whose message would be the name of self._result_var,
308 # and letting any other error propagate.
308 # and letting any other error propagate.
309 try:
309 try:
310 super(DocTestCase, self).tearDown()
310 super(DocTestCase, self).tearDown()
311 except AttributeError, exc:
311 except AttributeError as exc:
312 if exc.args[0] != self._result_var:
312 if exc.args[0] != self._result_var:
313 raise
313 raise
314
314
315
315
316 # A simple subclassing of the original with a different class name, so we can
316 # A simple subclassing of the original with a different class name, so we can
317 # distinguish and treat differently IPython examples from pure python ones.
317 # distinguish and treat differently IPython examples from pure python ones.
318 class IPExample(doctest.Example): pass
318 class IPExample(doctest.Example): pass
319
319
320
320
321 class IPExternalExample(doctest.Example):
321 class IPExternalExample(doctest.Example):
322 """Doctest examples to be run in an external process."""
322 """Doctest examples to be run in an external process."""
323
323
324 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
324 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
325 options=None):
325 options=None):
326 # Parent constructor
326 # Parent constructor
327 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
327 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
328
328
329 # An EXTRA newline is needed to prevent pexpect hangs
329 # An EXTRA newline is needed to prevent pexpect hangs
330 self.source += '\n'
330 self.source += '\n'
331
331
332
332
333 class IPDocTestParser(doctest.DocTestParser):
333 class IPDocTestParser(doctest.DocTestParser):
334 """
334 """
335 A class used to parse strings containing doctest examples.
335 A class used to parse strings containing doctest examples.
336
336
337 Note: This is a version modified to properly recognize IPython input and
337 Note: This is a version modified to properly recognize IPython input and
338 convert any IPython examples into valid Python ones.
338 convert any IPython examples into valid Python ones.
339 """
339 """
340 # This regular expression is used to find doctest examples in a
340 # This regular expression is used to find doctest examples in a
341 # string. It defines three groups: `source` is the source code
341 # string. It defines three groups: `source` is the source code
342 # (including leading indentation and prompts); `indent` is the
342 # (including leading indentation and prompts); `indent` is the
343 # indentation of the first (PS1) line of the source code; and
343 # indentation of the first (PS1) line of the source code; and
344 # `want` is the expected output (including leading indentation).
344 # `want` is the expected output (including leading indentation).
345
345
346 # Classic Python prompts or default IPython ones
346 # Classic Python prompts or default IPython ones
347 _PS1_PY = r'>>>'
347 _PS1_PY = r'>>>'
348 _PS2_PY = r'\.\.\.'
348 _PS2_PY = r'\.\.\.'
349
349
350 _PS1_IP = r'In\ \[\d+\]:'
350 _PS1_IP = r'In\ \[\d+\]:'
351 _PS2_IP = r'\ \ \ \.\.\.+:'
351 _PS2_IP = r'\ \ \ \.\.\.+:'
352
352
353 _RE_TPL = r'''
353 _RE_TPL = r'''
354 # Source consists of a PS1 line followed by zero or more PS2 lines.
354 # Source consists of a PS1 line followed by zero or more PS2 lines.
355 (?P<source>
355 (?P<source>
356 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
356 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
357 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
357 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
358 \n? # a newline
358 \n? # a newline
359 # Want consists of any non-blank lines that do not start with PS1.
359 # Want consists of any non-blank lines that do not start with PS1.
360 (?P<want> (?:(?![ ]*$) # Not a blank line
360 (?P<want> (?:(?![ ]*$) # Not a blank line
361 (?![ ]*%s) # Not a line starting with PS1
361 (?![ ]*%s) # Not a line starting with PS1
362 (?![ ]*%s) # Not a line starting with PS2
362 (?![ ]*%s) # Not a line starting with PS2
363 .*$\n? # But any other line
363 .*$\n? # But any other line
364 )*)
364 )*)
365 '''
365 '''
366
366
367 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
367 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
368 re.MULTILINE | re.VERBOSE)
368 re.MULTILINE | re.VERBOSE)
369
369
370 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
370 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
371 re.MULTILINE | re.VERBOSE)
371 re.MULTILINE | re.VERBOSE)
372
372
373 # Mark a test as being fully random. In this case, we simply append the
373 # Mark a test as being fully random. In this case, we simply append the
374 # random marker ('#random') to each individual example's output. This way
374 # random marker ('#random') to each individual example's output. This way
375 # we don't need to modify any other code.
375 # we don't need to modify any other code.
376 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
376 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
377
377
378 # Mark tests to be executed in an external process - currently unsupported.
378 # Mark tests to be executed in an external process - currently unsupported.
379 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
379 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
380
380
381 def ip2py(self,source):
381 def ip2py(self,source):
382 """Convert input IPython source into valid Python."""
382 """Convert input IPython source into valid Python."""
383 out = []
383 out = []
384 newline = out.append
384 newline = out.append
385 #print 'IPSRC:\n',source,'\n###' # dbg
385 #print 'IPSRC:\n',source,'\n###' # dbg
386 # The input source must be first stripped of all bracketing whitespace
386 # The input source must be first stripped of all bracketing whitespace
387 # and turned into lines, so it looks to the parser like regular user
387 # and turned into lines, so it looks to the parser like regular user
388 # input
388 # input
389 for lnum,line in enumerate(source.strip().splitlines()):
389 for lnum,line in enumerate(source.strip().splitlines()):
390 newline(_ip.prefilter(line,lnum>0))
390 newline(_ip.prefilter(line,lnum>0))
391 newline('') # ensure a closing newline, needed by doctest
391 newline('') # ensure a closing newline, needed by doctest
392 #print "PYSRC:", '\n'.join(out) # dbg
392 #print "PYSRC:", '\n'.join(out) # dbg
393 return '\n'.join(out)
393 return '\n'.join(out)
394
394
395 def parse(self, string, name='<string>'):
395 def parse(self, string, name='<string>'):
396 """
396 """
397 Divide the given string into examples and intervening text,
397 Divide the given string into examples and intervening text,
398 and return them as a list of alternating Examples and strings.
398 and return them as a list of alternating Examples and strings.
399 Line numbers for the Examples are 0-based. The optional
399 Line numbers for the Examples are 0-based. The optional
400 argument `name` is a name identifying this string, and is only
400 argument `name` is a name identifying this string, and is only
401 used for error messages.
401 used for error messages.
402 """
402 """
403
403
404 #print 'Parse string:\n',string # dbg
404 #print 'Parse string:\n',string # dbg
405
405
406 string = string.expandtabs()
406 string = string.expandtabs()
407 # If all lines begin with the same indentation, then strip it.
407 # If all lines begin with the same indentation, then strip it.
408 min_indent = self._min_indent(string)
408 min_indent = self._min_indent(string)
409 if min_indent > 0:
409 if min_indent > 0:
410 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
410 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
411
411
412 output = []
412 output = []
413 charno, lineno = 0, 0
413 charno, lineno = 0, 0
414
414
415 # We make 'all random' tests by adding the '# random' mark to every
415 # We make 'all random' tests by adding the '# random' mark to every
416 # block of output in the test.
416 # block of output in the test.
417 if self._RANDOM_TEST.search(string):
417 if self._RANDOM_TEST.search(string):
418 random_marker = '\n# random'
418 random_marker = '\n# random'
419 else:
419 else:
420 random_marker = ''
420 random_marker = ''
421
421
422 # Whether to convert the input from ipython to python syntax
422 # Whether to convert the input from ipython to python syntax
423 ip2py = False
423 ip2py = False
424 # Find all doctest examples in the string. First, try them as Python
424 # Find all doctest examples in the string. First, try them as Python
425 # examples, then as IPython ones
425 # examples, then as IPython ones
426 terms = list(self._EXAMPLE_RE_PY.finditer(string))
426 terms = list(self._EXAMPLE_RE_PY.finditer(string))
427 if terms:
427 if terms:
428 # Normal Python example
428 # Normal Python example
429 #print '-'*70 # dbg
429 #print '-'*70 # dbg
430 #print 'PyExample, Source:\n',string # dbg
430 #print 'PyExample, Source:\n',string # dbg
431 #print '-'*70 # dbg
431 #print '-'*70 # dbg
432 Example = doctest.Example
432 Example = doctest.Example
433 else:
433 else:
434 # It's an ipython example. Note that IPExamples are run
434 # It's an ipython example. Note that IPExamples are run
435 # in-process, so their syntax must be turned into valid python.
435 # in-process, so their syntax must be turned into valid python.
436 # IPExternalExamples are run out-of-process (via pexpect) so they
436 # IPExternalExamples are run out-of-process (via pexpect) so they
437 # don't need any filtering (a real ipython will be executing them).
437 # don't need any filtering (a real ipython will be executing them).
438 terms = list(self._EXAMPLE_RE_IP.finditer(string))
438 terms = list(self._EXAMPLE_RE_IP.finditer(string))
439 if self._EXTERNAL_IP.search(string):
439 if self._EXTERNAL_IP.search(string):
440 #print '-'*70 # dbg
440 #print '-'*70 # dbg
441 #print 'IPExternalExample, Source:\n',string # dbg
441 #print 'IPExternalExample, Source:\n',string # dbg
442 #print '-'*70 # dbg
442 #print '-'*70 # dbg
443 Example = IPExternalExample
443 Example = IPExternalExample
444 else:
444 else:
445 #print '-'*70 # dbg
445 #print '-'*70 # dbg
446 #print 'IPExample, Source:\n',string # dbg
446 #print 'IPExample, Source:\n',string # dbg
447 #print '-'*70 # dbg
447 #print '-'*70 # dbg
448 Example = IPExample
448 Example = IPExample
449 ip2py = True
449 ip2py = True
450
450
451 for m in terms:
451 for m in terms:
452 # Add the pre-example text to `output`.
452 # Add the pre-example text to `output`.
453 output.append(string[charno:m.start()])
453 output.append(string[charno:m.start()])
454 # Update lineno (lines before this example)
454 # Update lineno (lines before this example)
455 lineno += string.count('\n', charno, m.start())
455 lineno += string.count('\n', charno, m.start())
456 # Extract info from the regexp match.
456 # Extract info from the regexp match.
457 (source, options, want, exc_msg) = \
457 (source, options, want, exc_msg) = \
458 self._parse_example(m, name, lineno,ip2py)
458 self._parse_example(m, name, lineno,ip2py)
459
459
460 # Append the random-output marker (it defaults to empty in most
460 # Append the random-output marker (it defaults to empty in most
461 # cases, it's only non-empty for 'all-random' tests):
461 # cases, it's only non-empty for 'all-random' tests):
462 want += random_marker
462 want += random_marker
463
463
464 if Example is IPExternalExample:
464 if Example is IPExternalExample:
465 options[doctest.NORMALIZE_WHITESPACE] = True
465 options[doctest.NORMALIZE_WHITESPACE] = True
466 want += '\n'
466 want += '\n'
467
467
468 # Create an Example, and add it to the list.
468 # Create an Example, and add it to the list.
469 if not self._IS_BLANK_OR_COMMENT(source):
469 if not self._IS_BLANK_OR_COMMENT(source):
470 output.append(Example(source, want, exc_msg,
470 output.append(Example(source, want, exc_msg,
471 lineno=lineno,
471 lineno=lineno,
472 indent=min_indent+len(m.group('indent')),
472 indent=min_indent+len(m.group('indent')),
473 options=options))
473 options=options))
474 # Update lineno (lines inside this example)
474 # Update lineno (lines inside this example)
475 lineno += string.count('\n', m.start(), m.end())
475 lineno += string.count('\n', m.start(), m.end())
476 # Update charno.
476 # Update charno.
477 charno = m.end()
477 charno = m.end()
478 # Add any remaining post-example text to `output`.
478 # Add any remaining post-example text to `output`.
479 output.append(string[charno:])
479 output.append(string[charno:])
480 return output
480 return output
481
481
482 def _parse_example(self, m, name, lineno,ip2py=False):
482 def _parse_example(self, m, name, lineno,ip2py=False):
483 """
483 """
484 Given a regular expression match from `_EXAMPLE_RE` (`m`),
484 Given a regular expression match from `_EXAMPLE_RE` (`m`),
485 return a pair `(source, want)`, where `source` is the matched
485 return a pair `(source, want)`, where `source` is the matched
486 example's source code (with prompts and indentation stripped);
486 example's source code (with prompts and indentation stripped);
487 and `want` is the example's expected output (with indentation
487 and `want` is the example's expected output (with indentation
488 stripped).
488 stripped).
489
489
490 `name` is the string's name, and `lineno` is the line number
490 `name` is the string's name, and `lineno` is the line number
491 where the example starts; both are used for error messages.
491 where the example starts; both are used for error messages.
492
492
493 Optional:
493 Optional:
494 `ip2py`: if true, filter the input via IPython to convert the syntax
494 `ip2py`: if true, filter the input via IPython to convert the syntax
495 into valid python.
495 into valid python.
496 """
496 """
497
497
498 # Get the example's indentation level.
498 # Get the example's indentation level.
499 indent = len(m.group('indent'))
499 indent = len(m.group('indent'))
500
500
501 # Divide source into lines; check that they're properly
501 # Divide source into lines; check that they're properly
502 # indented; and then strip their indentation & prompts.
502 # indented; and then strip their indentation & prompts.
503 source_lines = m.group('source').split('\n')
503 source_lines = m.group('source').split('\n')
504
504
505 # We're using variable-length input prompts
505 # We're using variable-length input prompts
506 ps1 = m.group('ps1')
506 ps1 = m.group('ps1')
507 ps2 = m.group('ps2')
507 ps2 = m.group('ps2')
508 ps1_len = len(ps1)
508 ps1_len = len(ps1)
509
509
510 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
510 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
511 if ps2:
511 if ps2:
512 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
512 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
513
513
514 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
514 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
515
515
516 if ip2py:
516 if ip2py:
517 # Convert source input from IPython into valid Python syntax
517 # Convert source input from IPython into valid Python syntax
518 source = self.ip2py(source)
518 source = self.ip2py(source)
519
519
520 # Divide want into lines; check that it's properly indented; and
520 # Divide want into lines; check that it's properly indented; and
521 # then strip the indentation. Spaces before the last newline should
521 # then strip the indentation. Spaces before the last newline should
522 # be preserved, so plain rstrip() isn't good enough.
522 # be preserved, so plain rstrip() isn't good enough.
523 want = m.group('want')
523 want = m.group('want')
524 want_lines = want.split('\n')
524 want_lines = want.split('\n')
525 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
525 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
526 del want_lines[-1] # forget final newline & spaces after it
526 del want_lines[-1] # forget final newline & spaces after it
527 self._check_prefix(want_lines, ' '*indent, name,
527 self._check_prefix(want_lines, ' '*indent, name,
528 lineno + len(source_lines))
528 lineno + len(source_lines))
529
529
530 # Remove ipython output prompt that might be present in the first line
530 # Remove ipython output prompt that might be present in the first line
531 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
531 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
532
532
533 want = '\n'.join([wl[indent:] for wl in want_lines])
533 want = '\n'.join([wl[indent:] for wl in want_lines])
534
534
535 # If `want` contains a traceback message, then extract it.
535 # If `want` contains a traceback message, then extract it.
536 m = self._EXCEPTION_RE.match(want)
536 m = self._EXCEPTION_RE.match(want)
537 if m:
537 if m:
538 exc_msg = m.group('msg')
538 exc_msg = m.group('msg')
539 else:
539 else:
540 exc_msg = None
540 exc_msg = None
541
541
542 # Extract options from the source.
542 # Extract options from the source.
543 options = self._find_options(source, name, lineno)
543 options = self._find_options(source, name, lineno)
544
544
545 return source, options, want, exc_msg
545 return source, options, want, exc_msg
546
546
547 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
547 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
548 """
548 """
549 Given the lines of a source string (including prompts and
549 Given the lines of a source string (including prompts and
550 leading indentation), check to make sure that every prompt is
550 leading indentation), check to make sure that every prompt is
551 followed by a space character. If any line is not followed by
551 followed by a space character. If any line is not followed by
552 a space character, then raise ValueError.
552 a space character, then raise ValueError.
553
553
554 Note: IPython-modified version which takes the input prompt length as a
554 Note: IPython-modified version which takes the input prompt length as a
555 parameter, so that prompts of variable length can be dealt with.
555 parameter, so that prompts of variable length can be dealt with.
556 """
556 """
557 space_idx = indent+ps1_len
557 space_idx = indent+ps1_len
558 min_len = space_idx+1
558 min_len = space_idx+1
559 for i, line in enumerate(lines):
559 for i, line in enumerate(lines):
560 if len(line) >= min_len and line[space_idx] != ' ':
560 if len(line) >= min_len and line[space_idx] != ' ':
561 raise ValueError('line %r of the docstring for %s '
561 raise ValueError('line %r of the docstring for %s '
562 'lacks blank after %s: %r' %
562 'lacks blank after %s: %r' %
563 (lineno+i+1, name,
563 (lineno+i+1, name,
564 line[indent:space_idx], line))
564 line[indent:space_idx], line))
565
565
566
566
567 SKIP = doctest.register_optionflag('SKIP')
567 SKIP = doctest.register_optionflag('SKIP')
568
568
569
569
570 class IPDocTestRunner(doctest.DocTestRunner,object):
570 class IPDocTestRunner(doctest.DocTestRunner,object):
571 """Test runner that synchronizes the IPython namespace with test globals.
571 """Test runner that synchronizes the IPython namespace with test globals.
572 """
572 """
573
573
574 def run(self, test, compileflags=None, out=None, clear_globs=True):
574 def run(self, test, compileflags=None, out=None, clear_globs=True):
575
575
576 # Hack: ipython needs access to the execution context of the example,
576 # Hack: ipython needs access to the execution context of the example,
577 # so that it can propagate user variables loaded by %run into
577 # so that it can propagate user variables loaded by %run into
578 # test.globs. We put them here into our modified %run as a function
578 # test.globs. We put them here into our modified %run as a function
579 # attribute. Our new %run will then only make the namespace update
579 # attribute. Our new %run will then only make the namespace update
580 # when called (rather than unconconditionally updating test.globs here
580 # when called (rather than unconconditionally updating test.globs here
581 # for all examples, most of which won't be calling %run anyway).
581 # for all examples, most of which won't be calling %run anyway).
582 #_ip._ipdoctest_test_globs = test.globs
582 #_ip._ipdoctest_test_globs = test.globs
583 #_ip._ipdoctest_test_filename = test.filename
583 #_ip._ipdoctest_test_filename = test.filename
584
584
585 test.globs.update(_ip.user_ns)
585 test.globs.update(_ip.user_ns)
586
586
587 return super(IPDocTestRunner,self).run(test,
587 return super(IPDocTestRunner,self).run(test,
588 compileflags,out,clear_globs)
588 compileflags,out,clear_globs)
589
589
590
590
591 class DocFileCase(doctest.DocFileCase):
591 class DocFileCase(doctest.DocFileCase):
592 """Overrides to provide filename
592 """Overrides to provide filename
593 """
593 """
594 def address(self):
594 def address(self):
595 return (self._dt_test.filename, None, None)
595 return (self._dt_test.filename, None, None)
596
596
597
597
598 class ExtensionDoctest(doctests.Doctest):
598 class ExtensionDoctest(doctests.Doctest):
599 """Nose Plugin that supports doctests in extension modules.
599 """Nose Plugin that supports doctests in extension modules.
600 """
600 """
601 name = 'extdoctest' # call nosetests with --with-extdoctest
601 name = 'extdoctest' # call nosetests with --with-extdoctest
602 enabled = True
602 enabled = True
603
603
604 def __init__(self,exclude_patterns=None):
604 def __init__(self,exclude_patterns=None):
605 """Create a new ExtensionDoctest plugin.
605 """Create a new ExtensionDoctest plugin.
606
606
607 Parameters
607 Parameters
608 ----------
608 ----------
609
609
610 exclude_patterns : sequence of strings, optional
610 exclude_patterns : sequence of strings, optional
611 These patterns are compiled as regular expressions, subsequently used
611 These patterns are compiled as regular expressions, subsequently used
612 to exclude any filename which matches them from inclusion in the test
612 to exclude any filename which matches them from inclusion in the test
613 suite (using pattern.search(), NOT pattern.match() ).
613 suite (using pattern.search(), NOT pattern.match() ).
614 """
614 """
615
615
616 if exclude_patterns is None:
616 if exclude_patterns is None:
617 exclude_patterns = []
617 exclude_patterns = []
618 self.exclude_patterns = map(re.compile,exclude_patterns)
618 self.exclude_patterns = map(re.compile,exclude_patterns)
619 doctests.Doctest.__init__(self)
619 doctests.Doctest.__init__(self)
620
620
621 def options(self, parser, env=os.environ):
621 def options(self, parser, env=os.environ):
622 Plugin.options(self, parser, env)
622 Plugin.options(self, parser, env)
623 parser.add_option('--doctest-tests', action='store_true',
623 parser.add_option('--doctest-tests', action='store_true',
624 dest='doctest_tests',
624 dest='doctest_tests',
625 default=env.get('NOSE_DOCTEST_TESTS',True),
625 default=env.get('NOSE_DOCTEST_TESTS',True),
626 help="Also look for doctests in test modules. "
626 help="Also look for doctests in test modules. "
627 "Note that classes, methods and functions should "
627 "Note that classes, methods and functions should "
628 "have either doctests or non-doctest tests, "
628 "have either doctests or non-doctest tests, "
629 "not both. [NOSE_DOCTEST_TESTS]")
629 "not both. [NOSE_DOCTEST_TESTS]")
630 parser.add_option('--doctest-extension', action="append",
630 parser.add_option('--doctest-extension', action="append",
631 dest="doctestExtension",
631 dest="doctestExtension",
632 help="Also look for doctests in files with "
632 help="Also look for doctests in files with "
633 "this extension [NOSE_DOCTEST_EXTENSION]")
633 "this extension [NOSE_DOCTEST_EXTENSION]")
634 # Set the default as a list, if given in env; otherwise
634 # Set the default as a list, if given in env; otherwise
635 # an additional value set on the command line will cause
635 # an additional value set on the command line will cause
636 # an error.
636 # an error.
637 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
637 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
638 if env_setting is not None:
638 if env_setting is not None:
639 parser.set_defaults(doctestExtension=tolist(env_setting))
639 parser.set_defaults(doctestExtension=tolist(env_setting))
640
640
641
641
642 def configure(self, options, config):
642 def configure(self, options, config):
643 Plugin.configure(self, options, config)
643 Plugin.configure(self, options, config)
644 # Pull standard doctest plugin out of config; we will do doctesting
644 # Pull standard doctest plugin out of config; we will do doctesting
645 config.plugins.plugins = [p for p in config.plugins.plugins
645 config.plugins.plugins = [p for p in config.plugins.plugins
646 if p.name != 'doctest']
646 if p.name != 'doctest']
647 self.doctest_tests = options.doctest_tests
647 self.doctest_tests = options.doctest_tests
648 self.extension = tolist(options.doctestExtension)
648 self.extension = tolist(options.doctestExtension)
649
649
650 self.parser = doctest.DocTestParser()
650 self.parser = doctest.DocTestParser()
651 self.finder = DocTestFinder()
651 self.finder = DocTestFinder()
652 self.checker = IPDoctestOutputChecker()
652 self.checker = IPDoctestOutputChecker()
653 self.globs = None
653 self.globs = None
654 self.extraglobs = None
654 self.extraglobs = None
655
655
656
656
657 def loadTestsFromExtensionModule(self,filename):
657 def loadTestsFromExtensionModule(self,filename):
658 bpath,mod = os.path.split(filename)
658 bpath,mod = os.path.split(filename)
659 modname = os.path.splitext(mod)[0]
659 modname = os.path.splitext(mod)[0]
660 try:
660 try:
661 sys.path.append(bpath)
661 sys.path.append(bpath)
662 module = __import__(modname)
662 module = __import__(modname)
663 tests = list(self.loadTestsFromModule(module))
663 tests = list(self.loadTestsFromModule(module))
664 finally:
664 finally:
665 sys.path.pop()
665 sys.path.pop()
666 return tests
666 return tests
667
667
668 # NOTE: the method below is almost a copy of the original one in nose, with
668 # NOTE: the method below is almost a copy of the original one in nose, with
669 # a few modifications to control output checking.
669 # a few modifications to control output checking.
670
670
671 def loadTestsFromModule(self, module):
671 def loadTestsFromModule(self, module):
672 #print '*** ipdoctest - lTM',module # dbg
672 #print '*** ipdoctest - lTM',module # dbg
673
673
674 if not self.matches(module.__name__):
674 if not self.matches(module.__name__):
675 log.debug("Doctest doesn't want module %s", module)
675 log.debug("Doctest doesn't want module %s", module)
676 return
676 return
677
677
678 tests = self.finder.find(module,globs=self.globs,
678 tests = self.finder.find(module,globs=self.globs,
679 extraglobs=self.extraglobs)
679 extraglobs=self.extraglobs)
680 if not tests:
680 if not tests:
681 return
681 return
682
682
683 # always use whitespace and ellipsis options
683 # always use whitespace and ellipsis options
684 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
684 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
685
685
686 tests.sort()
686 tests.sort()
687 module_file = module.__file__
687 module_file = module.__file__
688 if module_file[-4:] in ('.pyc', '.pyo'):
688 if module_file[-4:] in ('.pyc', '.pyo'):
689 module_file = module_file[:-1]
689 module_file = module_file[:-1]
690 for test in tests:
690 for test in tests:
691 if not test.examples:
691 if not test.examples:
692 continue
692 continue
693 if not test.filename:
693 if not test.filename:
694 test.filename = module_file
694 test.filename = module_file
695
695
696 yield DocTestCase(test,
696 yield DocTestCase(test,
697 optionflags=optionflags,
697 optionflags=optionflags,
698 checker=self.checker)
698 checker=self.checker)
699
699
700
700
701 def loadTestsFromFile(self, filename):
701 def loadTestsFromFile(self, filename):
702 #print "ipdoctest - from file", filename # dbg
702 #print "ipdoctest - from file", filename # dbg
703 if is_extension_module(filename):
703 if is_extension_module(filename):
704 for t in self.loadTestsFromExtensionModule(filename):
704 for t in self.loadTestsFromExtensionModule(filename):
705 yield t
705 yield t
706 else:
706 else:
707 if self.extension and anyp(filename.endswith, self.extension):
707 if self.extension and anyp(filename.endswith, self.extension):
708 name = os.path.basename(filename)
708 name = os.path.basename(filename)
709 dh = open(filename)
709 dh = open(filename)
710 try:
710 try:
711 doc = dh.read()
711 doc = dh.read()
712 finally:
712 finally:
713 dh.close()
713 dh.close()
714 test = self.parser.get_doctest(
714 test = self.parser.get_doctest(
715 doc, globs={'__file__': filename}, name=name,
715 doc, globs={'__file__': filename}, name=name,
716 filename=filename, lineno=0)
716 filename=filename, lineno=0)
717 if test.examples:
717 if test.examples:
718 #print 'FileCase:',test.examples # dbg
718 #print 'FileCase:',test.examples # dbg
719 yield DocFileCase(test)
719 yield DocFileCase(test)
720 else:
720 else:
721 yield False # no tests to load
721 yield False # no tests to load
722
722
723 def wantFile(self,filename):
723 def wantFile(self,filename):
724 """Return whether the given filename should be scanned for tests.
724 """Return whether the given filename should be scanned for tests.
725
725
726 Modified version that accepts extension modules as valid containers for
726 Modified version that accepts extension modules as valid containers for
727 doctests.
727 doctests.
728 """
728 """
729 #print '*** ipdoctest- wantFile:',filename # dbg
729 #print '*** ipdoctest- wantFile:',filename # dbg
730
730
731 for pat in self.exclude_patterns:
731 for pat in self.exclude_patterns:
732 if pat.search(filename):
732 if pat.search(filename):
733 # print '###>>> SKIP:',filename # dbg
733 # print '###>>> SKIP:',filename # dbg
734 return False
734 return False
735
735
736 if is_extension_module(filename):
736 if is_extension_module(filename):
737 return True
737 return True
738 else:
738 else:
739 return doctests.Doctest.wantFile(self,filename)
739 return doctests.Doctest.wantFile(self,filename)
740
740
741 def wantDirectory(self, directory):
741 def wantDirectory(self, directory):
742 """Return whether the given directory should be scanned for tests.
742 """Return whether the given directory should be scanned for tests.
743
743
744 Modified version that supports exclusions.
744 Modified version that supports exclusions.
745 """
745 """
746
746
747 for pat in self.exclude_patterns:
747 for pat in self.exclude_patterns:
748 if pat.search(directory):
748 if pat.search(directory):
749 return False
749 return False
750 return True
750 return True
751
751
752
752
753 class IPythonDoctest(ExtensionDoctest):
753 class IPythonDoctest(ExtensionDoctest):
754 """Nose Plugin that supports doctests in extension modules.
754 """Nose Plugin that supports doctests in extension modules.
755 """
755 """
756 name = 'ipdoctest' # call nosetests with --with-ipdoctest
756 name = 'ipdoctest' # call nosetests with --with-ipdoctest
757 enabled = True
757 enabled = True
758
758
759 def makeTest(self, obj, parent):
759 def makeTest(self, obj, parent):
760 """Look for doctests in the given object, which will be a
760 """Look for doctests in the given object, which will be a
761 function, method or class.
761 function, method or class.
762 """
762 """
763 #print 'Plugin analyzing:', obj, parent # dbg
763 #print 'Plugin analyzing:', obj, parent # dbg
764 # always use whitespace and ellipsis options
764 # always use whitespace and ellipsis options
765 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
765 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
766
766
767 doctests = self.finder.find(obj, module=getmodule(parent))
767 doctests = self.finder.find(obj, module=getmodule(parent))
768 if doctests:
768 if doctests:
769 for test in doctests:
769 for test in doctests:
770 if len(test.examples) == 0:
770 if len(test.examples) == 0:
771 continue
771 continue
772
772
773 yield DocTestCase(test, obj=obj,
773 yield DocTestCase(test, obj=obj,
774 optionflags=optionflags,
774 optionflags=optionflags,
775 checker=self.checker)
775 checker=self.checker)
776
776
777 def options(self, parser, env=os.environ):
777 def options(self, parser, env=os.environ):
778 #print "Options for nose plugin:", self.name # dbg
778 #print "Options for nose plugin:", self.name # dbg
779 Plugin.options(self, parser, env)
779 Plugin.options(self, parser, env)
780 parser.add_option('--ipdoctest-tests', action='store_true',
780 parser.add_option('--ipdoctest-tests', action='store_true',
781 dest='ipdoctest_tests',
781 dest='ipdoctest_tests',
782 default=env.get('NOSE_IPDOCTEST_TESTS',True),
782 default=env.get('NOSE_IPDOCTEST_TESTS',True),
783 help="Also look for doctests in test modules. "
783 help="Also look for doctests in test modules. "
784 "Note that classes, methods and functions should "
784 "Note that classes, methods and functions should "
785 "have either doctests or non-doctest tests, "
785 "have either doctests or non-doctest tests, "
786 "not both. [NOSE_IPDOCTEST_TESTS]")
786 "not both. [NOSE_IPDOCTEST_TESTS]")
787 parser.add_option('--ipdoctest-extension', action="append",
787 parser.add_option('--ipdoctest-extension', action="append",
788 dest="ipdoctest_extension",
788 dest="ipdoctest_extension",
789 help="Also look for doctests in files with "
789 help="Also look for doctests in files with "
790 "this extension [NOSE_IPDOCTEST_EXTENSION]")
790 "this extension [NOSE_IPDOCTEST_EXTENSION]")
791 # Set the default as a list, if given in env; otherwise
791 # Set the default as a list, if given in env; otherwise
792 # an additional value set on the command line will cause
792 # an additional value set on the command line will cause
793 # an error.
793 # an error.
794 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
794 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
795 if env_setting is not None:
795 if env_setting is not None:
796 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
796 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
797
797
798 def configure(self, options, config):
798 def configure(self, options, config):
799 #print "Configuring nose plugin:", self.name # dbg
799 #print "Configuring nose plugin:", self.name # dbg
800 Plugin.configure(self, options, config)
800 Plugin.configure(self, options, config)
801 # Pull standard doctest plugin out of config; we will do doctesting
801 # Pull standard doctest plugin out of config; we will do doctesting
802 config.plugins.plugins = [p for p in config.plugins.plugins
802 config.plugins.plugins = [p for p in config.plugins.plugins
803 if p.name != 'doctest']
803 if p.name != 'doctest']
804 self.doctest_tests = options.ipdoctest_tests
804 self.doctest_tests = options.ipdoctest_tests
805 self.extension = tolist(options.ipdoctest_extension)
805 self.extension = tolist(options.ipdoctest_extension)
806
806
807 self.parser = IPDocTestParser()
807 self.parser = IPDocTestParser()
808 self.finder = DocTestFinder(parser=self.parser)
808 self.finder = DocTestFinder(parser=self.parser)
809 self.checker = IPDoctestOutputChecker()
809 self.checker = IPDoctestOutputChecker()
810 self.globs = None
810 self.globs = None
811 self.extraglobs = None
811 self.extraglobs = None
@@ -1,306 +1,306 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Class and program to colorize python source code for ANSI terminals.
3 Class and program to colorize python source code for ANSI terminals.
4
4
5 Based on an HTML code highlighter by Jurgen Hermann found at:
5 Based on an HTML code highlighter by Jurgen Hermann found at:
6 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298
6 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298
7
7
8 Modifications by Fernando Perez (fperez@colorado.edu).
8 Modifications by Fernando Perez (fperez@colorado.edu).
9
9
10 Information on the original HTML highlighter follows:
10 Information on the original HTML highlighter follows:
11
11
12 MoinMoin - Python Source Parser
12 MoinMoin - Python Source Parser
13
13
14 Title: Colorize Python source using the built-in tokenizer
14 Title: Colorize Python source using the built-in tokenizer
15
15
16 Submitter: Jurgen Hermann
16 Submitter: Jurgen Hermann
17 Last Updated:2001/04/06
17 Last Updated:2001/04/06
18
18
19 Version no:1.2
19 Version no:1.2
20
20
21 Description:
21 Description:
22
22
23 This code is part of MoinMoin (http://moin.sourceforge.net/) and converts
23 This code is part of MoinMoin (http://moin.sourceforge.net/) and converts
24 Python source code to HTML markup, rendering comments, keywords,
24 Python source code to HTML markup, rendering comments, keywords,
25 operators, numeric and string literals in different colors.
25 operators, numeric and string literals in different colors.
26
26
27 It shows how to use the built-in keyword, token and tokenize modules to
27 It shows how to use the built-in keyword, token and tokenize modules to
28 scan Python source code and re-emit it with no changes to its original
28 scan Python source code and re-emit it with no changes to its original
29 formatting (which is the hard part).
29 formatting (which is the hard part).
30 """
30 """
31
31
32 __all__ = ['ANSICodeColors','Parser']
32 __all__ = ['ANSICodeColors','Parser']
33
33
34 _scheme_default = 'Linux'
34 _scheme_default = 'Linux'
35
35
36 # Imports
36 # Imports
37 import StringIO
37 import StringIO
38 import keyword
38 import keyword
39 import os
39 import os
40 import optparse
40 import optparse
41 import sys
41 import sys
42 import token
42 import token
43 import tokenize
43 import tokenize
44
44
45 try:
45 try:
46 generate_tokens = tokenize.generate_tokens
46 generate_tokens = tokenize.generate_tokens
47 except AttributeError:
47 except AttributeError:
48 # Python 3. Note that we use the undocumented _tokenize because it expects
48 # Python 3. Note that we use the undocumented _tokenize because it expects
49 # strings, not bytes. See also Python issue #9969.
49 # strings, not bytes. See also Python issue #9969.
50 generate_tokens = tokenize._tokenize
50 generate_tokens = tokenize._tokenize
51
51
52 from IPython.utils.coloransi import *
52 from IPython.utils.coloransi import *
53
53
54 #############################################################################
54 #############################################################################
55 ### Python Source Parser (does Hilighting)
55 ### Python Source Parser (does Hilighting)
56 #############################################################################
56 #############################################################################
57
57
58 _KEYWORD = token.NT_OFFSET + 1
58 _KEYWORD = token.NT_OFFSET + 1
59 _TEXT = token.NT_OFFSET + 2
59 _TEXT = token.NT_OFFSET + 2
60
60
61 #****************************************************************************
61 #****************************************************************************
62 # Builtin color schemes
62 # Builtin color schemes
63
63
64 Colors = TermColors # just a shorthand
64 Colors = TermColors # just a shorthand
65
65
66 # Build a few color schemes
66 # Build a few color schemes
67 NoColor = ColorScheme(
67 NoColor = ColorScheme(
68 'NoColor',{
68 'NoColor',{
69 token.NUMBER : Colors.NoColor,
69 token.NUMBER : Colors.NoColor,
70 token.OP : Colors.NoColor,
70 token.OP : Colors.NoColor,
71 token.STRING : Colors.NoColor,
71 token.STRING : Colors.NoColor,
72 tokenize.COMMENT : Colors.NoColor,
72 tokenize.COMMENT : Colors.NoColor,
73 token.NAME : Colors.NoColor,
73 token.NAME : Colors.NoColor,
74 token.ERRORTOKEN : Colors.NoColor,
74 token.ERRORTOKEN : Colors.NoColor,
75
75
76 _KEYWORD : Colors.NoColor,
76 _KEYWORD : Colors.NoColor,
77 _TEXT : Colors.NoColor,
77 _TEXT : Colors.NoColor,
78
78
79 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
79 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
80 } )
80 } )
81
81
82 LinuxColors = ColorScheme(
82 LinuxColors = ColorScheme(
83 'Linux',{
83 'Linux',{
84 token.NUMBER : Colors.LightCyan,
84 token.NUMBER : Colors.LightCyan,
85 token.OP : Colors.Yellow,
85 token.OP : Colors.Yellow,
86 token.STRING : Colors.LightBlue,
86 token.STRING : Colors.LightBlue,
87 tokenize.COMMENT : Colors.LightRed,
87 tokenize.COMMENT : Colors.LightRed,
88 token.NAME : Colors.Normal,
88 token.NAME : Colors.Normal,
89 token.ERRORTOKEN : Colors.Red,
89 token.ERRORTOKEN : Colors.Red,
90
90
91 _KEYWORD : Colors.LightGreen,
91 _KEYWORD : Colors.LightGreen,
92 _TEXT : Colors.Yellow,
92 _TEXT : Colors.Yellow,
93
93
94 'normal' : Colors.Normal # color off (usu. Colors.Normal)
94 'normal' : Colors.Normal # color off (usu. Colors.Normal)
95 } )
95 } )
96
96
97 LightBGColors = ColorScheme(
97 LightBGColors = ColorScheme(
98 'LightBG',{
98 'LightBG',{
99 token.NUMBER : Colors.Cyan,
99 token.NUMBER : Colors.Cyan,
100 token.OP : Colors.Blue,
100 token.OP : Colors.Blue,
101 token.STRING : Colors.Blue,
101 token.STRING : Colors.Blue,
102 tokenize.COMMENT : Colors.Red,
102 tokenize.COMMENT : Colors.Red,
103 token.NAME : Colors.Normal,
103 token.NAME : Colors.Normal,
104 token.ERRORTOKEN : Colors.Red,
104 token.ERRORTOKEN : Colors.Red,
105
105
106 _KEYWORD : Colors.Green,
106 _KEYWORD : Colors.Green,
107 _TEXT : Colors.Blue,
107 _TEXT : Colors.Blue,
108
108
109 'normal' : Colors.Normal # color off (usu. Colors.Normal)
109 'normal' : Colors.Normal # color off (usu. Colors.Normal)
110 } )
110 } )
111
111
112 # Build table of color schemes (needed by the parser)
112 # Build table of color schemes (needed by the parser)
113 ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
113 ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
114 _scheme_default)
114 _scheme_default)
115
115
116 class Parser:
116 class Parser:
117 """ Format colored Python source.
117 """ Format colored Python source.
118 """
118 """
119
119
120 def __init__(self, color_table=None,out = sys.stdout):
120 def __init__(self, color_table=None,out = sys.stdout):
121 """ Create a parser with a specified color table and output channel.
121 """ Create a parser with a specified color table and output channel.
122
122
123 Call format() to process code.
123 Call format() to process code.
124 """
124 """
125 self.color_table = color_table and color_table or ANSICodeColors
125 self.color_table = color_table and color_table or ANSICodeColors
126 self.out = out
126 self.out = out
127
127
128 def format(self, raw, out = None, scheme = ''):
128 def format(self, raw, out = None, scheme = ''):
129 return self.format2(raw, out, scheme)[0]
129 return self.format2(raw, out, scheme)[0]
130
130
131 def format2(self, raw, out = None, scheme = ''):
131 def format2(self, raw, out = None, scheme = ''):
132 """ Parse and send the colored source.
132 """ Parse and send the colored source.
133
133
134 If out and scheme are not specified, the defaults (given to
134 If out and scheme are not specified, the defaults (given to
135 constructor) are used.
135 constructor) are used.
136
136
137 out should be a file-type object. Optionally, out can be given as the
137 out should be a file-type object. Optionally, out can be given as the
138 string 'str' and the parser will automatically return the output in a
138 string 'str' and the parser will automatically return the output in a
139 string."""
139 string."""
140
140
141 string_output = 0
141 string_output = 0
142 if out == 'str' or self.out == 'str' or \
142 if out == 'str' or self.out == 'str' or \
143 isinstance(self.out,StringIO.StringIO):
143 isinstance(self.out,StringIO.StringIO):
144 # XXX - I don't really like this state handling logic, but at this
144 # XXX - I don't really like this state handling logic, but at this
145 # point I don't want to make major changes, so adding the
145 # point I don't want to make major changes, so adding the
146 # isinstance() check is the simplest I can do to ensure correct
146 # isinstance() check is the simplest I can do to ensure correct
147 # behavior.
147 # behavior.
148 out_old = self.out
148 out_old = self.out
149 self.out = StringIO.StringIO()
149 self.out = StringIO.StringIO()
150 string_output = 1
150 string_output = 1
151 elif out is not None:
151 elif out is not None:
152 self.out = out
152 self.out = out
153
153
154 # Fast return of the unmodified input for NoColor scheme
154 # Fast return of the unmodified input for NoColor scheme
155 if scheme == 'NoColor':
155 if scheme == 'NoColor':
156 error = False
156 error = False
157 self.out.write(raw)
157 self.out.write(raw)
158 if string_output:
158 if string_output:
159 return raw,error
159 return raw,error
160 else:
160 else:
161 return None,error
161 return None,error
162
162
163 # local shorthands
163 # local shorthands
164 colors = self.color_table[scheme].colors
164 colors = self.color_table[scheme].colors
165 self.colors = colors # put in object so __call__ sees it
165 self.colors = colors # put in object so __call__ sees it
166
166
167 # Remove trailing whitespace and normalize tabs
167 # Remove trailing whitespace and normalize tabs
168 self.raw = raw.expandtabs().rstrip()
168 self.raw = raw.expandtabs().rstrip()
169
169
170 # store line offsets in self.lines
170 # store line offsets in self.lines
171 self.lines = [0, 0]
171 self.lines = [0, 0]
172 pos = 0
172 pos = 0
173 raw_find = self.raw.find
173 raw_find = self.raw.find
174 lines_append = self.lines.append
174 lines_append = self.lines.append
175 while 1:
175 while 1:
176 pos = raw_find('\n', pos) + 1
176 pos = raw_find('\n', pos) + 1
177 if not pos: break
177 if not pos: break
178 lines_append(pos)
178 lines_append(pos)
179 lines_append(len(self.raw))
179 lines_append(len(self.raw))
180
180
181 # parse the source and write it
181 # parse the source and write it
182 self.pos = 0
182 self.pos = 0
183 text = StringIO.StringIO(self.raw)
183 text = StringIO.StringIO(self.raw)
184
184
185 error = False
185 error = False
186 try:
186 try:
187 for atoken in generate_tokens(text.readline):
187 for atoken in generate_tokens(text.readline):
188 self(*atoken)
188 self(*atoken)
189 except tokenize.TokenError as ex:
189 except tokenize.TokenError as ex:
190 msg = ex.args[0]
190 msg = ex.args[0]
191 line = ex.args[1][0]
191 line = ex.args[1][0]
192 self.out.write("%s\n\n*** ERROR: %s%s%s\n" %
192 self.out.write("%s\n\n*** ERROR: %s%s%s\n" %
193 (colors[token.ERRORTOKEN],
193 (colors[token.ERRORTOKEN],
194 msg, self.raw[self.lines[line]:],
194 msg, self.raw[self.lines[line]:],
195 colors.normal)
195 colors.normal)
196 )
196 )
197 error = True
197 error = True
198 self.out.write(colors.normal+'\n')
198 self.out.write(colors.normal+'\n')
199 if string_output:
199 if string_output:
200 output = self.out.getvalue()
200 output = self.out.getvalue()
201 self.out = out_old
201 self.out = out_old
202 return (output, error)
202 return (output, error)
203 return (None, error)
203 return (None, error)
204
204
205 def __call__(self, toktype, toktext, (srow,scol), (erow,ecol), line):
205 def __call__(self, toktype, toktext, (srow,scol), (erow,ecol), line):
206 """ Token handler, with syntax highlighting."""
206 """ Token handler, with syntax highlighting."""
207
207
208 # local shorthands
208 # local shorthands
209 colors = self.colors
209 colors = self.colors
210 owrite = self.out.write
210 owrite = self.out.write
211
211
212 # line separator, so this works across platforms
212 # line separator, so this works across platforms
213 linesep = os.linesep
213 linesep = os.linesep
214
214
215 # calculate new positions
215 # calculate new positions
216 oldpos = self.pos
216 oldpos = self.pos
217 newpos = self.lines[srow] + scol
217 newpos = self.lines[srow] + scol
218 self.pos = newpos + len(toktext)
218 self.pos = newpos + len(toktext)
219
219
220 # send the original whitespace, if needed
220 # send the original whitespace, if needed
221 if newpos > oldpos:
221 if newpos > oldpos:
222 owrite(self.raw[oldpos:newpos])
222 owrite(self.raw[oldpos:newpos])
223
223
224 # skip indenting tokens
224 # skip indenting tokens
225 if toktype in [token.INDENT, token.DEDENT]:
225 if toktype in [token.INDENT, token.DEDENT]:
226 self.pos = newpos
226 self.pos = newpos
227 return
227 return
228
228
229 # map token type to a color group
229 # map token type to a color group
230 if token.LPAR <= toktype and toktype <= token.OP:
230 if token.LPAR <= toktype and toktype <= token.OP:
231 toktype = token.OP
231 toktype = token.OP
232 elif toktype == token.NAME and keyword.iskeyword(toktext):
232 elif toktype == token.NAME and keyword.iskeyword(toktext):
233 toktype = _KEYWORD
233 toktype = _KEYWORD
234 color = colors.get(toktype, colors[_TEXT])
234 color = colors.get(toktype, colors[_TEXT])
235
235
236 #print '<%s>' % toktext, # dbg
236 #print '<%s>' % toktext, # dbg
237
237
238 # Triple quoted strings must be handled carefully so that backtracking
238 # Triple quoted strings must be handled carefully so that backtracking
239 # in pagers works correctly. We need color terminators on _each_ line.
239 # in pagers works correctly. We need color terminators on _each_ line.
240 if linesep in toktext:
240 if linesep in toktext:
241 toktext = toktext.replace(linesep, '%s%s%s' %
241 toktext = toktext.replace(linesep, '%s%s%s' %
242 (colors.normal,linesep,color))
242 (colors.normal,linesep,color))
243
243
244 # send text
244 # send text
245 owrite('%s%s%s' % (color,toktext,colors.normal))
245 owrite('%s%s%s' % (color,toktext,colors.normal))
246
246
247 def main(argv=None):
247 def main(argv=None):
248 """Run as a command-line script: colorize a python file or stdin using ANSI
248 """Run as a command-line script: colorize a python file or stdin using ANSI
249 color escapes and print to stdout.
249 color escapes and print to stdout.
250
250
251 Inputs:
251 Inputs:
252
252
253 - argv(None): a list of strings like sys.argv[1:] giving the command-line
253 - argv(None): a list of strings like sys.argv[1:] giving the command-line
254 arguments. If None, use sys.argv[1:].
254 arguments. If None, use sys.argv[1:].
255 """
255 """
256
256
257 usage_msg = """%prog [options] [filename]
257 usage_msg = """%prog [options] [filename]
258
258
259 Colorize a python file or stdin using ANSI color escapes and print to stdout.
259 Colorize a python file or stdin using ANSI color escapes and print to stdout.
260 If no filename is given, or if filename is -, read standard input."""
260 If no filename is given, or if filename is -, read standard input."""
261
261
262 parser = optparse.OptionParser(usage=usage_msg)
262 parser = optparse.OptionParser(usage=usage_msg)
263 newopt = parser.add_option
263 newopt = parser.add_option
264 newopt('-s','--scheme',metavar='NAME',dest='scheme_name',action='store',
264 newopt('-s','--scheme',metavar='NAME',dest='scheme_name',action='store',
265 choices=['Linux','LightBG','NoColor'],default=_scheme_default,
265 choices=['Linux','LightBG','NoColor'],default=_scheme_default,
266 help="give the color scheme to use. Currently only 'Linux'\
266 help="give the color scheme to use. Currently only 'Linux'\
267 (default) and 'LightBG' and 'NoColor' are implemented (give without\
267 (default) and 'LightBG' and 'NoColor' are implemented (give without\
268 quotes)")
268 quotes)")
269
269
270 opts,args = parser.parse_args(argv)
270 opts,args = parser.parse_args(argv)
271
271
272 if len(args) > 1:
272 if len(args) > 1:
273 parser.error("you must give at most one filename.")
273 parser.error("you must give at most one filename.")
274
274
275 if len(args) == 0:
275 if len(args) == 0:
276 fname = '-' # no filename given; setup to read from stdin
276 fname = '-' # no filename given; setup to read from stdin
277 else:
277 else:
278 fname = args[0]
278 fname = args[0]
279
279
280 if fname == '-':
280 if fname == '-':
281 stream = sys.stdin
281 stream = sys.stdin
282 else:
282 else:
283 try:
283 try:
284 stream = open(fname)
284 stream = open(fname)
285 except IOError,msg:
285 except IOError as msg:
286 print >> sys.stderr, msg
286 print >> sys.stderr, msg
287 sys.exit(1)
287 sys.exit(1)
288
288
289 parser = Parser()
289 parser = Parser()
290
290
291 # we need nested try blocks because pre-2.5 python doesn't support unified
291 # we need nested try blocks because pre-2.5 python doesn't support unified
292 # try-except-finally
292 # try-except-finally
293 try:
293 try:
294 try:
294 try:
295 # write colorized version to stdout
295 # write colorized version to stdout
296 parser.format(stream.read(),scheme=opts.scheme_name)
296 parser.format(stream.read(),scheme=opts.scheme_name)
297 except IOError,msg:
297 except IOError as msg:
298 # if user reads through a pager and quits, don't print traceback
298 # if user reads through a pager and quits, don't print traceback
299 if msg.args != (32,'Broken pipe'):
299 if msg.args != (32,'Broken pipe'):
300 raise
300 raise
301 finally:
301 finally:
302 if stream is not sys.stdin:
302 if stream is not sys.stdin:
303 stream.close() # in case a non-handled exception happened above
303 stream.close() # in case a non-handled exception happened above
304
304
305 if __name__ == "__main__":
305 if __name__ == "__main__":
306 main()
306 main()
@@ -1,195 +1,195 b''
1 """Common utilities for the various process_* implementations.
1 """Common utilities for the various process_* implementations.
2
2
3 This file is only meant to be imported by the platform-specific implementations
3 This file is only meant to be imported by the platform-specific implementations
4 of subprocess utilities, and it contains tools that are common to all of them.
4 of subprocess utilities, and it contains tools that are common to all of them.
5 """
5 """
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 import subprocess
17 import subprocess
18 import shlex
18 import shlex
19 import sys
19 import sys
20
20
21 from IPython.utils import py3compat
21 from IPython.utils import py3compat
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Function definitions
24 # Function definitions
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 def read_no_interrupt(p):
27 def read_no_interrupt(p):
28 """Read from a pipe ignoring EINTR errors.
28 """Read from a pipe ignoring EINTR errors.
29
29
30 This is necessary because when reading from pipes with GUI event loops
30 This is necessary because when reading from pipes with GUI event loops
31 running in the background, often interrupts are raised that stop the
31 running in the background, often interrupts are raised that stop the
32 command from completing."""
32 command from completing."""
33 import errno
33 import errno
34
34
35 try:
35 try:
36 return p.read()
36 return p.read()
37 except IOError, err:
37 except IOError as err:
38 if err.errno != errno.EINTR:
38 if err.errno != errno.EINTR:
39 raise
39 raise
40
40
41
41
42 def process_handler(cmd, callback, stderr=subprocess.PIPE):
42 def process_handler(cmd, callback, stderr=subprocess.PIPE):
43 """Open a command in a shell subprocess and execute a callback.
43 """Open a command in a shell subprocess and execute a callback.
44
44
45 This function provides common scaffolding for creating subprocess.Popen()
45 This function provides common scaffolding for creating subprocess.Popen()
46 calls. It creates a Popen object and then calls the callback with it.
46 calls. It creates a Popen object and then calls the callback with it.
47
47
48 Parameters
48 Parameters
49 ----------
49 ----------
50 cmd : str
50 cmd : str
51 A string to be executed with the underlying system shell (by calling
51 A string to be executed with the underlying system shell (by calling
52 :func:`Popen` with ``shell=True``.
52 :func:`Popen` with ``shell=True``.
53
53
54 callback : callable
54 callback : callable
55 A one-argument function that will be called with the Popen object.
55 A one-argument function that will be called with the Popen object.
56
56
57 stderr : file descriptor number, optional
57 stderr : file descriptor number, optional
58 By default this is set to ``subprocess.PIPE``, but you can also pass the
58 By default this is set to ``subprocess.PIPE``, but you can also pass the
59 value ``subprocess.STDOUT`` to force the subprocess' stderr to go into
59 value ``subprocess.STDOUT`` to force the subprocess' stderr to go into
60 the same file descriptor as its stdout. This is useful to read stdout
60 the same file descriptor as its stdout. This is useful to read stdout
61 and stderr combined in the order they are generated.
61 and stderr combined in the order they are generated.
62
62
63 Returns
63 Returns
64 -------
64 -------
65 The return value of the provided callback is returned.
65 The return value of the provided callback is returned.
66 """
66 """
67 sys.stdout.flush()
67 sys.stdout.flush()
68 sys.stderr.flush()
68 sys.stderr.flush()
69 # On win32, close_fds can't be true when using pipes for stdin/out/err
69 # On win32, close_fds can't be true when using pipes for stdin/out/err
70 close_fds = sys.platform != 'win32'
70 close_fds = sys.platform != 'win32'
71 p = subprocess.Popen(cmd, shell=True,
71 p = subprocess.Popen(cmd, shell=True,
72 stdin=subprocess.PIPE,
72 stdin=subprocess.PIPE,
73 stdout=subprocess.PIPE,
73 stdout=subprocess.PIPE,
74 stderr=stderr,
74 stderr=stderr,
75 close_fds=close_fds)
75 close_fds=close_fds)
76
76
77 try:
77 try:
78 out = callback(p)
78 out = callback(p)
79 except KeyboardInterrupt:
79 except KeyboardInterrupt:
80 print('^C')
80 print('^C')
81 sys.stdout.flush()
81 sys.stdout.flush()
82 sys.stderr.flush()
82 sys.stderr.flush()
83 out = None
83 out = None
84 finally:
84 finally:
85 # Make really sure that we don't leave processes behind, in case the
85 # Make really sure that we don't leave processes behind, in case the
86 # call above raises an exception
86 # call above raises an exception
87 # We start by assuming the subprocess finished (to avoid NameErrors
87 # We start by assuming the subprocess finished (to avoid NameErrors
88 # later depending on the path taken)
88 # later depending on the path taken)
89 if p.returncode is None:
89 if p.returncode is None:
90 try:
90 try:
91 p.terminate()
91 p.terminate()
92 p.poll()
92 p.poll()
93 except OSError:
93 except OSError:
94 pass
94 pass
95 # One last try on our way out
95 # One last try on our way out
96 if p.returncode is None:
96 if p.returncode is None:
97 try:
97 try:
98 p.kill()
98 p.kill()
99 except OSError:
99 except OSError:
100 pass
100 pass
101
101
102 return out
102 return out
103
103
104
104
105 def getoutput(cmd):
105 def getoutput(cmd):
106 """Return standard output of executing cmd in a shell.
106 """Return standard output of executing cmd in a shell.
107
107
108 Accepts the same arguments as os.system().
108 Accepts the same arguments as os.system().
109
109
110 Parameters
110 Parameters
111 ----------
111 ----------
112 cmd : str
112 cmd : str
113 A command to be executed in the system shell.
113 A command to be executed in the system shell.
114
114
115 Returns
115 Returns
116 -------
116 -------
117 stdout : str
117 stdout : str
118 """
118 """
119
119
120 out = process_handler(cmd, lambda p: p.communicate()[0], subprocess.STDOUT)
120 out = process_handler(cmd, lambda p: p.communicate()[0], subprocess.STDOUT)
121 if out is None:
121 if out is None:
122 return ''
122 return ''
123 return py3compat.bytes_to_str(out)
123 return py3compat.bytes_to_str(out)
124
124
125
125
126 def getoutputerror(cmd):
126 def getoutputerror(cmd):
127 """Return (standard output, standard error) of executing cmd in a shell.
127 """Return (standard output, standard error) of executing cmd in a shell.
128
128
129 Accepts the same arguments as os.system().
129 Accepts the same arguments as os.system().
130
130
131 Parameters
131 Parameters
132 ----------
132 ----------
133 cmd : str
133 cmd : str
134 A command to be executed in the system shell.
134 A command to be executed in the system shell.
135
135
136 Returns
136 Returns
137 -------
137 -------
138 stdout : str
138 stdout : str
139 stderr : str
139 stderr : str
140 """
140 """
141
141
142 out_err = process_handler(cmd, lambda p: p.communicate())
142 out_err = process_handler(cmd, lambda p: p.communicate())
143 if out_err is None:
143 if out_err is None:
144 return '', ''
144 return '', ''
145 out, err = out_err
145 out, err = out_err
146 return py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
146 return py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
147
147
148
148
149 def arg_split(s, posix=False, strict=True):
149 def arg_split(s, posix=False, strict=True):
150 """Split a command line's arguments in a shell-like manner.
150 """Split a command line's arguments in a shell-like manner.
151
151
152 This is a modified version of the standard library's shlex.split()
152 This is a modified version of the standard library's shlex.split()
153 function, but with a default of posix=False for splitting, so that quotes
153 function, but with a default of posix=False for splitting, so that quotes
154 in inputs are respected.
154 in inputs are respected.
155
155
156 if strict=False, then any errors shlex.split would raise will result in the
156 if strict=False, then any errors shlex.split would raise will result in the
157 unparsed remainder being the last element of the list, rather than raising.
157 unparsed remainder being the last element of the list, rather than raising.
158 This is because we sometimes use arg_split to parse things other than
158 This is because we sometimes use arg_split to parse things other than
159 command-line args.
159 command-line args.
160 """
160 """
161
161
162 # Unfortunately, python's shlex module is buggy with unicode input:
162 # Unfortunately, python's shlex module is buggy with unicode input:
163 # http://bugs.python.org/issue1170
163 # http://bugs.python.org/issue1170
164 # At least encoding the input when it's unicode seems to help, but there
164 # At least encoding the input when it's unicode seems to help, but there
165 # may be more problems lurking. Apparently this is fixed in python3.
165 # may be more problems lurking. Apparently this is fixed in python3.
166 is_unicode = False
166 is_unicode = False
167 if (not py3compat.PY3) and isinstance(s, unicode):
167 if (not py3compat.PY3) and isinstance(s, unicode):
168 is_unicode = True
168 is_unicode = True
169 s = s.encode('utf-8')
169 s = s.encode('utf-8')
170 lex = shlex.shlex(s, posix=posix)
170 lex = shlex.shlex(s, posix=posix)
171 lex.whitespace_split = True
171 lex.whitespace_split = True
172 # Extract tokens, ensuring that things like leaving open quotes
172 # Extract tokens, ensuring that things like leaving open quotes
173 # does not cause this to raise. This is important, because we
173 # does not cause this to raise. This is important, because we
174 # sometimes pass Python source through this (e.g. %timeit f(" ")),
174 # sometimes pass Python source through this (e.g. %timeit f(" ")),
175 # and it shouldn't raise an exception.
175 # and it shouldn't raise an exception.
176 # It may be a bad idea to parse things that are not command-line args
176 # It may be a bad idea to parse things that are not command-line args
177 # through this function, but we do, so let's be safe about it.
177 # through this function, but we do, so let's be safe about it.
178 lex.commenters='' #fix for GH-1269
178 lex.commenters='' #fix for GH-1269
179 tokens = []
179 tokens = []
180 while True:
180 while True:
181 try:
181 try:
182 tokens.append(lex.next())
182 tokens.append(lex.next())
183 except StopIteration:
183 except StopIteration:
184 break
184 break
185 except ValueError:
185 except ValueError:
186 if strict:
186 if strict:
187 raise
187 raise
188 # couldn't parse, get remaining blob as last token
188 # couldn't parse, get remaining blob as last token
189 tokens.append(lex.token)
189 tokens.append(lex.token)
190 break
190 break
191
191
192 if is_unicode:
192 if is_unicode:
193 # Convert the tokens back to unicode.
193 # Convert the tokens back to unicode.
194 tokens = [x.decode('utf-8') for x in tokens]
194 tokens = [x.decode('utf-8') for x in tokens]
195 return tokens
195 return tokens
@@ -1,26 +1,26 b''
1 """daemonize function from twisted.scripts._twistd_unix."""
1 """daemonize function from twisted.scripts._twistd_unix."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) Twisted Matrix Laboratories.
4 # Copyright (c) Twisted Matrix Laboratories.
5 # See Twisted's LICENSE for details.
5 # See Twisted's LICENSE for details.
6 # http://twistedmatrix.com/
6 # http://twistedmatrix.com/
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8
8
9 import os, errno
9 import os, errno
10
10
11 def daemonize():
11 def daemonize():
12 # See http://www.erlenstar.demon.co.uk/unix/faq_toc.html#TOC16
12 # See http://www.erlenstar.demon.co.uk/unix/faq_toc.html#TOC16
13 if os.fork(): # launch child and...
13 if os.fork(): # launch child and...
14 os._exit(0) # kill off parent
14 os._exit(0) # kill off parent
15 os.setsid()
15 os.setsid()
16 if os.fork(): # launch child and...
16 if os.fork(): # launch child and...
17 os._exit(0) # kill off parent again.
17 os._exit(0) # kill off parent again.
18 null = os.open('/dev/null', os.O_RDWR)
18 null = os.open('/dev/null', os.O_RDWR)
19 for i in range(3):
19 for i in range(3):
20 try:
20 try:
21 os.dup2(null, i)
21 os.dup2(null, i)
22 except OSError, e:
22 except OSError as e:
23 if e.errno != errno.EBADF:
23 if e.errno != errno.EBADF:
24 raise
24 raise
25 os.close(null)
25 os.close(null)
26
26
@@ -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 not self.has_key(key):
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, 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 self.has_key(k):
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 self.has_key(key)
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,364 +1,364 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2
2
3 """ PickleShare - a small 'shelve' like datastore with concurrency support
3 """ PickleShare - a small 'shelve' like datastore with concurrency support
4
4
5 Like shelve, a PickleShareDB object acts like a normal dictionary. Unlike
5 Like shelve, a PickleShareDB object acts like a normal dictionary. Unlike
6 shelve, many processes can access the database simultaneously. Changing a
6 shelve, many processes can access the database simultaneously. Changing a
7 value in database is immediately visible to other processes accessing the
7 value in database is immediately visible to other processes accessing the
8 same database.
8 same database.
9
9
10 Concurrency is possible because the values are stored in separate files. Hence
10 Concurrency is possible because the values are stored in separate files. Hence
11 the "database" is a directory where *all* files are governed by PickleShare.
11 the "database" is a directory where *all* files are governed by PickleShare.
12
12
13 Example usage::
13 Example usage::
14
14
15 from pickleshare import *
15 from pickleshare import *
16 db = PickleShareDB('~/testpickleshare')
16 db = PickleShareDB('~/testpickleshare')
17 db.clear()
17 db.clear()
18 print "Should be empty:",db.items()
18 print "Should be empty:",db.items()
19 db['hello'] = 15
19 db['hello'] = 15
20 db['aku ankka'] = [1,2,313]
20 db['aku ankka'] = [1,2,313]
21 db['paths/are/ok/key'] = [1,(5,46)]
21 db['paths/are/ok/key'] = [1,(5,46)]
22 print db.keys()
22 print db.keys()
23 del db['aku ankka']
23 del db['aku ankka']
24
24
25 This module is certainly not ZODB, but can be used for low-load
25 This module is certainly not ZODB, but can be used for low-load
26 (non-mission-critical) situations where tiny code size trumps the
26 (non-mission-critical) situations where tiny code size trumps the
27 advanced features of a "real" object database.
27 advanced features of a "real" object database.
28
28
29 Installation guide: easy_install pickleshare
29 Installation guide: easy_install pickleshare
30
30
31 Author: Ville Vainio <vivainio@gmail.com>
31 Author: Ville Vainio <vivainio@gmail.com>
32 License: MIT open source license.
32 License: MIT open source license.
33
33
34 """
34 """
35
35
36 from IPython.external.path import path as Path
36 from IPython.external.path import path as Path
37 import os,stat,time
37 import os,stat,time
38 import collections
38 import collections
39 import cPickle as pickle
39 import cPickle as pickle
40 import glob
40 import glob
41
41
42 def gethashfile(key):
42 def gethashfile(key):
43 return ("%02x" % abs(hash(key) % 256))[-2:]
43 return ("%02x" % abs(hash(key) % 256))[-2:]
44
44
45 _sentinel = object()
45 _sentinel = object()
46
46
47 class PickleShareDB(collections.MutableMapping):
47 class PickleShareDB(collections.MutableMapping):
48 """ The main 'connection' object for PickleShare database """
48 """ The main 'connection' object for PickleShare database """
49 def __init__(self,root):
49 def __init__(self,root):
50 """ Return a db object that will manage the specied directory"""
50 """ Return a db object that will manage the specied directory"""
51 self.root = Path(root).expanduser().abspath()
51 self.root = Path(root).expanduser().abspath()
52 if not self.root.isdir():
52 if not self.root.isdir():
53 self.root.makedirs()
53 self.root.makedirs()
54 # cache has { 'key' : (obj, orig_mod_time) }
54 # cache has { 'key' : (obj, orig_mod_time) }
55 self.cache = {}
55 self.cache = {}
56
56
57
57
58 def __getitem__(self,key):
58 def __getitem__(self,key):
59 """ db['key'] reading """
59 """ db['key'] reading """
60 fil = self.root / key
60 fil = self.root / key
61 try:
61 try:
62 mtime = (fil.stat()[stat.ST_MTIME])
62 mtime = (fil.stat()[stat.ST_MTIME])
63 except OSError:
63 except OSError:
64 raise KeyError(key)
64 raise KeyError(key)
65
65
66 if fil in self.cache and mtime == self.cache[fil][1]:
66 if fil in self.cache and mtime == self.cache[fil][1]:
67 return self.cache[fil][0]
67 return self.cache[fil][0]
68 try:
68 try:
69 # The cached item has expired, need to read
69 # The cached item has expired, need to read
70 obj = pickle.loads(fil.open("rb").read())
70 obj = pickle.loads(fil.open("rb").read())
71 except:
71 except:
72 raise KeyError(key)
72 raise KeyError(key)
73
73
74 self.cache[fil] = (obj,mtime)
74 self.cache[fil] = (obj,mtime)
75 return obj
75 return obj
76
76
77 def __setitem__(self,key,value):
77 def __setitem__(self,key,value):
78 """ db['key'] = 5 """
78 """ db['key'] = 5 """
79 fil = self.root / key
79 fil = self.root / key
80 parent = fil.parent
80 parent = fil.parent
81 if parent and not parent.isdir():
81 if parent and not parent.isdir():
82 parent.makedirs()
82 parent.makedirs()
83 # We specify protocol 2, so that we can mostly go between Python 2
83 # We specify protocol 2, so that we can mostly go between Python 2
84 # and Python 3. We can upgrade to protocol 3 when Python 2 is obsolete.
84 # and Python 3. We can upgrade to protocol 3 when Python 2 is obsolete.
85 pickled = pickle.dump(value,fil.open('wb'), protocol=2)
85 pickled = pickle.dump(value,fil.open('wb'), protocol=2)
86 try:
86 try:
87 self.cache[fil] = (value,fil.mtime)
87 self.cache[fil] = (value,fil.mtime)
88 except OSError,e:
88 except OSError as e:
89 if e.errno != 2:
89 if e.errno != 2:
90 raise
90 raise
91
91
92 def hset(self, hashroot, key, value):
92 def hset(self, hashroot, key, value):
93 """ hashed set """
93 """ hashed set """
94 hroot = self.root / hashroot
94 hroot = self.root / hashroot
95 if not hroot.isdir():
95 if not hroot.isdir():
96 hroot.makedirs()
96 hroot.makedirs()
97 hfile = hroot / gethashfile(key)
97 hfile = hroot / gethashfile(key)
98 d = self.get(hfile, {})
98 d = self.get(hfile, {})
99 d.update( {key : value})
99 d.update( {key : value})
100 self[hfile] = d
100 self[hfile] = d
101
101
102
102
103
103
104 def hget(self, hashroot, key, default = _sentinel, fast_only = True):
104 def hget(self, hashroot, key, default = _sentinel, fast_only = True):
105 """ hashed get """
105 """ hashed get """
106 hroot = self.root / hashroot
106 hroot = self.root / hashroot
107 hfile = hroot / gethashfile(key)
107 hfile = hroot / gethashfile(key)
108
108
109 d = self.get(hfile, _sentinel )
109 d = self.get(hfile, _sentinel )
110 #print "got dict",d,"from",hfile
110 #print "got dict",d,"from",hfile
111 if d is _sentinel:
111 if d is _sentinel:
112 if fast_only:
112 if fast_only:
113 if default is _sentinel:
113 if default is _sentinel:
114 raise KeyError(key)
114 raise KeyError(key)
115
115
116 return default
116 return default
117
117
118 # slow mode ok, works even after hcompress()
118 # slow mode ok, works even after hcompress()
119 d = self.hdict(hashroot)
119 d = self.hdict(hashroot)
120
120
121 return d.get(key, default)
121 return d.get(key, default)
122
122
123 def hdict(self, hashroot):
123 def hdict(self, hashroot):
124 """ Get all data contained in hashed category 'hashroot' as dict """
124 """ Get all data contained in hashed category 'hashroot' as dict """
125 hfiles = self.keys(hashroot + "/*")
125 hfiles = self.keys(hashroot + "/*")
126 hfiles.sort()
126 hfiles.sort()
127 last = len(hfiles) and hfiles[-1] or ''
127 last = len(hfiles) and hfiles[-1] or ''
128 if last.endswith('xx'):
128 if last.endswith('xx'):
129 # print "using xx"
129 # print "using xx"
130 hfiles = [last] + hfiles[:-1]
130 hfiles = [last] + hfiles[:-1]
131
131
132 all = {}
132 all = {}
133
133
134 for f in hfiles:
134 for f in hfiles:
135 # print "using",f
135 # print "using",f
136 try:
136 try:
137 all.update(self[f])
137 all.update(self[f])
138 except KeyError:
138 except KeyError:
139 print "Corrupt",f,"deleted - hset is not threadsafe!"
139 print "Corrupt",f,"deleted - hset is not threadsafe!"
140 del self[f]
140 del self[f]
141
141
142 self.uncache(f)
142 self.uncache(f)
143
143
144 return all
144 return all
145
145
146 def hcompress(self, hashroot):
146 def hcompress(self, hashroot):
147 """ Compress category 'hashroot', so hset is fast again
147 """ Compress category 'hashroot', so hset is fast again
148
148
149 hget will fail if fast_only is True for compressed items (that were
149 hget will fail if fast_only is True for compressed items (that were
150 hset before hcompress).
150 hset before hcompress).
151
151
152 """
152 """
153 hfiles = self.keys(hashroot + "/*")
153 hfiles = self.keys(hashroot + "/*")
154 all = {}
154 all = {}
155 for f in hfiles:
155 for f in hfiles:
156 # print "using",f
156 # print "using",f
157 all.update(self[f])
157 all.update(self[f])
158 self.uncache(f)
158 self.uncache(f)
159
159
160 self[hashroot + '/xx'] = all
160 self[hashroot + '/xx'] = all
161 for f in hfiles:
161 for f in hfiles:
162 p = self.root / f
162 p = self.root / f
163 if p.basename() == 'xx':
163 if p.basename() == 'xx':
164 continue
164 continue
165 p.remove()
165 p.remove()
166
166
167
167
168
168
169 def __delitem__(self,key):
169 def __delitem__(self,key):
170 """ del db["key"] """
170 """ del db["key"] """
171 fil = self.root / key
171 fil = self.root / key
172 self.cache.pop(fil,None)
172 self.cache.pop(fil,None)
173 try:
173 try:
174 fil.remove()
174 fil.remove()
175 except OSError:
175 except OSError:
176 # notfound and permission denied are ok - we
176 # notfound and permission denied are ok - we
177 # lost, the other process wins the conflict
177 # lost, the other process wins the conflict
178 pass
178 pass
179
179
180 def _normalized(self, p):
180 def _normalized(self, p):
181 """ Make a key suitable for user's eyes """
181 """ Make a key suitable for user's eyes """
182 return str(self.root.relpathto(p)).replace('\\','/')
182 return str(self.root.relpathto(p)).replace('\\','/')
183
183
184 def keys(self, globpat = None):
184 def keys(self, globpat = None):
185 """ All keys in DB, or all keys matching a glob"""
185 """ All keys in DB, or all keys matching a glob"""
186
186
187 if globpat is None:
187 if globpat is None:
188 files = self.root.walkfiles()
188 files = self.root.walkfiles()
189 else:
189 else:
190 files = [Path(p) for p in glob.glob(self.root/globpat)]
190 files = [Path(p) for p in glob.glob(self.root/globpat)]
191 return [self._normalized(p) for p in files if p.isfile()]
191 return [self._normalized(p) for p in files if p.isfile()]
192
192
193 def __iter__(self):
193 def __iter__(self):
194 return iter(self.keys())
194 return iter(self.keys())
195
195
196 def __len__(self):
196 def __len__(self):
197 return len(self.keys())
197 return len(self.keys())
198
198
199 def uncache(self,*items):
199 def uncache(self,*items):
200 """ Removes all, or specified items from cache
200 """ Removes all, or specified items from cache
201
201
202 Use this after reading a large amount of large objects
202 Use this after reading a large amount of large objects
203 to free up memory, when you won't be needing the objects
203 to free up memory, when you won't be needing the objects
204 for a while.
204 for a while.
205
205
206 """
206 """
207 if not items:
207 if not items:
208 self.cache = {}
208 self.cache = {}
209 for it in items:
209 for it in items:
210 self.cache.pop(it,None)
210 self.cache.pop(it,None)
211
211
212 def waitget(self,key, maxwaittime = 60 ):
212 def waitget(self,key, maxwaittime = 60 ):
213 """ Wait (poll) for a key to get a value
213 """ Wait (poll) for a key to get a value
214
214
215 Will wait for `maxwaittime` seconds before raising a KeyError.
215 Will wait for `maxwaittime` seconds before raising a KeyError.
216 The call exits normally if the `key` field in db gets a value
216 The call exits normally if the `key` field in db gets a value
217 within the timeout period.
217 within the timeout period.
218
218
219 Use this for synchronizing different processes or for ensuring
219 Use this for synchronizing different processes or for ensuring
220 that an unfortunately timed "db['key'] = newvalue" operation
220 that an unfortunately timed "db['key'] = newvalue" operation
221 in another process (which causes all 'get' operation to cause a
221 in another process (which causes all 'get' operation to cause a
222 KeyError for the duration of pickling) won't screw up your program
222 KeyError for the duration of pickling) won't screw up your program
223 logic.
223 logic.
224 """
224 """
225
225
226 wtimes = [0.2] * 3 + [0.5] * 2 + [1]
226 wtimes = [0.2] * 3 + [0.5] * 2 + [1]
227 tries = 0
227 tries = 0
228 waited = 0
228 waited = 0
229 while 1:
229 while 1:
230 try:
230 try:
231 val = self[key]
231 val = self[key]
232 return val
232 return val
233 except KeyError:
233 except KeyError:
234 pass
234 pass
235
235
236 if waited > maxwaittime:
236 if waited > maxwaittime:
237 raise KeyError(key)
237 raise KeyError(key)
238
238
239 time.sleep(wtimes[tries])
239 time.sleep(wtimes[tries])
240 waited+=wtimes[tries]
240 waited+=wtimes[tries]
241 if tries < len(wtimes) -1:
241 if tries < len(wtimes) -1:
242 tries+=1
242 tries+=1
243
243
244 def getlink(self,folder):
244 def getlink(self,folder):
245 """ Get a convenient link for accessing items """
245 """ Get a convenient link for accessing items """
246 return PickleShareLink(self, folder)
246 return PickleShareLink(self, folder)
247
247
248 def __repr__(self):
248 def __repr__(self):
249 return "PickleShareDB('%s')" % self.root
249 return "PickleShareDB('%s')" % self.root
250
250
251
251
252
252
253 class PickleShareLink:
253 class PickleShareLink:
254 """ A shortdand for accessing nested PickleShare data conveniently.
254 """ A shortdand for accessing nested PickleShare data conveniently.
255
255
256 Created through PickleShareDB.getlink(), example::
256 Created through PickleShareDB.getlink(), example::
257
257
258 lnk = db.getlink('myobjects/test')
258 lnk = db.getlink('myobjects/test')
259 lnk.foo = 2
259 lnk.foo = 2
260 lnk.bar = lnk.foo + 5
260 lnk.bar = lnk.foo + 5
261
261
262 """
262 """
263 def __init__(self, db, keydir ):
263 def __init__(self, db, keydir ):
264 self.__dict__.update(locals())
264 self.__dict__.update(locals())
265
265
266 def __getattr__(self,key):
266 def __getattr__(self,key):
267 return self.__dict__['db'][self.__dict__['keydir']+'/' + key]
267 return self.__dict__['db'][self.__dict__['keydir']+'/' + key]
268 def __setattr__(self,key,val):
268 def __setattr__(self,key,val):
269 self.db[self.keydir+'/' + key] = val
269 self.db[self.keydir+'/' + key] = val
270 def __repr__(self):
270 def __repr__(self):
271 db = self.__dict__['db']
271 db = self.__dict__['db']
272 keys = db.keys( self.__dict__['keydir'] +"/*")
272 keys = db.keys( self.__dict__['keydir'] +"/*")
273 return "<PickleShareLink '%s': %s>" % (
273 return "<PickleShareLink '%s': %s>" % (
274 self.__dict__['keydir'],
274 self.__dict__['keydir'],
275 ";".join([Path(k).basename() for k in keys]))
275 ";".join([Path(k).basename() for k in keys]))
276
276
277
277
278 def test():
278 def test():
279 db = PickleShareDB('~/testpickleshare')
279 db = PickleShareDB('~/testpickleshare')
280 db.clear()
280 db.clear()
281 print "Should be empty:",db.items()
281 print "Should be empty:",db.items()
282 db['hello'] = 15
282 db['hello'] = 15
283 db['aku ankka'] = [1,2,313]
283 db['aku ankka'] = [1,2,313]
284 db['paths/nest/ok/keyname'] = [1,(5,46)]
284 db['paths/nest/ok/keyname'] = [1,(5,46)]
285 db.hset('hash', 'aku', 12)
285 db.hset('hash', 'aku', 12)
286 db.hset('hash', 'ankka', 313)
286 db.hset('hash', 'ankka', 313)
287 print "12 =",db.hget('hash','aku')
287 print "12 =",db.hget('hash','aku')
288 print "313 =",db.hget('hash','ankka')
288 print "313 =",db.hget('hash','ankka')
289 print "all hashed",db.hdict('hash')
289 print "all hashed",db.hdict('hash')
290 print db.keys()
290 print db.keys()
291 print db.keys('paths/nest/ok/k*')
291 print db.keys('paths/nest/ok/k*')
292 print dict(db) # snapsot of whole db
292 print dict(db) # snapsot of whole db
293 db.uncache() # frees memory, causes re-reads later
293 db.uncache() # frees memory, causes re-reads later
294
294
295 # shorthand for accessing deeply nested files
295 # shorthand for accessing deeply nested files
296 lnk = db.getlink('myobjects/test')
296 lnk = db.getlink('myobjects/test')
297 lnk.foo = 2
297 lnk.foo = 2
298 lnk.bar = lnk.foo + 5
298 lnk.bar = lnk.foo + 5
299 print lnk.bar # 7
299 print lnk.bar # 7
300
300
301 def stress():
301 def stress():
302 db = PickleShareDB('~/fsdbtest')
302 db = PickleShareDB('~/fsdbtest')
303 import time,sys
303 import time,sys
304 for i in range(1000):
304 for i in range(1000):
305 for j in range(1000):
305 for j in range(1000):
306 if i % 15 == 0 and i < 200:
306 if i % 15 == 0 and i < 200:
307 if str(j) in db:
307 if str(j) in db:
308 del db[str(j)]
308 del db[str(j)]
309 continue
309 continue
310
310
311 if j%33 == 0:
311 if j%33 == 0:
312 time.sleep(0.02)
312 time.sleep(0.02)
313
313
314 db[str(j)] = db.get(str(j), []) + [(i,j,"proc %d" % os.getpid())]
314 db[str(j)] = db.get(str(j), []) + [(i,j,"proc %d" % os.getpid())]
315 db.hset('hash',j, db.hget('hash',j,15) + 1 )
315 db.hset('hash',j, db.hget('hash',j,15) + 1 )
316
316
317 print i,
317 print i,
318 sys.stdout.flush()
318 sys.stdout.flush()
319 if i % 10 == 0:
319 if i % 10 == 0:
320 db.uncache()
320 db.uncache()
321
321
322 def main():
322 def main():
323 import textwrap
323 import textwrap
324 usage = textwrap.dedent("""\
324 usage = textwrap.dedent("""\
325 pickleshare - manage PickleShare databases
325 pickleshare - manage PickleShare databases
326
326
327 Usage:
327 Usage:
328
328
329 pickleshare dump /path/to/db > dump.txt
329 pickleshare dump /path/to/db > dump.txt
330 pickleshare load /path/to/db < dump.txt
330 pickleshare load /path/to/db < dump.txt
331 pickleshare test /path/to/db
331 pickleshare test /path/to/db
332 """)
332 """)
333 DB = PickleShareDB
333 DB = PickleShareDB
334 import sys
334 import sys
335 if len(sys.argv) < 2:
335 if len(sys.argv) < 2:
336 print usage
336 print usage
337 return
337 return
338
338
339 cmd = sys.argv[1]
339 cmd = sys.argv[1]
340 args = sys.argv[2:]
340 args = sys.argv[2:]
341 if cmd == 'dump':
341 if cmd == 'dump':
342 if not args: args= ['.']
342 if not args: args= ['.']
343 db = DB(args[0])
343 db = DB(args[0])
344 import pprint
344 import pprint
345 pprint.pprint(db.items())
345 pprint.pprint(db.items())
346 elif cmd == 'load':
346 elif cmd == 'load':
347 cont = sys.stdin.read()
347 cont = sys.stdin.read()
348 db = DB(args[0])
348 db = DB(args[0])
349 data = eval(cont)
349 data = eval(cont)
350 db.clear()
350 db.clear()
351 for k,v in db.items():
351 for k,v in db.items():
352 db[k] = v
352 db[k] = v
353 elif cmd == 'testwait':
353 elif cmd == 'testwait':
354 db = DB(args[0])
354 db = DB(args[0])
355 db.clear()
355 db.clear()
356 print db.waitget('250')
356 print db.waitget('250')
357 elif cmd == 'test':
357 elif cmd == 'test':
358 test()
358 test()
359 stress()
359 stress()
360
360
361 if __name__== "__main__":
361 if __name__== "__main__":
362 main()
362 main()
363
363
364
364
@@ -1,994 +1,994 b''
1 """Base classes to manage the interaction with a running kernel.
1 """Base classes to manage the interaction with a running kernel.
2
2
3 TODO
3 TODO
4 * Create logger to handle debugging and console messages.
4 * Create logger to handle debugging and console messages.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2011 The IPython Development Team
8 # Copyright (C) 2008-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 atexit
19 import atexit
20 import errno
20 import errno
21 import json
21 import json
22 from subprocess import Popen
22 from subprocess import Popen
23 import os
23 import os
24 import signal
24 import signal
25 import sys
25 import sys
26 from threading import Thread
26 from threading import Thread
27 import time
27 import time
28
28
29 # System library imports.
29 # System library imports.
30 import zmq
30 import zmq
31 # import ZMQError in top-level namespace, to avoid ugly attribute-error messages
31 # import ZMQError in top-level namespace, to avoid ugly attribute-error messages
32 # during garbage collection of threads at exit:
32 # during garbage collection of threads at exit:
33 from zmq import ZMQError
33 from zmq import ZMQError
34 from zmq.eventloop import ioloop, zmqstream
34 from zmq.eventloop import ioloop, zmqstream
35
35
36 # Local imports.
36 # Local imports.
37 from IPython.config.loader import Config
37 from IPython.config.loader import Config
38 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
38 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
39 from IPython.utils.traitlets import (
39 from IPython.utils.traitlets import (
40 HasTraits, Any, Instance, Type, Unicode, Integer, Bool
40 HasTraits, Any, Instance, Type, Unicode, Integer, Bool
41 )
41 )
42 from IPython.utils.py3compat import str_to_bytes
42 from IPython.utils.py3compat import str_to_bytes
43 from IPython.zmq.entry_point import write_connection_file
43 from IPython.zmq.entry_point import write_connection_file
44 from session import Session
44 from session import Session
45
45
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47 # Constants and exceptions
47 # Constants and exceptions
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49
49
50 class InvalidPortNumber(Exception):
50 class InvalidPortNumber(Exception):
51 pass
51 pass
52
52
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54 # Utility functions
54 # Utility functions
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56
56
57 # some utilities to validate message structure, these might get moved elsewhere
57 # some utilities to validate message structure, these might get moved elsewhere
58 # if they prove to have more generic utility
58 # if they prove to have more generic utility
59
59
60 def validate_string_list(lst):
60 def validate_string_list(lst):
61 """Validate that the input is a list of strings.
61 """Validate that the input is a list of strings.
62
62
63 Raises ValueError if not."""
63 Raises ValueError if not."""
64 if not isinstance(lst, list):
64 if not isinstance(lst, list):
65 raise ValueError('input %r must be a list' % lst)
65 raise ValueError('input %r must be a list' % lst)
66 for x in lst:
66 for x in lst:
67 if not isinstance(x, basestring):
67 if not isinstance(x, basestring):
68 raise ValueError('element %r in list must be a string' % x)
68 raise ValueError('element %r in list must be a string' % x)
69
69
70
70
71 def validate_string_dict(dct):
71 def validate_string_dict(dct):
72 """Validate that the input is a dict with string keys and values.
72 """Validate that the input is a dict with string keys and values.
73
73
74 Raises ValueError if not."""
74 Raises ValueError if not."""
75 for k,v in dct.iteritems():
75 for k,v in dct.iteritems():
76 if not isinstance(k, basestring):
76 if not isinstance(k, basestring):
77 raise ValueError('key %r in dict must be a string' % k)
77 raise ValueError('key %r in dict must be a string' % k)
78 if not isinstance(v, basestring):
78 if not isinstance(v, basestring):
79 raise ValueError('value %r in dict must be a string' % v)
79 raise ValueError('value %r in dict must be a string' % v)
80
80
81
81
82 #-----------------------------------------------------------------------------
82 #-----------------------------------------------------------------------------
83 # ZMQ Socket Channel classes
83 # ZMQ Socket Channel classes
84 #-----------------------------------------------------------------------------
84 #-----------------------------------------------------------------------------
85
85
86 class ZMQSocketChannel(Thread):
86 class ZMQSocketChannel(Thread):
87 """The base class for the channels that use ZMQ sockets.
87 """The base class for the channels that use ZMQ sockets.
88 """
88 """
89 context = None
89 context = None
90 session = None
90 session = None
91 socket = None
91 socket = None
92 ioloop = None
92 ioloop = None
93 stream = None
93 stream = None
94 _address = None
94 _address = None
95 _exiting = False
95 _exiting = False
96
96
97 def __init__(self, context, session, address):
97 def __init__(self, context, session, address):
98 """Create a channel
98 """Create a channel
99
99
100 Parameters
100 Parameters
101 ----------
101 ----------
102 context : :class:`zmq.Context`
102 context : :class:`zmq.Context`
103 The ZMQ context to use.
103 The ZMQ context to use.
104 session : :class:`session.Session`
104 session : :class:`session.Session`
105 The session to use.
105 The session to use.
106 address : tuple
106 address : tuple
107 Standard (ip, port) tuple that the kernel is listening on.
107 Standard (ip, port) tuple that the kernel is listening on.
108 """
108 """
109 super(ZMQSocketChannel, self).__init__()
109 super(ZMQSocketChannel, self).__init__()
110 self.daemon = True
110 self.daemon = True
111
111
112 self.context = context
112 self.context = context
113 self.session = session
113 self.session = session
114 if address[1] == 0:
114 if address[1] == 0:
115 message = 'The port number for a channel cannot be 0.'
115 message = 'The port number for a channel cannot be 0.'
116 raise InvalidPortNumber(message)
116 raise InvalidPortNumber(message)
117 self._address = address
117 self._address = address
118 atexit.register(self._notice_exit)
118 atexit.register(self._notice_exit)
119
119
120 def _notice_exit(self):
120 def _notice_exit(self):
121 self._exiting = True
121 self._exiting = True
122
122
123 def _run_loop(self):
123 def _run_loop(self):
124 """Run my loop, ignoring EINTR events in the poller"""
124 """Run my loop, ignoring EINTR events in the poller"""
125 while True:
125 while True:
126 try:
126 try:
127 self.ioloop.start()
127 self.ioloop.start()
128 except ZMQError as e:
128 except ZMQError as e:
129 if e.errno == errno.EINTR:
129 if e.errno == errno.EINTR:
130 continue
130 continue
131 else:
131 else:
132 raise
132 raise
133 except Exception:
133 except Exception:
134 if self._exiting:
134 if self._exiting:
135 break
135 break
136 else:
136 else:
137 raise
137 raise
138 else:
138 else:
139 break
139 break
140
140
141 def stop(self):
141 def stop(self):
142 """Stop the channel's activity.
142 """Stop the channel's activity.
143
143
144 This calls :method:`Thread.join` and returns when the thread
144 This calls :method:`Thread.join` and returns when the thread
145 terminates. :class:`RuntimeError` will be raised if
145 terminates. :class:`RuntimeError` will be raised if
146 :method:`self.start` is called again.
146 :method:`self.start` is called again.
147 """
147 """
148 self.join()
148 self.join()
149
149
150 @property
150 @property
151 def address(self):
151 def address(self):
152 """Get the channel's address as an (ip, port) tuple.
152 """Get the channel's address as an (ip, port) tuple.
153
153
154 By the default, the address is (localhost, 0), where 0 means a random
154 By the default, the address is (localhost, 0), where 0 means a random
155 port.
155 port.
156 """
156 """
157 return self._address
157 return self._address
158
158
159 def _queue_send(self, msg):
159 def _queue_send(self, msg):
160 """Queue a message to be sent from the IOLoop's thread.
160 """Queue a message to be sent from the IOLoop's thread.
161
161
162 Parameters
162 Parameters
163 ----------
163 ----------
164 msg : message to send
164 msg : message to send
165
165
166 This is threadsafe, as it uses IOLoop.add_callback to give the loop's
166 This is threadsafe, as it uses IOLoop.add_callback to give the loop's
167 thread control of the action.
167 thread control of the action.
168 """
168 """
169 def thread_send():
169 def thread_send():
170 self.session.send(self.stream, msg)
170 self.session.send(self.stream, msg)
171 self.ioloop.add_callback(thread_send)
171 self.ioloop.add_callback(thread_send)
172
172
173 def _handle_recv(self, msg):
173 def _handle_recv(self, msg):
174 """callback for stream.on_recv
174 """callback for stream.on_recv
175
175
176 unpacks message, and calls handlers with it.
176 unpacks message, and calls handlers with it.
177 """
177 """
178 ident,smsg = self.session.feed_identities(msg)
178 ident,smsg = self.session.feed_identities(msg)
179 self.call_handlers(self.session.unserialize(smsg))
179 self.call_handlers(self.session.unserialize(smsg))
180
180
181
181
182
182
183 class ShellSocketChannel(ZMQSocketChannel):
183 class ShellSocketChannel(ZMQSocketChannel):
184 """The DEALER channel for issues request/replies to the kernel.
184 """The DEALER channel for issues request/replies to the kernel.
185 """
185 """
186
186
187 command_queue = None
187 command_queue = None
188 # flag for whether execute requests should be allowed to call raw_input:
188 # flag for whether execute requests should be allowed to call raw_input:
189 allow_stdin = True
189 allow_stdin = True
190
190
191 def __init__(self, context, session, address):
191 def __init__(self, context, session, address):
192 super(ShellSocketChannel, self).__init__(context, session, address)
192 super(ShellSocketChannel, self).__init__(context, session, address)
193 self.ioloop = ioloop.IOLoop()
193 self.ioloop = ioloop.IOLoop()
194
194
195 def run(self):
195 def run(self):
196 """The thread's main activity. Call start() instead."""
196 """The thread's main activity. Call start() instead."""
197 self.socket = self.context.socket(zmq.DEALER)
197 self.socket = self.context.socket(zmq.DEALER)
198 self.socket.setsockopt(zmq.IDENTITY, self.session.bsession)
198 self.socket.setsockopt(zmq.IDENTITY, self.session.bsession)
199 self.socket.connect('tcp://%s:%i' % self.address)
199 self.socket.connect('tcp://%s:%i' % self.address)
200 self.stream = zmqstream.ZMQStream(self.socket, self.ioloop)
200 self.stream = zmqstream.ZMQStream(self.socket, self.ioloop)
201 self.stream.on_recv(self._handle_recv)
201 self.stream.on_recv(self._handle_recv)
202 self._run_loop()
202 self._run_loop()
203 try:
203 try:
204 self.socket.close()
204 self.socket.close()
205 except:
205 except:
206 pass
206 pass
207
207
208 def stop(self):
208 def stop(self):
209 self.ioloop.stop()
209 self.ioloop.stop()
210 super(ShellSocketChannel, self).stop()
210 super(ShellSocketChannel, self).stop()
211
211
212 def call_handlers(self, msg):
212 def call_handlers(self, msg):
213 """This method is called in the ioloop thread when a message arrives.
213 """This method is called in the ioloop thread when a message arrives.
214
214
215 Subclasses should override this method to handle incoming messages.
215 Subclasses should override this method to handle incoming messages.
216 It is important to remember that this method is called in the thread
216 It is important to remember that this method is called in the thread
217 so that some logic must be done to ensure that the application leve
217 so that some logic must be done to ensure that the application leve
218 handlers are called in the application thread.
218 handlers are called in the application thread.
219 """
219 """
220 raise NotImplementedError('call_handlers must be defined in a subclass.')
220 raise NotImplementedError('call_handlers must be defined in a subclass.')
221
221
222 def execute(self, code, silent=False,
222 def execute(self, code, silent=False,
223 user_variables=None, user_expressions=None, allow_stdin=None):
223 user_variables=None, user_expressions=None, allow_stdin=None):
224 """Execute code in the kernel.
224 """Execute code in the kernel.
225
225
226 Parameters
226 Parameters
227 ----------
227 ----------
228 code : str
228 code : str
229 A string of Python code.
229 A string of Python code.
230
230
231 silent : bool, optional (default False)
231 silent : bool, optional (default False)
232 If set, the kernel will execute the code as quietly possible.
232 If set, the kernel will execute the code as quietly possible.
233
233
234 user_variables : list, optional
234 user_variables : list, optional
235 A list of variable names to pull from the user's namespace. They
235 A list of variable names to pull from the user's namespace. They
236 will come back as a dict with these names as keys and their
236 will come back as a dict with these names as keys and their
237 :func:`repr` as values.
237 :func:`repr` as values.
238
238
239 user_expressions : dict, optional
239 user_expressions : dict, optional
240 A dict with string keys and to pull from the user's
240 A dict with string keys and to pull from the user's
241 namespace. They will come back as a dict with these names as keys
241 namespace. They will come back as a dict with these names as keys
242 and their :func:`repr` as values.
242 and their :func:`repr` as values.
243
243
244 allow_stdin : bool, optional
244 allow_stdin : bool, optional
245 Flag for
245 Flag for
246 A dict with string keys and to pull from the user's
246 A dict with string keys and to pull from the user's
247 namespace. They will come back as a dict with these names as keys
247 namespace. They will come back as a dict with these names as keys
248 and their :func:`repr` as values.
248 and their :func:`repr` as values.
249
249
250 Returns
250 Returns
251 -------
251 -------
252 The msg_id of the message sent.
252 The msg_id of the message sent.
253 """
253 """
254 if user_variables is None:
254 if user_variables is None:
255 user_variables = []
255 user_variables = []
256 if user_expressions is None:
256 if user_expressions is None:
257 user_expressions = {}
257 user_expressions = {}
258 if allow_stdin is None:
258 if allow_stdin is None:
259 allow_stdin = self.allow_stdin
259 allow_stdin = self.allow_stdin
260
260
261
261
262 # Don't waste network traffic if inputs are invalid
262 # Don't waste network traffic if inputs are invalid
263 if not isinstance(code, basestring):
263 if not isinstance(code, basestring):
264 raise ValueError('code %r must be a string' % code)
264 raise ValueError('code %r must be a string' % code)
265 validate_string_list(user_variables)
265 validate_string_list(user_variables)
266 validate_string_dict(user_expressions)
266 validate_string_dict(user_expressions)
267
267
268 # Create class for content/msg creation. Related to, but possibly
268 # Create class for content/msg creation. Related to, but possibly
269 # not in Session.
269 # not in Session.
270 content = dict(code=code, silent=silent,
270 content = dict(code=code, silent=silent,
271 user_variables=user_variables,
271 user_variables=user_variables,
272 user_expressions=user_expressions,
272 user_expressions=user_expressions,
273 allow_stdin=allow_stdin,
273 allow_stdin=allow_stdin,
274 )
274 )
275 msg = self.session.msg('execute_request', content)
275 msg = self.session.msg('execute_request', content)
276 self._queue_send(msg)
276 self._queue_send(msg)
277 return msg['header']['msg_id']
277 return msg['header']['msg_id']
278
278
279 def complete(self, text, line, cursor_pos, block=None):
279 def complete(self, text, line, cursor_pos, block=None):
280 """Tab complete text in the kernel's namespace.
280 """Tab complete text in the kernel's namespace.
281
281
282 Parameters
282 Parameters
283 ----------
283 ----------
284 text : str
284 text : str
285 The text to complete.
285 The text to complete.
286 line : str
286 line : str
287 The full line of text that is the surrounding context for the
287 The full line of text that is the surrounding context for the
288 text to complete.
288 text to complete.
289 cursor_pos : int
289 cursor_pos : int
290 The position of the cursor in the line where the completion was
290 The position of the cursor in the line where the completion was
291 requested.
291 requested.
292 block : str, optional
292 block : str, optional
293 The full block of code in which the completion is being requested.
293 The full block of code in which the completion is being requested.
294
294
295 Returns
295 Returns
296 -------
296 -------
297 The msg_id of the message sent.
297 The msg_id of the message sent.
298 """
298 """
299 content = dict(text=text, line=line, block=block, cursor_pos=cursor_pos)
299 content = dict(text=text, line=line, block=block, cursor_pos=cursor_pos)
300 msg = self.session.msg('complete_request', content)
300 msg = self.session.msg('complete_request', content)
301 self._queue_send(msg)
301 self._queue_send(msg)
302 return msg['header']['msg_id']
302 return msg['header']['msg_id']
303
303
304 def object_info(self, oname, detail_level=0):
304 def object_info(self, oname, detail_level=0):
305 """Get metadata information about an object.
305 """Get metadata information about an object.
306
306
307 Parameters
307 Parameters
308 ----------
308 ----------
309 oname : str
309 oname : str
310 A string specifying the object name.
310 A string specifying the object name.
311 detail_level : int, optional
311 detail_level : int, optional
312 The level of detail for the introspection (0-2)
312 The level of detail for the introspection (0-2)
313
313
314 Returns
314 Returns
315 -------
315 -------
316 The msg_id of the message sent.
316 The msg_id of the message sent.
317 """
317 """
318 content = dict(oname=oname, detail_level=detail_level)
318 content = dict(oname=oname, detail_level=detail_level)
319 msg = self.session.msg('object_info_request', content)
319 msg = self.session.msg('object_info_request', content)
320 self._queue_send(msg)
320 self._queue_send(msg)
321 return msg['header']['msg_id']
321 return msg['header']['msg_id']
322
322
323 def history(self, raw=True, output=False, hist_access_type='range', **kwargs):
323 def history(self, raw=True, output=False, hist_access_type='range', **kwargs):
324 """Get entries from the history list.
324 """Get entries from the history list.
325
325
326 Parameters
326 Parameters
327 ----------
327 ----------
328 raw : bool
328 raw : bool
329 If True, return the raw input.
329 If True, return the raw input.
330 output : bool
330 output : bool
331 If True, then return the output as well.
331 If True, then return the output as well.
332 hist_access_type : str
332 hist_access_type : str
333 'range' (fill in session, start and stop params), 'tail' (fill in n)
333 'range' (fill in session, start and stop params), 'tail' (fill in n)
334 or 'search' (fill in pattern param).
334 or 'search' (fill in pattern param).
335
335
336 session : int
336 session : int
337 For a range request, the session from which to get lines. Session
337 For a range request, the session from which to get lines. Session
338 numbers are positive integers; negative ones count back from the
338 numbers are positive integers; negative ones count back from the
339 current session.
339 current session.
340 start : int
340 start : int
341 The first line number of a history range.
341 The first line number of a history range.
342 stop : int
342 stop : int
343 The final (excluded) line number of a history range.
343 The final (excluded) line number of a history range.
344
344
345 n : int
345 n : int
346 The number of lines of history to get for a tail request.
346 The number of lines of history to get for a tail request.
347
347
348 pattern : str
348 pattern : str
349 The glob-syntax pattern for a search request.
349 The glob-syntax pattern for a search request.
350
350
351 Returns
351 Returns
352 -------
352 -------
353 The msg_id of the message sent.
353 The msg_id of the message sent.
354 """
354 """
355 content = dict(raw=raw, output=output, hist_access_type=hist_access_type,
355 content = dict(raw=raw, output=output, hist_access_type=hist_access_type,
356 **kwargs)
356 **kwargs)
357 msg = self.session.msg('history_request', content)
357 msg = self.session.msg('history_request', content)
358 self._queue_send(msg)
358 self._queue_send(msg)
359 return msg['header']['msg_id']
359 return msg['header']['msg_id']
360
360
361 def shutdown(self, restart=False):
361 def shutdown(self, restart=False):
362 """Request an immediate kernel shutdown.
362 """Request an immediate kernel shutdown.
363
363
364 Upon receipt of the (empty) reply, client code can safely assume that
364 Upon receipt of the (empty) reply, client code can safely assume that
365 the kernel has shut down and it's safe to forcefully terminate it if
365 the kernel has shut down and it's safe to forcefully terminate it if
366 it's still alive.
366 it's still alive.
367
367
368 The kernel will send the reply via a function registered with Python's
368 The kernel will send the reply via a function registered with Python's
369 atexit module, ensuring it's truly done as the kernel is done with all
369 atexit module, ensuring it's truly done as the kernel is done with all
370 normal operation.
370 normal operation.
371 """
371 """
372 # Send quit message to kernel. Once we implement kernel-side setattr,
372 # Send quit message to kernel. Once we implement kernel-side setattr,
373 # this should probably be done that way, but for now this will do.
373 # this should probably be done that way, but for now this will do.
374 msg = self.session.msg('shutdown_request', {'restart':restart})
374 msg = self.session.msg('shutdown_request', {'restart':restart})
375 self._queue_send(msg)
375 self._queue_send(msg)
376 return msg['header']['msg_id']
376 return msg['header']['msg_id']
377
377
378
378
379
379
380 class SubSocketChannel(ZMQSocketChannel):
380 class SubSocketChannel(ZMQSocketChannel):
381 """The SUB channel which listens for messages that the kernel publishes.
381 """The SUB channel which listens for messages that the kernel publishes.
382 """
382 """
383
383
384 def __init__(self, context, session, address):
384 def __init__(self, context, session, address):
385 super(SubSocketChannel, self).__init__(context, session, address)
385 super(SubSocketChannel, self).__init__(context, session, address)
386 self.ioloop = ioloop.IOLoop()
386 self.ioloop = ioloop.IOLoop()
387
387
388 def run(self):
388 def run(self):
389 """The thread's main activity. Call start() instead."""
389 """The thread's main activity. Call start() instead."""
390 self.socket = self.context.socket(zmq.SUB)
390 self.socket = self.context.socket(zmq.SUB)
391 self.socket.setsockopt(zmq.SUBSCRIBE,b'')
391 self.socket.setsockopt(zmq.SUBSCRIBE,b'')
392 self.socket.setsockopt(zmq.IDENTITY, self.session.bsession)
392 self.socket.setsockopt(zmq.IDENTITY, self.session.bsession)
393 self.socket.connect('tcp://%s:%i' % self.address)
393 self.socket.connect('tcp://%s:%i' % self.address)
394 self.stream = zmqstream.ZMQStream(self.socket, self.ioloop)
394 self.stream = zmqstream.ZMQStream(self.socket, self.ioloop)
395 self.stream.on_recv(self._handle_recv)
395 self.stream.on_recv(self._handle_recv)
396 self._run_loop()
396 self._run_loop()
397 try:
397 try:
398 self.socket.close()
398 self.socket.close()
399 except:
399 except:
400 pass
400 pass
401
401
402 def stop(self):
402 def stop(self):
403 self.ioloop.stop()
403 self.ioloop.stop()
404 super(SubSocketChannel, self).stop()
404 super(SubSocketChannel, self).stop()
405
405
406 def call_handlers(self, msg):
406 def call_handlers(self, msg):
407 """This method is called in the ioloop thread when a message arrives.
407 """This method is called in the ioloop thread when a message arrives.
408
408
409 Subclasses should override this method to handle incoming messages.
409 Subclasses should override this method to handle incoming messages.
410 It is important to remember that this method is called in the thread
410 It is important to remember that this method is called in the thread
411 so that some logic must be done to ensure that the application leve
411 so that some logic must be done to ensure that the application leve
412 handlers are called in the application thread.
412 handlers are called in the application thread.
413 """
413 """
414 raise NotImplementedError('call_handlers must be defined in a subclass.')
414 raise NotImplementedError('call_handlers must be defined in a subclass.')
415
415
416 def flush(self, timeout=1.0):
416 def flush(self, timeout=1.0):
417 """Immediately processes all pending messages on the SUB channel.
417 """Immediately processes all pending messages on the SUB channel.
418
418
419 Callers should use this method to ensure that :method:`call_handlers`
419 Callers should use this method to ensure that :method:`call_handlers`
420 has been called for all messages that have been received on the
420 has been called for all messages that have been received on the
421 0MQ SUB socket of this channel.
421 0MQ SUB socket of this channel.
422
422
423 This method is thread safe.
423 This method is thread safe.
424
424
425 Parameters
425 Parameters
426 ----------
426 ----------
427 timeout : float, optional
427 timeout : float, optional
428 The maximum amount of time to spend flushing, in seconds. The
428 The maximum amount of time to spend flushing, in seconds. The
429 default is one second.
429 default is one second.
430 """
430 """
431 # We do the IOLoop callback process twice to ensure that the IOLoop
431 # We do the IOLoop callback process twice to ensure that the IOLoop
432 # gets to perform at least one full poll.
432 # gets to perform at least one full poll.
433 stop_time = time.time() + timeout
433 stop_time = time.time() + timeout
434 for i in xrange(2):
434 for i in xrange(2):
435 self._flushed = False
435 self._flushed = False
436 self.ioloop.add_callback(self._flush)
436 self.ioloop.add_callback(self._flush)
437 while not self._flushed and time.time() < stop_time:
437 while not self._flushed and time.time() < stop_time:
438 time.sleep(0.01)
438 time.sleep(0.01)
439
439
440 def _flush(self):
440 def _flush(self):
441 """Callback for :method:`self.flush`."""
441 """Callback for :method:`self.flush`."""
442 self.stream.flush()
442 self.stream.flush()
443 self._flushed = True
443 self._flushed = True
444
444
445
445
446 class StdInSocketChannel(ZMQSocketChannel):
446 class StdInSocketChannel(ZMQSocketChannel):
447 """A reply channel to handle raw_input requests that the kernel makes."""
447 """A reply channel to handle raw_input requests that the kernel makes."""
448
448
449 msg_queue = None
449 msg_queue = None
450
450
451 def __init__(self, context, session, address):
451 def __init__(self, context, session, address):
452 super(StdInSocketChannel, self).__init__(context, session, address)
452 super(StdInSocketChannel, self).__init__(context, session, address)
453 self.ioloop = ioloop.IOLoop()
453 self.ioloop = ioloop.IOLoop()
454
454
455 def run(self):
455 def run(self):
456 """The thread's main activity. Call start() instead."""
456 """The thread's main activity. Call start() instead."""
457 self.socket = self.context.socket(zmq.DEALER)
457 self.socket = self.context.socket(zmq.DEALER)
458 self.socket.setsockopt(zmq.IDENTITY, self.session.bsession)
458 self.socket.setsockopt(zmq.IDENTITY, self.session.bsession)
459 self.socket.connect('tcp://%s:%i' % self.address)
459 self.socket.connect('tcp://%s:%i' % self.address)
460 self.stream = zmqstream.ZMQStream(self.socket, self.ioloop)
460 self.stream = zmqstream.ZMQStream(self.socket, self.ioloop)
461 self.stream.on_recv(self._handle_recv)
461 self.stream.on_recv(self._handle_recv)
462 self._run_loop()
462 self._run_loop()
463 try:
463 try:
464 self.socket.close()
464 self.socket.close()
465 except:
465 except:
466 pass
466 pass
467
467
468
468
469 def stop(self):
469 def stop(self):
470 self.ioloop.stop()
470 self.ioloop.stop()
471 super(StdInSocketChannel, self).stop()
471 super(StdInSocketChannel, self).stop()
472
472
473 def call_handlers(self, msg):
473 def call_handlers(self, msg):
474 """This method is called in the ioloop thread when a message arrives.
474 """This method is called in the ioloop thread when a message arrives.
475
475
476 Subclasses should override this method to handle incoming messages.
476 Subclasses should override this method to handle incoming messages.
477 It is important to remember that this method is called in the thread
477 It is important to remember that this method is called in the thread
478 so that some logic must be done to ensure that the application leve
478 so that some logic must be done to ensure that the application leve
479 handlers are called in the application thread.
479 handlers are called in the application thread.
480 """
480 """
481 raise NotImplementedError('call_handlers must be defined in a subclass.')
481 raise NotImplementedError('call_handlers must be defined in a subclass.')
482
482
483 def input(self, string):
483 def input(self, string):
484 """Send a string of raw input to the kernel."""
484 """Send a string of raw input to the kernel."""
485 content = dict(value=string)
485 content = dict(value=string)
486 msg = self.session.msg('input_reply', content)
486 msg = self.session.msg('input_reply', content)
487 self._queue_send(msg)
487 self._queue_send(msg)
488
488
489
489
490 class HBSocketChannel(ZMQSocketChannel):
490 class HBSocketChannel(ZMQSocketChannel):
491 """The heartbeat channel which monitors the kernel heartbeat.
491 """The heartbeat channel which monitors the kernel heartbeat.
492
492
493 Note that the heartbeat channel is paused by default. As long as you start
493 Note that the heartbeat channel is paused by default. As long as you start
494 this channel, the kernel manager will ensure that it is paused and un-paused
494 this channel, the kernel manager will ensure that it is paused and un-paused
495 as appropriate.
495 as appropriate.
496 """
496 """
497
497
498 time_to_dead = 3.0
498 time_to_dead = 3.0
499 socket = None
499 socket = None
500 poller = None
500 poller = None
501 _running = None
501 _running = None
502 _pause = None
502 _pause = None
503 _beating = None
503 _beating = None
504
504
505 def __init__(self, context, session, address):
505 def __init__(self, context, session, address):
506 super(HBSocketChannel, self).__init__(context, session, address)
506 super(HBSocketChannel, self).__init__(context, session, address)
507 self._running = False
507 self._running = False
508 self._pause =True
508 self._pause =True
509 self.poller = zmq.Poller()
509 self.poller = zmq.Poller()
510
510
511 def _create_socket(self):
511 def _create_socket(self):
512 if self.socket is not None:
512 if self.socket is not None:
513 # close previous socket, before opening a new one
513 # close previous socket, before opening a new one
514 self.poller.unregister(self.socket)
514 self.poller.unregister(self.socket)
515 self.socket.close()
515 self.socket.close()
516 self.socket = self.context.socket(zmq.REQ)
516 self.socket = self.context.socket(zmq.REQ)
517 self.socket.setsockopt(zmq.LINGER, 0)
517 self.socket.setsockopt(zmq.LINGER, 0)
518 self.socket.connect('tcp://%s:%i' % self.address)
518 self.socket.connect('tcp://%s:%i' % self.address)
519
519
520 self.poller.register(self.socket, zmq.POLLIN)
520 self.poller.register(self.socket, zmq.POLLIN)
521
521
522 def _poll(self, start_time):
522 def _poll(self, start_time):
523 """poll for heartbeat replies until we reach self.time_to_dead
523 """poll for heartbeat replies until we reach self.time_to_dead
524
524
525 Ignores interrupts, and returns the result of poll(), which
525 Ignores interrupts, and returns the result of poll(), which
526 will be an empty list if no messages arrived before the timeout,
526 will be an empty list if no messages arrived before the timeout,
527 or the event tuple if there is a message to receive.
527 or the event tuple if there is a message to receive.
528 """
528 """
529
529
530 until_dead = self.time_to_dead - (time.time() - start_time)
530 until_dead = self.time_to_dead - (time.time() - start_time)
531 # ensure poll at least once
531 # ensure poll at least once
532 until_dead = max(until_dead, 1e-3)
532 until_dead = max(until_dead, 1e-3)
533 events = []
533 events = []
534 while True:
534 while True:
535 try:
535 try:
536 events = self.poller.poll(1000 * until_dead)
536 events = self.poller.poll(1000 * until_dead)
537 except ZMQError as e:
537 except ZMQError as e:
538 if e.errno == errno.EINTR:
538 if e.errno == errno.EINTR:
539 # ignore interrupts during heartbeat
539 # ignore interrupts during heartbeat
540 # this may never actually happen
540 # this may never actually happen
541 until_dead = self.time_to_dead - (time.time() - start_time)
541 until_dead = self.time_to_dead - (time.time() - start_time)
542 until_dead = max(until_dead, 1e-3)
542 until_dead = max(until_dead, 1e-3)
543 pass
543 pass
544 else:
544 else:
545 raise
545 raise
546 except Exception:
546 except Exception:
547 if self._exiting:
547 if self._exiting:
548 break
548 break
549 else:
549 else:
550 raise
550 raise
551 else:
551 else:
552 break
552 break
553 return events
553 return events
554
554
555 def run(self):
555 def run(self):
556 """The thread's main activity. Call start() instead."""
556 """The thread's main activity. Call start() instead."""
557 self._create_socket()
557 self._create_socket()
558 self._running = True
558 self._running = True
559 self._beating = True
559 self._beating = True
560
560
561 while self._running:
561 while self._running:
562 if self._pause:
562 if self._pause:
563 # just sleep, and skip the rest of the loop
563 # just sleep, and skip the rest of the loop
564 time.sleep(self.time_to_dead)
564 time.sleep(self.time_to_dead)
565 continue
565 continue
566
566
567 since_last_heartbeat = 0.0
567 since_last_heartbeat = 0.0
568 # io.rprint('Ping from HB channel') # dbg
568 # io.rprint('Ping from HB channel') # dbg
569 # no need to catch EFSM here, because the previous event was
569 # no need to catch EFSM here, because the previous event was
570 # either a recv or connect, which cannot be followed by EFSM
570 # either a recv or connect, which cannot be followed by EFSM
571 self.socket.send(b'ping')
571 self.socket.send(b'ping')
572 request_time = time.time()
572 request_time = time.time()
573 ready = self._poll(request_time)
573 ready = self._poll(request_time)
574 if ready:
574 if ready:
575 self._beating = True
575 self._beating = True
576 # the poll above guarantees we have something to recv
576 # the poll above guarantees we have something to recv
577 self.socket.recv()
577 self.socket.recv()
578 # sleep the remainder of the cycle
578 # sleep the remainder of the cycle
579 remainder = self.time_to_dead - (time.time() - request_time)
579 remainder = self.time_to_dead - (time.time() - request_time)
580 if remainder > 0:
580 if remainder > 0:
581 time.sleep(remainder)
581 time.sleep(remainder)
582 continue
582 continue
583 else:
583 else:
584 # nothing was received within the time limit, signal heart failure
584 # nothing was received within the time limit, signal heart failure
585 self._beating = False
585 self._beating = False
586 since_last_heartbeat = time.time() - request_time
586 since_last_heartbeat = time.time() - request_time
587 self.call_handlers(since_last_heartbeat)
587 self.call_handlers(since_last_heartbeat)
588 # and close/reopen the socket, because the REQ/REP cycle has been broken
588 # and close/reopen the socket, because the REQ/REP cycle has been broken
589 self._create_socket()
589 self._create_socket()
590 continue
590 continue
591 try:
591 try:
592 self.socket.close()
592 self.socket.close()
593 except:
593 except:
594 pass
594 pass
595
595
596 def pause(self):
596 def pause(self):
597 """Pause the heartbeat."""
597 """Pause the heartbeat."""
598 self._pause = True
598 self._pause = True
599
599
600 def unpause(self):
600 def unpause(self):
601 """Unpause the heartbeat."""
601 """Unpause the heartbeat."""
602 self._pause = False
602 self._pause = False
603
603
604 def is_beating(self):
604 def is_beating(self):
605 """Is the heartbeat running and responsive (and not paused)."""
605 """Is the heartbeat running and responsive (and not paused)."""
606 if self.is_alive() and not self._pause and self._beating:
606 if self.is_alive() and not self._pause and self._beating:
607 return True
607 return True
608 else:
608 else:
609 return False
609 return False
610
610
611 def stop(self):
611 def stop(self):
612 self._running = False
612 self._running = False
613 super(HBSocketChannel, self).stop()
613 super(HBSocketChannel, self).stop()
614
614
615 def call_handlers(self, since_last_heartbeat):
615 def call_handlers(self, since_last_heartbeat):
616 """This method is called in the ioloop thread when a message arrives.
616 """This method is called in the ioloop thread when a message arrives.
617
617
618 Subclasses should override this method to handle incoming messages.
618 Subclasses should override this method to handle incoming messages.
619 It is important to remember that this method is called in the thread
619 It is important to remember that this method is called in the thread
620 so that some logic must be done to ensure that the application level
620 so that some logic must be done to ensure that the application level
621 handlers are called in the application thread.
621 handlers are called in the application thread.
622 """
622 """
623 raise NotImplementedError('call_handlers must be defined in a subclass.')
623 raise NotImplementedError('call_handlers must be defined in a subclass.')
624
624
625
625
626 #-----------------------------------------------------------------------------
626 #-----------------------------------------------------------------------------
627 # Main kernel manager class
627 # Main kernel manager class
628 #-----------------------------------------------------------------------------
628 #-----------------------------------------------------------------------------
629
629
630 class KernelManager(HasTraits):
630 class KernelManager(HasTraits):
631 """ Manages a kernel for a frontend.
631 """ Manages a kernel for a frontend.
632
632
633 The SUB channel is for the frontend to receive messages published by the
633 The SUB channel is for the frontend to receive messages published by the
634 kernel.
634 kernel.
635
635
636 The REQ channel is for the frontend to make requests of the kernel.
636 The REQ channel is for the frontend to make requests of the kernel.
637
637
638 The REP channel is for the kernel to request stdin (raw_input) from the
638 The REP channel is for the kernel to request stdin (raw_input) from the
639 frontend.
639 frontend.
640 """
640 """
641 # config object for passing to child configurables
641 # config object for passing to child configurables
642 config = Instance(Config)
642 config = Instance(Config)
643
643
644 # The PyZMQ Context to use for communication with the kernel.
644 # The PyZMQ Context to use for communication with the kernel.
645 context = Instance(zmq.Context)
645 context = Instance(zmq.Context)
646 def _context_default(self):
646 def _context_default(self):
647 return zmq.Context.instance()
647 return zmq.Context.instance()
648
648
649 # The Session to use for communication with the kernel.
649 # The Session to use for communication with the kernel.
650 session = Instance(Session)
650 session = Instance(Session)
651
651
652 # The kernel process with which the KernelManager is communicating.
652 # The kernel process with which the KernelManager is communicating.
653 kernel = Instance(Popen)
653 kernel = Instance(Popen)
654
654
655 # The addresses for the communication channels.
655 # The addresses for the communication channels.
656 connection_file = Unicode('')
656 connection_file = Unicode('')
657 ip = Unicode(LOCALHOST)
657 ip = Unicode(LOCALHOST)
658 def _ip_changed(self, name, old, new):
658 def _ip_changed(self, name, old, new):
659 if new == '*':
659 if new == '*':
660 self.ip = '0.0.0.0'
660 self.ip = '0.0.0.0'
661 shell_port = Integer(0)
661 shell_port = Integer(0)
662 iopub_port = Integer(0)
662 iopub_port = Integer(0)
663 stdin_port = Integer(0)
663 stdin_port = Integer(0)
664 hb_port = Integer(0)
664 hb_port = Integer(0)
665
665
666 # The classes to use for the various channels.
666 # The classes to use for the various channels.
667 shell_channel_class = Type(ShellSocketChannel)
667 shell_channel_class = Type(ShellSocketChannel)
668 sub_channel_class = Type(SubSocketChannel)
668 sub_channel_class = Type(SubSocketChannel)
669 stdin_channel_class = Type(StdInSocketChannel)
669 stdin_channel_class = Type(StdInSocketChannel)
670 hb_channel_class = Type(HBSocketChannel)
670 hb_channel_class = Type(HBSocketChannel)
671
671
672 # Protected traits.
672 # Protected traits.
673 _launch_args = Any
673 _launch_args = Any
674 _shell_channel = Any
674 _shell_channel = Any
675 _sub_channel = Any
675 _sub_channel = Any
676 _stdin_channel = Any
676 _stdin_channel = Any
677 _hb_channel = Any
677 _hb_channel = Any
678 _connection_file_written=Bool(False)
678 _connection_file_written=Bool(False)
679
679
680 def __init__(self, **kwargs):
680 def __init__(self, **kwargs):
681 super(KernelManager, self).__init__(**kwargs)
681 super(KernelManager, self).__init__(**kwargs)
682 if self.session is None:
682 if self.session is None:
683 self.session = Session(config=self.config)
683 self.session = Session(config=self.config)
684
684
685 def __del__(self):
685 def __del__(self):
686 self.cleanup_connection_file()
686 self.cleanup_connection_file()
687
687
688
688
689 #--------------------------------------------------------------------------
689 #--------------------------------------------------------------------------
690 # Channel management methods:
690 # Channel management methods:
691 #--------------------------------------------------------------------------
691 #--------------------------------------------------------------------------
692
692
693 def start_channels(self, shell=True, sub=True, stdin=True, hb=True):
693 def start_channels(self, shell=True, sub=True, stdin=True, hb=True):
694 """Starts the channels for this kernel.
694 """Starts the channels for this kernel.
695
695
696 This will create the channels if they do not exist and then start
696 This will create the channels if they do not exist and then start
697 them. If port numbers of 0 are being used (random ports) then you
697 them. If port numbers of 0 are being used (random ports) then you
698 must first call :method:`start_kernel`. If the channels have been
698 must first call :method:`start_kernel`. If the channels have been
699 stopped and you call this, :class:`RuntimeError` will be raised.
699 stopped and you call this, :class:`RuntimeError` will be raised.
700 """
700 """
701 if shell:
701 if shell:
702 self.shell_channel.start()
702 self.shell_channel.start()
703 if sub:
703 if sub:
704 self.sub_channel.start()
704 self.sub_channel.start()
705 if stdin:
705 if stdin:
706 self.stdin_channel.start()
706 self.stdin_channel.start()
707 self.shell_channel.allow_stdin = True
707 self.shell_channel.allow_stdin = True
708 else:
708 else:
709 self.shell_channel.allow_stdin = False
709 self.shell_channel.allow_stdin = False
710 if hb:
710 if hb:
711 self.hb_channel.start()
711 self.hb_channel.start()
712
712
713 def stop_channels(self):
713 def stop_channels(self):
714 """Stops all the running channels for this kernel.
714 """Stops all the running channels for this kernel.
715 """
715 """
716 if self.shell_channel.is_alive():
716 if self.shell_channel.is_alive():
717 self.shell_channel.stop()
717 self.shell_channel.stop()
718 if self.sub_channel.is_alive():
718 if self.sub_channel.is_alive():
719 self.sub_channel.stop()
719 self.sub_channel.stop()
720 if self.stdin_channel.is_alive():
720 if self.stdin_channel.is_alive():
721 self.stdin_channel.stop()
721 self.stdin_channel.stop()
722 if self.hb_channel.is_alive():
722 if self.hb_channel.is_alive():
723 self.hb_channel.stop()
723 self.hb_channel.stop()
724
724
725 @property
725 @property
726 def channels_running(self):
726 def channels_running(self):
727 """Are any of the channels created and running?"""
727 """Are any of the channels created and running?"""
728 return (self.shell_channel.is_alive() or self.sub_channel.is_alive() or
728 return (self.shell_channel.is_alive() or self.sub_channel.is_alive() or
729 self.stdin_channel.is_alive() or self.hb_channel.is_alive())
729 self.stdin_channel.is_alive() or self.hb_channel.is_alive())
730
730
731 #--------------------------------------------------------------------------
731 #--------------------------------------------------------------------------
732 # Kernel process management methods:
732 # Kernel process management methods:
733 #--------------------------------------------------------------------------
733 #--------------------------------------------------------------------------
734
734
735 def cleanup_connection_file(self):
735 def cleanup_connection_file(self):
736 """cleanup connection file *if we wrote it*
736 """cleanup connection file *if we wrote it*
737
737
738 Will not raise if the connection file was already removed somehow.
738 Will not raise if the connection file was already removed somehow.
739 """
739 """
740 if self._connection_file_written:
740 if self._connection_file_written:
741 # cleanup connection files on full shutdown of kernel we started
741 # cleanup connection files on full shutdown of kernel we started
742 self._connection_file_written = False
742 self._connection_file_written = False
743 try:
743 try:
744 os.remove(self.connection_file)
744 os.remove(self.connection_file)
745 except OSError:
745 except OSError:
746 pass
746 pass
747
747
748 def load_connection_file(self):
748 def load_connection_file(self):
749 """load connection info from JSON dict in self.connection_file"""
749 """load connection info from JSON dict in self.connection_file"""
750 with open(self.connection_file) as f:
750 with open(self.connection_file) as f:
751 cfg = json.loads(f.read())
751 cfg = json.loads(f.read())
752
752
753 self.ip = cfg['ip']
753 self.ip = cfg['ip']
754 self.shell_port = cfg['shell_port']
754 self.shell_port = cfg['shell_port']
755 self.stdin_port = cfg['stdin_port']
755 self.stdin_port = cfg['stdin_port']
756 self.iopub_port = cfg['iopub_port']
756 self.iopub_port = cfg['iopub_port']
757 self.hb_port = cfg['hb_port']
757 self.hb_port = cfg['hb_port']
758 self.session.key = str_to_bytes(cfg['key'])
758 self.session.key = str_to_bytes(cfg['key'])
759
759
760 def write_connection_file(self):
760 def write_connection_file(self):
761 """write connection info to JSON dict in self.connection_file"""
761 """write connection info to JSON dict in self.connection_file"""
762 if self._connection_file_written:
762 if self._connection_file_written:
763 return
763 return
764 self.connection_file,cfg = write_connection_file(self.connection_file,
764 self.connection_file,cfg = write_connection_file(self.connection_file,
765 ip=self.ip, key=self.session.key,
765 ip=self.ip, key=self.session.key,
766 stdin_port=self.stdin_port, iopub_port=self.iopub_port,
766 stdin_port=self.stdin_port, iopub_port=self.iopub_port,
767 shell_port=self.shell_port, hb_port=self.hb_port)
767 shell_port=self.shell_port, hb_port=self.hb_port)
768 # write_connection_file also sets default ports:
768 # write_connection_file also sets default ports:
769 self.shell_port = cfg['shell_port']
769 self.shell_port = cfg['shell_port']
770 self.stdin_port = cfg['stdin_port']
770 self.stdin_port = cfg['stdin_port']
771 self.iopub_port = cfg['iopub_port']
771 self.iopub_port = cfg['iopub_port']
772 self.hb_port = cfg['hb_port']
772 self.hb_port = cfg['hb_port']
773
773
774 self._connection_file_written = True
774 self._connection_file_written = True
775
775
776 def start_kernel(self, **kw):
776 def start_kernel(self, **kw):
777 """Starts a kernel process and configures the manager to use it.
777 """Starts a kernel process and configures the manager to use it.
778
778
779 If random ports (port=0) are being used, this method must be called
779 If random ports (port=0) are being used, this method must be called
780 before the channels are created.
780 before the channels are created.
781
781
782 Parameters:
782 Parameters:
783 -----------
783 -----------
784 launcher : callable, optional (default None)
784 launcher : callable, optional (default None)
785 A custom function for launching the kernel process (generally a
785 A custom function for launching the kernel process (generally a
786 wrapper around ``entry_point.base_launch_kernel``). In most cases,
786 wrapper around ``entry_point.base_launch_kernel``). In most cases,
787 it should not be necessary to use this parameter.
787 it should not be necessary to use this parameter.
788
788
789 **kw : optional
789 **kw : optional
790 See respective options for IPython and Python kernels.
790 See respective options for IPython and Python kernels.
791 """
791 """
792 if self.ip not in LOCAL_IPS:
792 if self.ip not in LOCAL_IPS:
793 raise RuntimeError("Can only launch a kernel on a local interface. "
793 raise RuntimeError("Can only launch a kernel on a local interface. "
794 "Make sure that the '*_address' attributes are "
794 "Make sure that the '*_address' attributes are "
795 "configured properly. "
795 "configured properly. "
796 "Currently valid addresses are: %s"%LOCAL_IPS
796 "Currently valid addresses are: %s"%LOCAL_IPS
797 )
797 )
798
798
799 # write connection file / get default ports
799 # write connection file / get default ports
800 self.write_connection_file()
800 self.write_connection_file()
801
801
802 self._launch_args = kw.copy()
802 self._launch_args = kw.copy()
803 launch_kernel = kw.pop('launcher', None)
803 launch_kernel = kw.pop('launcher', None)
804 if launch_kernel is None:
804 if launch_kernel is None:
805 from ipkernel import launch_kernel
805 from ipkernel import launch_kernel
806 self.kernel = launch_kernel(fname=self.connection_file, **kw)
806 self.kernel = launch_kernel(fname=self.connection_file, **kw)
807
807
808 def shutdown_kernel(self, restart=False):
808 def shutdown_kernel(self, restart=False):
809 """ Attempts to the stop the kernel process cleanly. If the kernel
809 """ Attempts to the stop the kernel process cleanly. If the kernel
810 cannot be stopped, it is killed, if possible.
810 cannot be stopped, it is killed, if possible.
811 """
811 """
812 # FIXME: Shutdown does not work on Windows due to ZMQ errors!
812 # FIXME: Shutdown does not work on Windows due to ZMQ errors!
813 if sys.platform == 'win32':
813 if sys.platform == 'win32':
814 self.kill_kernel()
814 self.kill_kernel()
815 return
815 return
816
816
817 # Pause the heart beat channel if it exists.
817 # Pause the heart beat channel if it exists.
818 if self._hb_channel is not None:
818 if self._hb_channel is not None:
819 self._hb_channel.pause()
819 self._hb_channel.pause()
820
820
821 # Don't send any additional kernel kill messages immediately, to give
821 # Don't send any additional kernel kill messages immediately, to give
822 # the kernel a chance to properly execute shutdown actions. Wait for at
822 # the kernel a chance to properly execute shutdown actions. Wait for at
823 # most 1s, checking every 0.1s.
823 # most 1s, checking every 0.1s.
824 self.shell_channel.shutdown(restart=restart)
824 self.shell_channel.shutdown(restart=restart)
825 for i in range(10):
825 for i in range(10):
826 if self.is_alive:
826 if self.is_alive:
827 time.sleep(0.1)
827 time.sleep(0.1)
828 else:
828 else:
829 break
829 break
830 else:
830 else:
831 # OK, we've waited long enough.
831 # OK, we've waited long enough.
832 if self.has_kernel:
832 if self.has_kernel:
833 self.kill_kernel()
833 self.kill_kernel()
834
834
835 if not restart and self._connection_file_written:
835 if not restart and self._connection_file_written:
836 # cleanup connection files on full shutdown of kernel we started
836 # cleanup connection files on full shutdown of kernel we started
837 self._connection_file_written = False
837 self._connection_file_written = False
838 try:
838 try:
839 os.remove(self.connection_file)
839 os.remove(self.connection_file)
840 except IOError:
840 except IOError:
841 pass
841 pass
842
842
843 def restart_kernel(self, now=False, **kw):
843 def restart_kernel(self, now=False, **kw):
844 """Restarts a kernel with the arguments that were used to launch it.
844 """Restarts a kernel with the arguments that were used to launch it.
845
845
846 If the old kernel was launched with random ports, the same ports will be
846 If the old kernel was launched with random ports, the same ports will be
847 used for the new kernel.
847 used for the new kernel.
848
848
849 Parameters
849 Parameters
850 ----------
850 ----------
851 now : bool, optional
851 now : bool, optional
852 If True, the kernel is forcefully restarted *immediately*, without
852 If True, the kernel is forcefully restarted *immediately*, without
853 having a chance to do any cleanup action. Otherwise the kernel is
853 having a chance to do any cleanup action. Otherwise the kernel is
854 given 1s to clean up before a forceful restart is issued.
854 given 1s to clean up before a forceful restart is issued.
855
855
856 In all cases the kernel is restarted, the only difference is whether
856 In all cases the kernel is restarted, the only difference is whether
857 it is given a chance to perform a clean shutdown or not.
857 it is given a chance to perform a clean shutdown or not.
858
858
859 **kw : optional
859 **kw : optional
860 Any options specified here will replace those used to launch the
860 Any options specified here will replace those used to launch the
861 kernel.
861 kernel.
862 """
862 """
863 if self._launch_args is None:
863 if self._launch_args is None:
864 raise RuntimeError("Cannot restart the kernel. "
864 raise RuntimeError("Cannot restart the kernel. "
865 "No previous call to 'start_kernel'.")
865 "No previous call to 'start_kernel'.")
866 else:
866 else:
867 # Stop currently running kernel.
867 # Stop currently running kernel.
868 if self.has_kernel:
868 if self.has_kernel:
869 if now:
869 if now:
870 self.kill_kernel()
870 self.kill_kernel()
871 else:
871 else:
872 self.shutdown_kernel(restart=True)
872 self.shutdown_kernel(restart=True)
873
873
874 # Start new kernel.
874 # Start new kernel.
875 self._launch_args.update(kw)
875 self._launch_args.update(kw)
876 self.start_kernel(**self._launch_args)
876 self.start_kernel(**self._launch_args)
877
877
878 # FIXME: Messages get dropped in Windows due to probable ZMQ bug
878 # FIXME: Messages get dropped in Windows due to probable ZMQ bug
879 # unless there is some delay here.
879 # unless there is some delay here.
880 if sys.platform == 'win32':
880 if sys.platform == 'win32':
881 time.sleep(0.2)
881 time.sleep(0.2)
882
882
883 @property
883 @property
884 def has_kernel(self):
884 def has_kernel(self):
885 """Returns whether a kernel process has been specified for the kernel
885 """Returns whether a kernel process has been specified for the kernel
886 manager.
886 manager.
887 """
887 """
888 return self.kernel is not None
888 return self.kernel is not None
889
889
890 def kill_kernel(self):
890 def kill_kernel(self):
891 """ Kill the running kernel. """
891 """ Kill the running kernel. """
892 if self.has_kernel:
892 if self.has_kernel:
893 # Pause the heart beat channel if it exists.
893 # Pause the heart beat channel if it exists.
894 if self._hb_channel is not None:
894 if self._hb_channel is not None:
895 self._hb_channel.pause()
895 self._hb_channel.pause()
896
896
897 # Attempt to kill the kernel.
897 # Attempt to kill the kernel.
898 try:
898 try:
899 self.kernel.kill()
899 self.kernel.kill()
900 except OSError, e:
900 except OSError as e:
901 # In Windows, we will get an Access Denied error if the process
901 # In Windows, we will get an Access Denied error if the process
902 # has already terminated. Ignore it.
902 # has already terminated. Ignore it.
903 if sys.platform == 'win32':
903 if sys.platform == 'win32':
904 if e.winerror != 5:
904 if e.winerror != 5:
905 raise
905 raise
906 # On Unix, we may get an ESRCH error if the process has already
906 # On Unix, we may get an ESRCH error if the process has already
907 # terminated. Ignore it.
907 # terminated. Ignore it.
908 else:
908 else:
909 from errno import ESRCH
909 from errno import ESRCH
910 if e.errno != ESRCH:
910 if e.errno != ESRCH:
911 raise
911 raise
912 self.kernel = None
912 self.kernel = None
913 else:
913 else:
914 raise RuntimeError("Cannot kill kernel. No kernel is running!")
914 raise RuntimeError("Cannot kill kernel. No kernel is running!")
915
915
916 def interrupt_kernel(self):
916 def interrupt_kernel(self):
917 """ Interrupts the kernel. Unlike ``signal_kernel``, this operation is
917 """ Interrupts the kernel. Unlike ``signal_kernel``, this operation is
918 well supported on all platforms.
918 well supported on all platforms.
919 """
919 """
920 if self.has_kernel:
920 if self.has_kernel:
921 if sys.platform == 'win32':
921 if sys.platform == 'win32':
922 from parentpoller import ParentPollerWindows as Poller
922 from parentpoller import ParentPollerWindows as Poller
923 Poller.send_interrupt(self.kernel.win32_interrupt_event)
923 Poller.send_interrupt(self.kernel.win32_interrupt_event)
924 else:
924 else:
925 self.kernel.send_signal(signal.SIGINT)
925 self.kernel.send_signal(signal.SIGINT)
926 else:
926 else:
927 raise RuntimeError("Cannot interrupt kernel. No kernel is running!")
927 raise RuntimeError("Cannot interrupt kernel. No kernel is running!")
928
928
929 def signal_kernel(self, signum):
929 def signal_kernel(self, signum):
930 """ Sends a signal to the kernel. Note that since only SIGTERM is
930 """ Sends a signal to the kernel. Note that since only SIGTERM is
931 supported on Windows, this function is only useful on Unix systems.
931 supported on Windows, this function is only useful on Unix systems.
932 """
932 """
933 if self.has_kernel:
933 if self.has_kernel:
934 self.kernel.send_signal(signum)
934 self.kernel.send_signal(signum)
935 else:
935 else:
936 raise RuntimeError("Cannot signal kernel. No kernel is running!")
936 raise RuntimeError("Cannot signal kernel. No kernel is running!")
937
937
938 @property
938 @property
939 def is_alive(self):
939 def is_alive(self):
940 """Is the kernel process still running?"""
940 """Is the kernel process still running?"""
941 if self.has_kernel:
941 if self.has_kernel:
942 if self.kernel.poll() is None:
942 if self.kernel.poll() is None:
943 return True
943 return True
944 else:
944 else:
945 return False
945 return False
946 elif self._hb_channel is not None:
946 elif self._hb_channel is not None:
947 # We didn't start the kernel with this KernelManager so we
947 # We didn't start the kernel with this KernelManager so we
948 # use the heartbeat.
948 # use the heartbeat.
949 return self._hb_channel.is_beating()
949 return self._hb_channel.is_beating()
950 else:
950 else:
951 # no heartbeat and not local, we can't tell if it's running,
951 # no heartbeat and not local, we can't tell if it's running,
952 # so naively return True
952 # so naively return True
953 return True
953 return True
954
954
955 #--------------------------------------------------------------------------
955 #--------------------------------------------------------------------------
956 # Channels used for communication with the kernel:
956 # Channels used for communication with the kernel:
957 #--------------------------------------------------------------------------
957 #--------------------------------------------------------------------------
958
958
959 @property
959 @property
960 def shell_channel(self):
960 def shell_channel(self):
961 """Get the REQ socket channel object to make requests of the kernel."""
961 """Get the REQ socket channel object to make requests of the kernel."""
962 if self._shell_channel is None:
962 if self._shell_channel is None:
963 self._shell_channel = self.shell_channel_class(self.context,
963 self._shell_channel = self.shell_channel_class(self.context,
964 self.session,
964 self.session,
965 (self.ip, self.shell_port))
965 (self.ip, self.shell_port))
966 return self._shell_channel
966 return self._shell_channel
967
967
968 @property
968 @property
969 def sub_channel(self):
969 def sub_channel(self):
970 """Get the SUB socket channel object."""
970 """Get the SUB socket channel object."""
971 if self._sub_channel is None:
971 if self._sub_channel is None:
972 self._sub_channel = self.sub_channel_class(self.context,
972 self._sub_channel = self.sub_channel_class(self.context,
973 self.session,
973 self.session,
974 (self.ip, self.iopub_port))
974 (self.ip, self.iopub_port))
975 return self._sub_channel
975 return self._sub_channel
976
976
977 @property
977 @property
978 def stdin_channel(self):
978 def stdin_channel(self):
979 """Get the REP socket channel object to handle stdin (raw_input)."""
979 """Get the REP socket channel object to handle stdin (raw_input)."""
980 if self._stdin_channel is None:
980 if self._stdin_channel is None:
981 self._stdin_channel = self.stdin_channel_class(self.context,
981 self._stdin_channel = self.stdin_channel_class(self.context,
982 self.session,
982 self.session,
983 (self.ip, self.stdin_port))
983 (self.ip, self.stdin_port))
984 return self._stdin_channel
984 return self._stdin_channel
985
985
986 @property
986 @property
987 def hb_channel(self):
987 def hb_channel(self):
988 """Get the heartbeat socket channel object to check that the
988 """Get the heartbeat socket channel object to check that the
989 kernel is alive."""
989 kernel is alive."""
990 if self._hb_channel is None:
990 if self._hb_channel is None:
991 self._hb_channel = self.hb_channel_class(self.context,
991 self._hb_channel = self.hb_channel_class(self.context,
992 self.session,
992 self.session,
993 (self.ip, self.hb_port))
993 (self.ip, self.hb_port))
994 return self._hb_channel
994 return self._hb_channel
@@ -1,136 +1,136 b''
1 # Standard library imports.
1 # Standard library imports.
2 try:
2 try:
3 import ctypes
3 import ctypes
4 except:
4 except:
5 ctypes = None
5 ctypes = None
6 import os
6 import os
7 import platform
7 import platform
8 import time
8 import time
9 from thread import interrupt_main
9 from thread import interrupt_main
10 from threading import Thread
10 from threading import Thread
11
11
12 from IPython.utils.warn import warn
12 from IPython.utils.warn import warn
13
13
14
14
15 class ParentPollerUnix(Thread):
15 class ParentPollerUnix(Thread):
16 """ A Unix-specific daemon thread that terminates the program immediately
16 """ A Unix-specific daemon thread that terminates the program immediately
17 when the parent process no longer exists.
17 when the parent process no longer exists.
18 """
18 """
19
19
20 def __init__(self):
20 def __init__(self):
21 super(ParentPollerUnix, self).__init__()
21 super(ParentPollerUnix, self).__init__()
22 self.daemon = True
22 self.daemon = True
23
23
24 def run(self):
24 def run(self):
25 # We cannot use os.waitpid because it works only for child processes.
25 # We cannot use os.waitpid because it works only for child processes.
26 from errno import EINTR
26 from errno import EINTR
27 while True:
27 while True:
28 try:
28 try:
29 if os.getppid() == 1:
29 if os.getppid() == 1:
30 os._exit(1)
30 os._exit(1)
31 time.sleep(1.0)
31 time.sleep(1.0)
32 except OSError, e:
32 except OSError as e:
33 if e.errno == EINTR:
33 if e.errno == EINTR:
34 continue
34 continue
35 raise
35 raise
36
36
37
37
38 class ParentPollerWindows(Thread):
38 class ParentPollerWindows(Thread):
39 """ A Windows-specific daemon thread that listens for a special event that
39 """ A Windows-specific daemon thread that listens for a special event that
40 signals an interrupt and, optionally, terminates the program immediately
40 signals an interrupt and, optionally, terminates the program immediately
41 when the parent process no longer exists.
41 when the parent process no longer exists.
42 """
42 """
43
43
44 def __init__(self, interrupt_handle=None, parent_handle=None):
44 def __init__(self, interrupt_handle=None, parent_handle=None):
45 """ Create the poller. At least one of the optional parameters must be
45 """ Create the poller. At least one of the optional parameters must be
46 provided.
46 provided.
47
47
48 Parameters:
48 Parameters:
49 -----------
49 -----------
50 interrupt_handle : HANDLE (int), optional
50 interrupt_handle : HANDLE (int), optional
51 If provided, the program will generate a Ctrl+C event when this
51 If provided, the program will generate a Ctrl+C event when this
52 handle is signaled.
52 handle is signaled.
53
53
54 parent_handle : HANDLE (int), optional
54 parent_handle : HANDLE (int), optional
55 If provided, the program will terminate immediately when this
55 If provided, the program will terminate immediately when this
56 handle is signaled.
56 handle is signaled.
57 """
57 """
58 assert(interrupt_handle or parent_handle)
58 assert(interrupt_handle or parent_handle)
59 super(ParentPollerWindows, self).__init__()
59 super(ParentPollerWindows, self).__init__()
60 if ctypes is None:
60 if ctypes is None:
61 raise ImportError("ParentPollerWindows requires ctypes")
61 raise ImportError("ParentPollerWindows requires ctypes")
62 self.daemon = True
62 self.daemon = True
63 self.interrupt_handle = interrupt_handle
63 self.interrupt_handle = interrupt_handle
64 self.parent_handle = parent_handle
64 self.parent_handle = parent_handle
65
65
66 @staticmethod
66 @staticmethod
67 def create_interrupt_event():
67 def create_interrupt_event():
68 """ Create an interrupt event handle.
68 """ Create an interrupt event handle.
69
69
70 The parent process should use this static method for creating the
70 The parent process should use this static method for creating the
71 interrupt event that is passed to the child process. It should store
71 interrupt event that is passed to the child process. It should store
72 this handle and use it with ``send_interrupt`` to interrupt the child
72 this handle and use it with ``send_interrupt`` to interrupt the child
73 process.
73 process.
74 """
74 """
75 # Create a security attributes struct that permits inheritance of the
75 # Create a security attributes struct that permits inheritance of the
76 # handle by new processes.
76 # handle by new processes.
77 # FIXME: We can clean up this mess by requiring pywin32 for IPython.
77 # FIXME: We can clean up this mess by requiring pywin32 for IPython.
78 class SECURITY_ATTRIBUTES(ctypes.Structure):
78 class SECURITY_ATTRIBUTES(ctypes.Structure):
79 _fields_ = [ ("nLength", ctypes.c_int),
79 _fields_ = [ ("nLength", ctypes.c_int),
80 ("lpSecurityDescriptor", ctypes.c_void_p),
80 ("lpSecurityDescriptor", ctypes.c_void_p),
81 ("bInheritHandle", ctypes.c_int) ]
81 ("bInheritHandle", ctypes.c_int) ]
82 sa = SECURITY_ATTRIBUTES()
82 sa = SECURITY_ATTRIBUTES()
83 sa_p = ctypes.pointer(sa)
83 sa_p = ctypes.pointer(sa)
84 sa.nLength = ctypes.sizeof(SECURITY_ATTRIBUTES)
84 sa.nLength = ctypes.sizeof(SECURITY_ATTRIBUTES)
85 sa.lpSecurityDescriptor = 0
85 sa.lpSecurityDescriptor = 0
86 sa.bInheritHandle = 1
86 sa.bInheritHandle = 1
87
87
88 return ctypes.windll.kernel32.CreateEventA(
88 return ctypes.windll.kernel32.CreateEventA(
89 sa_p, # lpEventAttributes
89 sa_p, # lpEventAttributes
90 False, # bManualReset
90 False, # bManualReset
91 False, # bInitialState
91 False, # bInitialState
92 '') # lpName
92 '') # lpName
93
93
94 @staticmethod
94 @staticmethod
95 def send_interrupt(interrupt_handle):
95 def send_interrupt(interrupt_handle):
96 """ Sends an interrupt event using the specified handle.
96 """ Sends an interrupt event using the specified handle.
97 """
97 """
98 ctypes.windll.kernel32.SetEvent(interrupt_handle)
98 ctypes.windll.kernel32.SetEvent(interrupt_handle)
99
99
100 def run(self):
100 def run(self):
101 """ Run the poll loop. This method never returns.
101 """ Run the poll loop. This method never returns.
102 """
102 """
103 from _subprocess import WAIT_OBJECT_0, INFINITE
103 from _subprocess import WAIT_OBJECT_0, INFINITE
104
104
105 # Build the list of handle to listen on.
105 # Build the list of handle to listen on.
106 handles = []
106 handles = []
107 if self.interrupt_handle:
107 if self.interrupt_handle:
108 handles.append(self.interrupt_handle)
108 handles.append(self.interrupt_handle)
109 if self.parent_handle:
109 if self.parent_handle:
110 handles.append(self.parent_handle)
110 handles.append(self.parent_handle)
111 arch = platform.architecture()[0]
111 arch = platform.architecture()[0]
112 c_int = ctypes.c_int64 if arch.startswith('64') else ctypes.c_int
112 c_int = ctypes.c_int64 if arch.startswith('64') else ctypes.c_int
113
113
114 # Listen forever.
114 # Listen forever.
115 while True:
115 while True:
116 result = ctypes.windll.kernel32.WaitForMultipleObjects(
116 result = ctypes.windll.kernel32.WaitForMultipleObjects(
117 len(handles), # nCount
117 len(handles), # nCount
118 (c_int * len(handles))(*handles), # lpHandles
118 (c_int * len(handles))(*handles), # lpHandles
119 False, # bWaitAll
119 False, # bWaitAll
120 INFINITE) # dwMilliseconds
120 INFINITE) # dwMilliseconds
121
121
122 if WAIT_OBJECT_0 <= result < len(handles):
122 if WAIT_OBJECT_0 <= result < len(handles):
123 handle = handles[result - WAIT_OBJECT_0]
123 handle = handles[result - WAIT_OBJECT_0]
124
124
125 if handle == self.interrupt_handle:
125 if handle == self.interrupt_handle:
126 interrupt_main()
126 interrupt_main()
127
127
128 elif handle == self.parent_handle:
128 elif handle == self.parent_handle:
129 os._exit(1)
129 os._exit(1)
130 elif result < 0:
130 elif result < 0:
131 # wait failed, just give up and stop polling.
131 # wait failed, just give up and stop polling.
132 warn("""Parent poll failed. If the frontend dies,
132 warn("""Parent poll failed. If the frontend dies,
133 the kernel may be left running. Please let us know
133 the kernel may be left running. Please let us know
134 about your system (bitness, Python, etc.) at
134 about your system (bitness, Python, etc.) at
135 ipython-dev@scipy.org""")
135 ipython-dev@scipy.org""")
136 return
136 return
General Comments 0
You need to be logged in to leave comments. Login now