##// END OF EJS Templates
conform to pep 3110...
Matthias BUSSONNIER -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -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 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now