##// END OF EJS Templates
Merge pull request #770 from minrk/jsonclean...
Fernando Perez -
r4797:ede79361 merge
parent child Browse files
Show More
@@ -1,660 +1,661 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 re
22 import re
23 import sys
23 import sys
24
24
25 from IPython.external import argparse
25 from IPython.external import argparse
26 from IPython.utils.path import filefind, get_ipython_dir
26 from IPython.utils.path import filefind, get_ipython_dir
27 from IPython.utils import py3compat, warn
27 from IPython.utils import py3compat, text, warn
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Exceptions
30 # Exceptions
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33
33
34 class ConfigError(Exception):
34 class ConfigError(Exception):
35 pass
35 pass
36
36
37
37
38 class ConfigLoaderError(ConfigError):
38 class ConfigLoaderError(ConfigError):
39 pass
39 pass
40
40
41 class ArgumentError(ConfigLoaderError):
41 class ArgumentError(ConfigLoaderError):
42 pass
42 pass
43
43
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45 # Argparse fix
45 # Argparse fix
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47
47
48 # Unfortunately argparse by default prints help messages to stderr instead of
48 # Unfortunately argparse by default prints help messages to stderr instead of
49 # stdout. This makes it annoying to capture long help screens at the command
49 # stdout. This makes it annoying to capture long help screens at the command
50 # line, since one must know how to pipe stderr, which many users don't know how
50 # line, since one must know how to pipe stderr, which many users don't know how
51 # to do. So we override the print_help method with one that defaults to
51 # to do. So we override the print_help method with one that defaults to
52 # stdout and use our class instead.
52 # stdout and use our class instead.
53
53
54 class ArgumentParser(argparse.ArgumentParser):
54 class ArgumentParser(argparse.ArgumentParser):
55 """Simple argparse subclass that prints help to stdout by default."""
55 """Simple argparse subclass that prints help to stdout by default."""
56
56
57 def print_help(self, file=None):
57 def print_help(self, file=None):
58 if file is None:
58 if file is None:
59 file = sys.stdout
59 file = sys.stdout
60 return super(ArgumentParser, self).print_help(file)
60 return super(ArgumentParser, self).print_help(file)
61
61
62 print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__
62 print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__
63
63
64 #-----------------------------------------------------------------------------
64 #-----------------------------------------------------------------------------
65 # Config class for holding config information
65 # Config class for holding config information
66 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
67
67
68
68
69 class Config(dict):
69 class Config(dict):
70 """An attribute based dict that can do smart merges."""
70 """An attribute based dict that can do smart merges."""
71
71
72 def __init__(self, *args, **kwds):
72 def __init__(self, *args, **kwds):
73 dict.__init__(self, *args, **kwds)
73 dict.__init__(self, *args, **kwds)
74 # This sets self.__dict__ = self, but it has to be done this way
74 # This sets self.__dict__ = self, but it has to be done this way
75 # because we are also overriding __setattr__.
75 # because we are also overriding __setattr__.
76 dict.__setattr__(self, '__dict__', self)
76 dict.__setattr__(self, '__dict__', self)
77
77
78 def _merge(self, other):
78 def _merge(self, other):
79 to_update = {}
79 to_update = {}
80 for k, v in other.iteritems():
80 for k, v in other.iteritems():
81 if not self.has_key(k):
81 if not self.has_key(k):
82 to_update[k] = v
82 to_update[k] = v
83 else: # I have this key
83 else: # I have this key
84 if isinstance(v, Config):
84 if isinstance(v, Config):
85 # Recursively merge common sub Configs
85 # Recursively merge common sub Configs
86 self[k]._merge(v)
86 self[k]._merge(v)
87 else:
87 else:
88 # Plain updates for non-Configs
88 # Plain updates for non-Configs
89 to_update[k] = v
89 to_update[k] = v
90
90
91 self.update(to_update)
91 self.update(to_update)
92
92
93 def _is_section_key(self, key):
93 def _is_section_key(self, key):
94 if key[0].upper()==key[0] and not key.startswith('_'):
94 if key[0].upper()==key[0] and not key.startswith('_'):
95 return True
95 return True
96 else:
96 else:
97 return False
97 return False
98
98
99 def __contains__(self, key):
99 def __contains__(self, key):
100 if self._is_section_key(key):
100 if self._is_section_key(key):
101 return True
101 return True
102 else:
102 else:
103 return super(Config, self).__contains__(key)
103 return super(Config, self).__contains__(key)
104 # .has_key is deprecated for dictionaries.
104 # .has_key is deprecated for dictionaries.
105 has_key = __contains__
105 has_key = __contains__
106
106
107 def _has_section(self, key):
107 def _has_section(self, key):
108 if self._is_section_key(key):
108 if self._is_section_key(key):
109 if super(Config, self).__contains__(key):
109 if super(Config, self).__contains__(key):
110 return True
110 return True
111 return False
111 return False
112
112
113 def copy(self):
113 def copy(self):
114 return type(self)(dict.copy(self))
114 return type(self)(dict.copy(self))
115
115
116 def __copy__(self):
116 def __copy__(self):
117 return self.copy()
117 return self.copy()
118
118
119 def __deepcopy__(self, memo):
119 def __deepcopy__(self, memo):
120 import copy
120 import copy
121 return type(self)(copy.deepcopy(self.items()))
121 return type(self)(copy.deepcopy(self.items()))
122
122
123 def __getitem__(self, key):
123 def __getitem__(self, key):
124 # We cannot use directly self._is_section_key, because it triggers
124 # We cannot use directly self._is_section_key, because it triggers
125 # infinite recursion on top of PyPy. Instead, we manually fish the
125 # infinite recursion on top of PyPy. Instead, we manually fish the
126 # bound method.
126 # bound method.
127 is_section_key = self.__class__._is_section_key.__get__(self)
127 is_section_key = self.__class__._is_section_key.__get__(self)
128
128
129 # Because we use this for an exec namespace, we need to delegate
129 # Because we use this for an exec namespace, we need to delegate
130 # the lookup of names in __builtin__ to itself. This means
130 # the lookup of names in __builtin__ to itself. This means
131 # that you can't have section or attribute names that are
131 # that you can't have section or attribute names that are
132 # builtins.
132 # builtins.
133 try:
133 try:
134 return getattr(builtin_mod, key)
134 return getattr(builtin_mod, key)
135 except AttributeError:
135 except AttributeError:
136 pass
136 pass
137 if is_section_key(key):
137 if is_section_key(key):
138 try:
138 try:
139 return dict.__getitem__(self, key)
139 return dict.__getitem__(self, key)
140 except KeyError:
140 except KeyError:
141 c = Config()
141 c = Config()
142 dict.__setitem__(self, key, c)
142 dict.__setitem__(self, key, c)
143 return c
143 return c
144 else:
144 else:
145 return dict.__getitem__(self, key)
145 return dict.__getitem__(self, key)
146
146
147 def __setitem__(self, key, value):
147 def __setitem__(self, key, value):
148 # Don't allow names in __builtin__ to be modified.
148 # Don't allow names in __builtin__ to be modified.
149 if hasattr(builtin_mod, key):
149 if hasattr(builtin_mod, key):
150 raise ConfigError('Config variable names cannot have the same name '
150 raise ConfigError('Config variable names cannot have the same name '
151 'as a Python builtin: %s' % key)
151 'as a Python builtin: %s' % key)
152 if self._is_section_key(key):
152 if self._is_section_key(key):
153 if not isinstance(value, Config):
153 if not isinstance(value, Config):
154 raise ValueError('values whose keys begin with an uppercase '
154 raise ValueError('values whose keys begin with an uppercase '
155 'char must be Config instances: %r, %r' % (key, value))
155 'char must be Config instances: %r, %r' % (key, value))
156 else:
156 else:
157 dict.__setitem__(self, key, value)
157 dict.__setitem__(self, key, value)
158
158
159 def __getattr__(self, key):
159 def __getattr__(self, key):
160 try:
160 try:
161 return self.__getitem__(key)
161 return self.__getitem__(key)
162 except KeyError, e:
162 except KeyError, e:
163 raise AttributeError(e)
163 raise AttributeError(e)
164
164
165 def __setattr__(self, key, value):
165 def __setattr__(self, key, value):
166 try:
166 try:
167 self.__setitem__(key, value)
167 self.__setitem__(key, value)
168 except KeyError, e:
168 except KeyError, e:
169 raise AttributeError(e)
169 raise AttributeError(e)
170
170
171 def __delattr__(self, key):
171 def __delattr__(self, key):
172 try:
172 try:
173 dict.__delitem__(self, key)
173 dict.__delitem__(self, key)
174 except KeyError, e:
174 except KeyError, e:
175 raise AttributeError(e)
175 raise AttributeError(e)
176
176
177
177
178 #-----------------------------------------------------------------------------
178 #-----------------------------------------------------------------------------
179 # Config loading classes
179 # Config loading classes
180 #-----------------------------------------------------------------------------
180 #-----------------------------------------------------------------------------
181
181
182
182
183 class ConfigLoader(object):
183 class ConfigLoader(object):
184 """A object for loading configurations from just about anywhere.
184 """A object for loading configurations from just about anywhere.
185
185
186 The resulting configuration is packaged as a :class:`Struct`.
186 The resulting configuration is packaged as a :class:`Struct`.
187
187
188 Notes
188 Notes
189 -----
189 -----
190 A :class:`ConfigLoader` does one thing: load a config from a source
190 A :class:`ConfigLoader` does one thing: load a config from a source
191 (file, command line arguments) and returns the data as a :class:`Struct`.
191 (file, command line arguments) and returns the data as a :class:`Struct`.
192 There are lots of things that :class:`ConfigLoader` does not do. It does
192 There are lots of things that :class:`ConfigLoader` does not do. It does
193 not implement complex logic for finding config files. It does not handle
193 not implement complex logic for finding config files. It does not handle
194 default values or merge multiple configs. These things need to be
194 default values or merge multiple configs. These things need to be
195 handled elsewhere.
195 handled elsewhere.
196 """
196 """
197
197
198 def __init__(self):
198 def __init__(self):
199 """A base class for config loaders.
199 """A base class for config loaders.
200
200
201 Examples
201 Examples
202 --------
202 --------
203
203
204 >>> cl = ConfigLoader()
204 >>> cl = ConfigLoader()
205 >>> config = cl.load_config()
205 >>> config = cl.load_config()
206 >>> config
206 >>> config
207 {}
207 {}
208 """
208 """
209 self.clear()
209 self.clear()
210
210
211 def clear(self):
211 def clear(self):
212 self.config = Config()
212 self.config = Config()
213
213
214 def load_config(self):
214 def load_config(self):
215 """Load a config from somewhere, return a :class:`Config` instance.
215 """Load a config from somewhere, return a :class:`Config` instance.
216
216
217 Usually, this will cause self.config to be set and then returned.
217 Usually, this will cause self.config to be set and then returned.
218 However, in most cases, :meth:`ConfigLoader.clear` should be called
218 However, in most cases, :meth:`ConfigLoader.clear` should be called
219 to erase any previous state.
219 to erase any previous state.
220 """
220 """
221 self.clear()
221 self.clear()
222 return self.config
222 return self.config
223
223
224
224
225 class FileConfigLoader(ConfigLoader):
225 class FileConfigLoader(ConfigLoader):
226 """A base class for file based configurations.
226 """A base class for file based configurations.
227
227
228 As we add more file based config loaders, the common logic should go
228 As we add more file based config loaders, the common logic should go
229 here.
229 here.
230 """
230 """
231 pass
231 pass
232
232
233
233
234 class PyFileConfigLoader(FileConfigLoader):
234 class PyFileConfigLoader(FileConfigLoader):
235 """A config loader for pure python files.
235 """A config loader for pure python files.
236
236
237 This calls execfile on a plain python file and looks for attributes
237 This calls execfile on a plain python file and looks for attributes
238 that are all caps. These attribute are added to the config Struct.
238 that are all caps. These attribute are added to the config Struct.
239 """
239 """
240
240
241 def __init__(self, filename, path=None):
241 def __init__(self, filename, path=None):
242 """Build a config loader for a filename and path.
242 """Build a config loader for a filename and path.
243
243
244 Parameters
244 Parameters
245 ----------
245 ----------
246 filename : str
246 filename : str
247 The file name of the config file.
247 The file name of the config file.
248 path : str, list, tuple
248 path : str, list, tuple
249 The path to search for the config file on, or a sequence of
249 The path to search for the config file on, or a sequence of
250 paths to try in order.
250 paths to try in order.
251 """
251 """
252 super(PyFileConfigLoader, self).__init__()
252 super(PyFileConfigLoader, self).__init__()
253 self.filename = filename
253 self.filename = filename
254 self.path = path
254 self.path = path
255 self.full_filename = ''
255 self.full_filename = ''
256 self.data = None
256 self.data = None
257
257
258 def load_config(self):
258 def load_config(self):
259 """Load the config from a file and return it as a Struct."""
259 """Load the config from a file and return it as a Struct."""
260 self.clear()
260 self.clear()
261 self._find_file()
261 self._find_file()
262 self._read_file_as_dict()
262 self._read_file_as_dict()
263 self._convert_to_config()
263 self._convert_to_config()
264 return self.config
264 return self.config
265
265
266 def _find_file(self):
266 def _find_file(self):
267 """Try to find the file by searching the paths."""
267 """Try to find the file by searching the paths."""
268 self.full_filename = filefind(self.filename, self.path)
268 self.full_filename = filefind(self.filename, self.path)
269
269
270 def _read_file_as_dict(self):
270 def _read_file_as_dict(self):
271 """Load the config file into self.config, with recursive loading."""
271 """Load the config file into self.config, with recursive loading."""
272 # This closure is made available in the namespace that is used
272 # This closure is made available in the namespace that is used
273 # to exec the config file. It allows users to call
273 # to exec the config file. It allows users to call
274 # load_subconfig('myconfig.py') to load config files recursively.
274 # load_subconfig('myconfig.py') to load config files recursively.
275 # It needs to be a closure because it has references to self.path
275 # It needs to be a closure because it has references to self.path
276 # and self.config. The sub-config is loaded with the same path
276 # and self.config. The sub-config is loaded with the same path
277 # as the parent, but it uses an empty config which is then merged
277 # as the parent, but it uses an empty config which is then merged
278 # with the parents.
278 # with the parents.
279
279
280 # If a profile is specified, the config file will be loaded
280 # If a profile is specified, the config file will be loaded
281 # from that profile
281 # from that profile
282
282
283 def load_subconfig(fname, profile=None):
283 def load_subconfig(fname, profile=None):
284 # import here to prevent circular imports
284 # import here to prevent circular imports
285 from IPython.core.profiledir import ProfileDir, ProfileDirError
285 from IPython.core.profiledir import ProfileDir, ProfileDirError
286 if profile is not None:
286 if profile is not None:
287 try:
287 try:
288 profile_dir = ProfileDir.find_profile_dir_by_name(
288 profile_dir = ProfileDir.find_profile_dir_by_name(
289 get_ipython_dir(),
289 get_ipython_dir(),
290 profile,
290 profile,
291 )
291 )
292 except ProfileDirError:
292 except ProfileDirError:
293 return
293 return
294 path = profile_dir.location
294 path = profile_dir.location
295 else:
295 else:
296 path = self.path
296 path = self.path
297 loader = PyFileConfigLoader(fname, path)
297 loader = PyFileConfigLoader(fname, path)
298 try:
298 try:
299 sub_config = loader.load_config()
299 sub_config = loader.load_config()
300 except IOError:
300 except IOError:
301 # Pass silently if the sub config is not there. This happens
301 # Pass silently if the sub config is not there. This happens
302 # when a user s using a profile, but not the default config.
302 # when a user s using a profile, but not the default config.
303 pass
303 pass
304 else:
304 else:
305 self.config._merge(sub_config)
305 self.config._merge(sub_config)
306
306
307 # Again, this needs to be a closure and should be used in config
307 # Again, this needs to be a closure and should be used in config
308 # files to get the config being loaded.
308 # files to get the config being loaded.
309 def get_config():
309 def get_config():
310 return self.config
310 return self.config
311
311
312 namespace = dict(load_subconfig=load_subconfig, get_config=get_config)
312 namespace = dict(load_subconfig=load_subconfig, get_config=get_config)
313 fs_encoding = sys.getfilesystemencoding() or 'ascii'
313 fs_encoding = sys.getfilesystemencoding() or 'ascii'
314 conf_filename = self.full_filename.encode(fs_encoding)
314 conf_filename = self.full_filename.encode(fs_encoding)
315 py3compat.execfile(conf_filename, namespace)
315 py3compat.execfile(conf_filename, namespace)
316
316
317 def _convert_to_config(self):
317 def _convert_to_config(self):
318 if self.data is None:
318 if self.data is None:
319 ConfigLoaderError('self.data does not exist')
319 ConfigLoaderError('self.data does not exist')
320
320
321
321
322 class CommandLineConfigLoader(ConfigLoader):
322 class CommandLineConfigLoader(ConfigLoader):
323 """A config loader for command line arguments.
323 """A config loader for command line arguments.
324
324
325 As we add more command line based loaders, the common logic should go
325 As we add more command line based loaders, the common logic should go
326 here.
326 here.
327 """
327 """
328
328
329 def _exec_config_str(self, lhs, rhs):
329 def _exec_config_str(self, lhs, rhs):
330 exec_str = 'self.config.' + lhs + '=' + rhs
330 exec_str = 'self.config.' + lhs + '=' + rhs
331 try:
331 try:
332 # Try to see if regular Python syntax will work. This
332 # Try to see if regular Python syntax will work. This
333 # won't handle strings as the quote marks are removed
333 # won't handle strings as the quote marks are removed
334 # by the system shell.
334 # by the system shell.
335 exec exec_str in locals(), globals()
335 exec exec_str in locals(), globals()
336 except (NameError, SyntaxError):
336 except (NameError, SyntaxError):
337 # This case happens if the rhs is a string but without
337 # This case happens if the rhs is a string but without
338 # the quote marks. Use repr, to get quote marks, and
338 # the quote marks. Use repr, to get quote marks, and
339 # 'u' prefix and see if
339 # 'u' prefix and see if
340 # it succeeds. If it still fails, we let it raise.
340 # it succeeds. If it still fails, we let it raise.
341 exec_str = u'self.config.' + lhs + '=' + repr(rhs)
341 exec_str = u'self.config.' + lhs + '=' + repr(rhs)
342 exec exec_str in locals(), globals()
342 exec exec_str in locals(), globals()
343
343
344 def _load_flag(self, cfg):
344 def _load_flag(self, cfg):
345 """update self.config from a flag, which can be a dict or Config"""
345 """update self.config from a flag, which can be a dict or Config"""
346 if isinstance(cfg, (dict, Config)):
346 if isinstance(cfg, (dict, Config)):
347 # don't clobber whole config sections, update
347 # don't clobber whole config sections, update
348 # each section from config:
348 # each section from config:
349 for sec,c in cfg.iteritems():
349 for sec,c in cfg.iteritems():
350 self.config[sec].update(c)
350 self.config[sec].update(c)
351 else:
351 else:
352 raise ValueError("Invalid flag: '%s'"%raw)
352 raise ValueError("Invalid flag: '%s'"%raw)
353
353
354 # raw --identifier=value pattern
354 # raw --identifier=value pattern
355 # but *also* accept '-' as wordsep, for aliases
355 # but *also* accept '-' as wordsep, for aliases
356 # accepts: --foo=a
356 # accepts: --foo=a
357 # --Class.trait=value
357 # --Class.trait=value
358 # --alias-name=value
358 # --alias-name=value
359 # rejects: -foo=value
359 # rejects: -foo=value
360 # --foo
360 # --foo
361 # --Class.trait
361 # --Class.trait
362 kv_pattern = re.compile(r'\-\-[A-Za-z][\w\-]*(\.[\w\-]+)*\=.*')
362 kv_pattern = re.compile(r'\-\-[A-Za-z][\w\-]*(\.[\w\-]+)*\=.*')
363
363
364 # just flags, no assignments, with two *or one* leading '-'
364 # just flags, no assignments, with two *or one* leading '-'
365 # accepts: --foo
365 # accepts: --foo
366 # -foo-bar-again
366 # -foo-bar-again
367 # rejects: --anything=anything
367 # rejects: --anything=anything
368 # --two.word
368 # --two.word
369
369
370 flag_pattern = re.compile(r'\-\-?\w+[\-\w]*$')
370 flag_pattern = re.compile(r'\-\-?\w+[\-\w]*$')
371
371
372 class KeyValueConfigLoader(CommandLineConfigLoader):
372 class KeyValueConfigLoader(CommandLineConfigLoader):
373 """A config loader that loads key value pairs from the command line.
373 """A config loader that loads key value pairs from the command line.
374
374
375 This allows command line options to be gives in the following form::
375 This allows command line options to be gives in the following form::
376
376
377 ipython --profile="foo" --InteractiveShell.autocall=False
377 ipython --profile="foo" --InteractiveShell.autocall=False
378 """
378 """
379
379
380 def __init__(self, argv=None, aliases=None, flags=None):
380 def __init__(self, argv=None, aliases=None, flags=None):
381 """Create a key value pair config loader.
381 """Create a key value pair config loader.
382
382
383 Parameters
383 Parameters
384 ----------
384 ----------
385 argv : list
385 argv : list
386 A list that has the form of sys.argv[1:] which has unicode
386 A list that has the form of sys.argv[1:] which has unicode
387 elements of the form u"key=value". If this is None (default),
387 elements of the form u"key=value". If this is None (default),
388 then sys.argv[1:] will be used.
388 then sys.argv[1:] will be used.
389 aliases : dict
389 aliases : dict
390 A dict of aliases for configurable traits.
390 A dict of aliases for configurable traits.
391 Keys are the short aliases, Values are the resolved trait.
391 Keys are the short aliases, Values are the resolved trait.
392 Of the form: `{'alias' : 'Configurable.trait'}`
392 Of the form: `{'alias' : 'Configurable.trait'}`
393 flags : dict
393 flags : dict
394 A dict of flags, keyed by str name. Vaues can be Config objects,
394 A dict of flags, keyed by str name. Vaues can be Config objects,
395 dicts, or "key=value" strings. If Config or dict, when the flag
395 dicts, or "key=value" strings. If Config or dict, when the flag
396 is triggered, The flag is loaded as `self.config.update(m)`.
396 is triggered, The flag is loaded as `self.config.update(m)`.
397
397
398 Returns
398 Returns
399 -------
399 -------
400 config : Config
400 config : Config
401 The resulting Config object.
401 The resulting Config object.
402
402
403 Examples
403 Examples
404 --------
404 --------
405
405
406 >>> from IPython.config.loader import KeyValueConfigLoader
406 >>> from IPython.config.loader import KeyValueConfigLoader
407 >>> cl = KeyValueConfigLoader()
407 >>> cl = KeyValueConfigLoader()
408 >>> cl.load_config(["--A.name='brian'","--B.number=0"])
408 >>> cl.load_config(["--A.name='brian'","--B.number=0"])
409 {'A': {'name': 'brian'}, 'B': {'number': 0}}
409 {'A': {'name': 'brian'}, 'B': {'number': 0}}
410 """
410 """
411 self.clear()
411 self.clear()
412 if argv is None:
412 if argv is None:
413 argv = sys.argv[1:]
413 argv = sys.argv[1:]
414 self.argv = argv
414 self.argv = argv
415 self.aliases = aliases or {}
415 self.aliases = aliases or {}
416 self.flags = flags or {}
416 self.flags = flags or {}
417
417
418
418
419 def clear(self):
419 def clear(self):
420 super(KeyValueConfigLoader, self).clear()
420 super(KeyValueConfigLoader, self).clear()
421 self.extra_args = []
421 self.extra_args = []
422
422
423
423
424 def _decode_argv(self, argv, enc=None):
424 def _decode_argv(self, argv, enc=None):
425 """decode argv if bytes, using stin.encoding, falling back on default enc"""
425 """decode argv if bytes, using stin.encoding, falling back on default enc"""
426 uargv = []
426 uargv = []
427 if enc is None:
427 if enc is None:
428 enc = sys.stdin.encoding or sys.getdefaultencoding()
428 enc = text.getdefaultencoding()
429 for arg in argv:
429 for arg in argv:
430 if not isinstance(arg, unicode):
430 if not isinstance(arg, unicode):
431 # only decode if not already decoded
431 # only decode if not already decoded
432 arg = arg.decode(enc)
432 arg = arg.decode(enc)
433 uargv.append(arg)
433 uargv.append(arg)
434 return uargv
434 return uargv
435
435
436
436
437 def load_config(self, argv=None, aliases=None, flags=None):
437 def load_config(self, argv=None, aliases=None, flags=None):
438 """Parse the configuration and generate the Config object.
438 """Parse the configuration and generate the Config object.
439
439
440 After loading, any arguments that are not key-value or
440 After loading, any arguments that are not key-value or
441 flags will be stored in self.extra_args - a list of
441 flags will be stored in self.extra_args - a list of
442 unparsed command-line arguments. This is used for
442 unparsed command-line arguments. This is used for
443 arguments such as input files or subcommands.
443 arguments such as input files or subcommands.
444
444
445 Parameters
445 Parameters
446 ----------
446 ----------
447 argv : list, optional
447 argv : list, optional
448 A list that has the form of sys.argv[1:] which has unicode
448 A list that has the form of sys.argv[1:] which has unicode
449 elements of the form u"key=value". If this is None (default),
449 elements of the form u"key=value". If this is None (default),
450 then self.argv will be used.
450 then self.argv will be used.
451 aliases : dict
451 aliases : dict
452 A dict of aliases for configurable traits.
452 A dict of aliases for configurable traits.
453 Keys are the short aliases, Values are the resolved trait.
453 Keys are the short aliases, Values are the resolved trait.
454 Of the form: `{'alias' : 'Configurable.trait'}`
454 Of the form: `{'alias' : 'Configurable.trait'}`
455 flags : dict
455 flags : dict
456 A dict of flags, keyed by str name. Values can be Config objects
456 A dict of flags, keyed by str name. Values can be Config objects
457 or dicts. When the flag is triggered, The config is loaded as
457 or dicts. When the flag is triggered, The config is loaded as
458 `self.config.update(cfg)`.
458 `self.config.update(cfg)`.
459 """
459 """
460 from IPython.config.configurable import Configurable
460 from IPython.config.configurable import Configurable
461
461
462 self.clear()
462 self.clear()
463 if argv is None:
463 if argv is None:
464 argv = self.argv
464 argv = self.argv
465 if aliases is None:
465 if aliases is None:
466 aliases = self.aliases
466 aliases = self.aliases
467 if flags is None:
467 if flags is None:
468 flags = self.flags
468 flags = self.flags
469
469
470 # ensure argv is a list of unicode strings:
470 # ensure argv is a list of unicode strings:
471 uargv = self._decode_argv(argv)
471 uargv = self._decode_argv(argv)
472 for idx,raw in enumerate(uargv):
472 for idx,raw in enumerate(uargv):
473 # strip leading '-'
473 # strip leading '-'
474 item = raw.lstrip('-')
474 item = raw.lstrip('-')
475
475
476 if raw == '--':
476 if raw == '--':
477 # don't parse arguments after '--'
477 # don't parse arguments after '--'
478 # this is useful for relaying arguments to scripts, e.g.
478 # this is useful for relaying arguments to scripts, e.g.
479 # ipython -i foo.py --pylab=qt -- args after '--' go-to-foo.py
479 # ipython -i foo.py --pylab=qt -- args after '--' go-to-foo.py
480 self.extra_args.extend(uargv[idx+1:])
480 self.extra_args.extend(uargv[idx+1:])
481 break
481 break
482
482
483 if kv_pattern.match(raw):
483 if kv_pattern.match(raw):
484 lhs,rhs = item.split('=',1)
484 lhs,rhs = item.split('=',1)
485 # Substitute longnames for aliases.
485 # Substitute longnames for aliases.
486 if lhs in aliases:
486 if lhs in aliases:
487 lhs = aliases[lhs]
487 lhs = aliases[lhs]
488 if '.' not in lhs:
488 if '.' not in lhs:
489 # probably a mistyped alias, but not technically illegal
489 # probably a mistyped alias, but not technically illegal
490 warn.warn("Unrecognized alias: '%s', it will probably have no effect."%lhs)
490 warn.warn("Unrecognized alias: '%s', it will probably have no effect."%lhs)
491 self._exec_config_str(lhs, rhs)
491 self._exec_config_str(lhs, rhs)
492
492
493 elif flag_pattern.match(raw):
493 elif flag_pattern.match(raw):
494 if item in flags:
494 if item in flags:
495 cfg,help = flags[item]
495 cfg,help = flags[item]
496 self._load_flag(cfg)
496 self._load_flag(cfg)
497 else:
497 else:
498 raise ArgumentError("Unrecognized flag: '%s'"%raw)
498 raise ArgumentError("Unrecognized flag: '%s'"%raw)
499 elif raw.startswith('-'):
499 elif raw.startswith('-'):
500 kv = '--'+item
500 kv = '--'+item
501 if kv_pattern.match(kv):
501 if kv_pattern.match(kv):
502 raise ArgumentError("Invalid argument: '%s', did you mean '%s'?"%(raw, kv))
502 raise ArgumentError("Invalid argument: '%s', did you mean '%s'?"%(raw, kv))
503 else:
503 else:
504 raise ArgumentError("Invalid argument: '%s'"%raw)
504 raise ArgumentError("Invalid argument: '%s'"%raw)
505 else:
505 else:
506 # keep all args that aren't valid in a list,
506 # keep all args that aren't valid in a list,
507 # in case our parent knows what to do with them.
507 # in case our parent knows what to do with them.
508 self.extra_args.append(item)
508 self.extra_args.append(item)
509 return self.config
509 return self.config
510
510
511 class ArgParseConfigLoader(CommandLineConfigLoader):
511 class ArgParseConfigLoader(CommandLineConfigLoader):
512 """A loader that uses the argparse module to load from the command line."""
512 """A loader that uses the argparse module to load from the command line."""
513
513
514 def __init__(self, argv=None, aliases=None, flags=None, *parser_args, **parser_kw):
514 def __init__(self, argv=None, aliases=None, flags=None, *parser_args, **parser_kw):
515 """Create a config loader for use with argparse.
515 """Create a config loader for use with argparse.
516
516
517 Parameters
517 Parameters
518 ----------
518 ----------
519
519
520 argv : optional, list
520 argv : optional, list
521 If given, used to read command-line arguments from, otherwise
521 If given, used to read command-line arguments from, otherwise
522 sys.argv[1:] is used.
522 sys.argv[1:] is used.
523
523
524 parser_args : tuple
524 parser_args : tuple
525 A tuple of positional arguments that will be passed to the
525 A tuple of positional arguments that will be passed to the
526 constructor of :class:`argparse.ArgumentParser`.
526 constructor of :class:`argparse.ArgumentParser`.
527
527
528 parser_kw : dict
528 parser_kw : dict
529 A tuple of keyword arguments that will be passed to the
529 A tuple of keyword arguments that will be passed to the
530 constructor of :class:`argparse.ArgumentParser`.
530 constructor of :class:`argparse.ArgumentParser`.
531
531
532 Returns
532 Returns
533 -------
533 -------
534 config : Config
534 config : Config
535 The resulting Config object.
535 The resulting Config object.
536 """
536 """
537 super(CommandLineConfigLoader, self).__init__()
537 super(CommandLineConfigLoader, self).__init__()
538 self.clear()
538 self.clear()
539 if argv is None:
539 if argv is None:
540 argv = sys.argv[1:]
540 argv = sys.argv[1:]
541 self.argv = argv
541 self.argv = argv
542 self.aliases = aliases or {}
542 self.aliases = aliases or {}
543 self.flags = flags or {}
543 self.flags = flags or {}
544
544
545 self.parser_args = parser_args
545 self.parser_args = parser_args
546 self.version = parser_kw.pop("version", None)
546 self.version = parser_kw.pop("version", None)
547 kwargs = dict(argument_default=argparse.SUPPRESS)
547 kwargs = dict(argument_default=argparse.SUPPRESS)
548 kwargs.update(parser_kw)
548 kwargs.update(parser_kw)
549 self.parser_kw = kwargs
549 self.parser_kw = kwargs
550
550
551 def load_config(self, argv=None, aliases=None, flags=None):
551 def load_config(self, argv=None, aliases=None, flags=None):
552 """Parse command line arguments and return as a Config object.
552 """Parse command line arguments and return as a Config object.
553
553
554 Parameters
554 Parameters
555 ----------
555 ----------
556
556
557 args : optional, list
557 args : optional, list
558 If given, a list with the structure of sys.argv[1:] to parse
558 If given, a list with the structure of sys.argv[1:] to parse
559 arguments from. If not given, the instance's self.argv attribute
559 arguments from. If not given, the instance's self.argv attribute
560 (given at construction time) is used."""
560 (given at construction time) is used."""
561 self.clear()
561 self.clear()
562 if argv is None:
562 if argv is None:
563 argv = self.argv
563 argv = self.argv
564 if aliases is None:
564 if aliases is None:
565 aliases = self.aliases
565 aliases = self.aliases
566 if flags is None:
566 if flags is None:
567 flags = self.flags
567 flags = self.flags
568 self._create_parser(aliases, flags)
568 self._create_parser(aliases, flags)
569 self._parse_args(argv)
569 self._parse_args(argv)
570 self._convert_to_config()
570 self._convert_to_config()
571 return self.config
571 return self.config
572
572
573 def get_extra_args(self):
573 def get_extra_args(self):
574 if hasattr(self, 'extra_args'):
574 if hasattr(self, 'extra_args'):
575 return self.extra_args
575 return self.extra_args
576 else:
576 else:
577 return []
577 return []
578
578
579 def _create_parser(self, aliases=None, flags=None):
579 def _create_parser(self, aliases=None, flags=None):
580 self.parser = ArgumentParser(*self.parser_args, **self.parser_kw)
580 self.parser = ArgumentParser(*self.parser_args, **self.parser_kw)
581 self._add_arguments(aliases, flags)
581 self._add_arguments(aliases, flags)
582
582
583 def _add_arguments(self, aliases=None, flags=None):
583 def _add_arguments(self, aliases=None, flags=None):
584 raise NotImplementedError("subclasses must implement _add_arguments")
584 raise NotImplementedError("subclasses must implement _add_arguments")
585
585
586 def _parse_args(self, args):
586 def _parse_args(self, args):
587 """self.parser->self.parsed_data"""
587 """self.parser->self.parsed_data"""
588 # decode sys.argv to support unicode command-line options
588 # decode sys.argv to support unicode command-line options
589 uargs = [py3compat.cast_unicode(a) for a in args]
589 enc = text.getdefaultencoding()
590 uargs = [py3compat.cast_unicode(a, enc) for a in args]
590 self.parsed_data, self.extra_args = self.parser.parse_known_args(uargs)
591 self.parsed_data, self.extra_args = self.parser.parse_known_args(uargs)
591
592
592 def _convert_to_config(self):
593 def _convert_to_config(self):
593 """self.parsed_data->self.config"""
594 """self.parsed_data->self.config"""
594 for k, v in vars(self.parsed_data).iteritems():
595 for k, v in vars(self.parsed_data).iteritems():
595 exec "self.config.%s = v"%k in locals(), globals()
596 exec "self.config.%s = v"%k in locals(), globals()
596
597
597 class KVArgParseConfigLoader(ArgParseConfigLoader):
598 class KVArgParseConfigLoader(ArgParseConfigLoader):
598 """A config loader that loads aliases and flags with argparse,
599 """A config loader that loads aliases and flags with argparse,
599 but will use KVLoader for the rest. This allows better parsing
600 but will use KVLoader for the rest. This allows better parsing
600 of common args, such as `ipython -c 'print 5'`, but still gets
601 of common args, such as `ipython -c 'print 5'`, but still gets
601 arbitrary config with `ipython --InteractiveShell.use_readline=False`"""
602 arbitrary config with `ipython --InteractiveShell.use_readline=False`"""
602
603
603 def _convert_to_config(self):
604 def _convert_to_config(self):
604 """self.parsed_data->self.config"""
605 """self.parsed_data->self.config"""
605 for k, v in vars(self.parsed_data).iteritems():
606 for k, v in vars(self.parsed_data).iteritems():
606 self._exec_config_str(k, v)
607 self._exec_config_str(k, v)
607
608
608 def _add_arguments(self, aliases=None, flags=None):
609 def _add_arguments(self, aliases=None, flags=None):
609 self.alias_flags = {}
610 self.alias_flags = {}
610 # print aliases, flags
611 # print aliases, flags
611 if aliases is None:
612 if aliases is None:
612 aliases = self.aliases
613 aliases = self.aliases
613 if flags is None:
614 if flags is None:
614 flags = self.flags
615 flags = self.flags
615 paa = self.parser.add_argument
616 paa = self.parser.add_argument
616 for key,value in aliases.iteritems():
617 for key,value in aliases.iteritems():
617 if key in flags:
618 if key in flags:
618 # flags
619 # flags
619 nargs = '?'
620 nargs = '?'
620 else:
621 else:
621 nargs = None
622 nargs = None
622 if len(key) is 1:
623 if len(key) is 1:
623 paa('-'+key, '--'+key, type=str, dest=value, nargs=nargs)
624 paa('-'+key, '--'+key, type=str, dest=value, nargs=nargs)
624 else:
625 else:
625 paa('--'+key, type=str, dest=value, nargs=nargs)
626 paa('--'+key, type=str, dest=value, nargs=nargs)
626 for key, (value, help) in flags.iteritems():
627 for key, (value, help) in flags.iteritems():
627 if key in self.aliases:
628 if key in self.aliases:
628 #
629 #
629 self.alias_flags[self.aliases[key]] = value
630 self.alias_flags[self.aliases[key]] = value
630 continue
631 continue
631 if len(key) is 1:
632 if len(key) is 1:
632 paa('-'+key, '--'+key, action='append_const', dest='_flags', const=value)
633 paa('-'+key, '--'+key, action='append_const', dest='_flags', const=value)
633 else:
634 else:
634 paa('--'+key, action='append_const', dest='_flags', const=value)
635 paa('--'+key, action='append_const', dest='_flags', const=value)
635
636
636 def _convert_to_config(self):
637 def _convert_to_config(self):
637 """self.parsed_data->self.config, parse unrecognized extra args via KVLoader."""
638 """self.parsed_data->self.config, parse unrecognized extra args via KVLoader."""
638 # remove subconfigs list from namespace before transforming the Namespace
639 # remove subconfigs list from namespace before transforming the Namespace
639 if '_flags' in self.parsed_data:
640 if '_flags' in self.parsed_data:
640 subcs = self.parsed_data._flags
641 subcs = self.parsed_data._flags
641 del self.parsed_data._flags
642 del self.parsed_data._flags
642 else:
643 else:
643 subcs = []
644 subcs = []
644
645
645 for k, v in vars(self.parsed_data).iteritems():
646 for k, v in vars(self.parsed_data).iteritems():
646 if v is None:
647 if v is None:
647 # it was a flag that shares the name of an alias
648 # it was a flag that shares the name of an alias
648 subcs.append(self.alias_flags[k])
649 subcs.append(self.alias_flags[k])
649 else:
650 else:
650 # eval the KV assignment
651 # eval the KV assignment
651 self._exec_config_str(k, v)
652 self._exec_config_str(k, v)
652
653
653 for subc in subcs:
654 for subc in subcs:
654 self._load_flag(subc)
655 self._load_flag(subc)
655
656
656 if self.extra_args:
657 if self.extra_args:
657 sub_parser = KeyValueConfigLoader()
658 sub_parser = KeyValueConfigLoader()
658 sub_parser.load_config(self.extra_args)
659 sub_parser.load_config(self.extra_args)
659 self.config._merge(sub_parser.config)
660 self.config._merge(sub_parser.config)
660 self.extra_args = sub_parser.extra_args
661 self.extra_args = sub_parser.extra_args
@@ -1,147 +1,148 b''
1 """Windows-specific implementation of process utilities.
1 """Windows-specific implementation of process utilities.
2
2
3 This file is only meant to be imported by process.py, not by end-users.
3 This file is only meant to be imported by process.py, not by end-users.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2010 The IPython Development Team
7 # Copyright (C) 2010 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 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # stdlib
18 # stdlib
19 import os
19 import os
20 import sys
20 import sys
21
21
22 from subprocess import STDOUT
22 from subprocess import STDOUT
23
23
24 # our own imports
24 # our own imports
25 from ._process_common import read_no_interrupt, process_handler
25 from ._process_common import read_no_interrupt, process_handler
26 from . import text
26
27
27 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
28 # Function definitions
29 # Function definitions
29 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
30
31
31 class AvoidUNCPath(object):
32 class AvoidUNCPath(object):
32 """A context manager to protect command execution from UNC paths.
33 """A context manager to protect command execution from UNC paths.
33
34
34 In the Win32 API, commands can't be invoked with the cwd being a UNC path.
35 In the Win32 API, commands can't be invoked with the cwd being a UNC path.
35 This context manager temporarily changes directory to the 'C:' drive on
36 This context manager temporarily changes directory to the 'C:' drive on
36 entering, and restores the original working directory on exit.
37 entering, and restores the original working directory on exit.
37
38
38 The context manager returns the starting working directory *if* it made a
39 The context manager returns the starting working directory *if* it made a
39 change and None otherwise, so that users can apply the necessary adjustment
40 change and None otherwise, so that users can apply the necessary adjustment
40 to their system calls in the event of a change.
41 to their system calls in the event of a change.
41
42
42 Example
43 Example
43 -------
44 -------
44 ::
45 ::
45 cmd = 'dir'
46 cmd = 'dir'
46 with AvoidUNCPath() as path:
47 with AvoidUNCPath() as path:
47 if path is not None:
48 if path is not None:
48 cmd = '"pushd %s &&"%s' % (path, cmd)
49 cmd = '"pushd %s &&"%s' % (path, cmd)
49 os.system(cmd)
50 os.system(cmd)
50 """
51 """
51 def __enter__(self):
52 def __enter__(self):
52 self.path = os.getcwdu()
53 self.path = os.getcwdu()
53 self.is_unc_path = self.path.startswith(r"\\")
54 self.is_unc_path = self.path.startswith(r"\\")
54 if self.is_unc_path:
55 if self.is_unc_path:
55 # change to c drive (as cmd.exe cannot handle UNC addresses)
56 # change to c drive (as cmd.exe cannot handle UNC addresses)
56 os.chdir("C:")
57 os.chdir("C:")
57 return self.path
58 return self.path
58 else:
59 else:
59 # We return None to signal that there was no change in the working
60 # We return None to signal that there was no change in the working
60 # directory
61 # directory
61 return None
62 return None
62
63
63 def __exit__(self, exc_type, exc_value, traceback):
64 def __exit__(self, exc_type, exc_value, traceback):
64 if self.is_unc_path:
65 if self.is_unc_path:
65 os.chdir(self.path)
66 os.chdir(self.path)
66
67
67
68
68 def _find_cmd(cmd):
69 def _find_cmd(cmd):
69 """Find the full path to a .bat or .exe using the win32api module."""
70 """Find the full path to a .bat or .exe using the win32api module."""
70 try:
71 try:
71 from win32api import SearchPath
72 from win32api import SearchPath
72 except ImportError:
73 except ImportError:
73 raise ImportError('you need to have pywin32 installed for this to work')
74 raise ImportError('you need to have pywin32 installed for this to work')
74 else:
75 else:
75 PATH = os.environ['PATH']
76 PATH = os.environ['PATH']
76 extensions = ['.exe', '.com', '.bat', '.py']
77 extensions = ['.exe', '.com', '.bat', '.py']
77 path = None
78 path = None
78 for ext in extensions:
79 for ext in extensions:
79 try:
80 try:
80 path = SearchPath(PATH, cmd + ext)[0]
81 path = SearchPath(PATH, cmd + ext)[0]
81 except:
82 except:
82 pass
83 pass
83 if path is None:
84 if path is None:
84 raise OSError("command %r not found" % cmd)
85 raise OSError("command %r not found" % cmd)
85 else:
86 else:
86 return path
87 return path
87
88
88
89
89 def _system_body(p):
90 def _system_body(p):
90 """Callback for _system."""
91 """Callback for _system."""
91 enc = sys.stdin.encoding or sys.getdefaultencoding()
92 enc = text.getdefaultencoding()
92 for line in read_no_interrupt(p.stdout).splitlines():
93 for line in read_no_interrupt(p.stdout).splitlines():
93 line = line.decode(enc, 'replace')
94 line = line.decode(enc, 'replace')
94 print(line, file=sys.stdout)
95 print(line, file=sys.stdout)
95 for line in read_no_interrupt(p.stderr).splitlines():
96 for line in read_no_interrupt(p.stderr).splitlines():
96 line = line.decode(enc, 'replace')
97 line = line.decode(enc, 'replace')
97 print(line, file=sys.stderr)
98 print(line, file=sys.stderr)
98
99
99 # Wait to finish for returncode
100 # Wait to finish for returncode
100 return p.wait()
101 return p.wait()
101
102
102
103
103 def system(cmd):
104 def system(cmd):
104 """Win32 version of os.system() that works with network shares.
105 """Win32 version of os.system() that works with network shares.
105
106
106 Note that this implementation returns None, as meant for use in IPython.
107 Note that this implementation returns None, as meant for use in IPython.
107
108
108 Parameters
109 Parameters
109 ----------
110 ----------
110 cmd : str
111 cmd : str
111 A command to be executed in the system shell.
112 A command to be executed in the system shell.
112
113
113 Returns
114 Returns
114 -------
115 -------
115 None : we explicitly do NOT return the subprocess status code, as this
116 None : we explicitly do NOT return the subprocess status code, as this
116 utility is meant to be used extensively in IPython, where any return value
117 utility is meant to be used extensively in IPython, where any return value
117 would trigger :func:`sys.displayhook` calls.
118 would trigger :func:`sys.displayhook` calls.
118 """
119 """
119 with AvoidUNCPath() as path:
120 with AvoidUNCPath() as path:
120 if path is not None:
121 if path is not None:
121 cmd = '"pushd %s &&"%s' % (path, cmd)
122 cmd = '"pushd %s &&"%s' % (path, cmd)
122 return process_handler(cmd, _system_body)
123 return process_handler(cmd, _system_body)
123
124
124
125
125 def getoutput(cmd):
126 def getoutput(cmd):
126 """Return standard output of executing cmd in a shell.
127 """Return standard output of executing cmd in a shell.
127
128
128 Accepts the same arguments as os.system().
129 Accepts the same arguments as os.system().
129
130
130 Parameters
131 Parameters
131 ----------
132 ----------
132 cmd : str
133 cmd : str
133 A command to be executed in the system shell.
134 A command to be executed in the system shell.
134
135
135 Returns
136 Returns
136 -------
137 -------
137 stdout : str
138 stdout : str
138 """
139 """
139
140
140 with AvoidUNCPath() as path:
141 with AvoidUNCPath() as path:
141 if path is not None:
142 if path is not None:
142 cmd = '"pushd %s &&"%s' % (path, cmd)
143 cmd = '"pushd %s &&"%s' % (path, cmd)
143 out = process_handler(cmd, lambda p: p.communicate()[0], STDOUT)
144 out = process_handler(cmd, lambda p: p.communicate()[0], STDOUT)
144
145
145 if out is None:
146 if out is None:
146 out = ''
147 out = ''
147 return out
148 return out
@@ -1,164 +1,165 b''
1 """Utilities to manipulate JSON objects.
1 """Utilities to manipulate JSON objects.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2010 The IPython Development Team
4 # Copyright (C) 2010 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING.txt, distributed as part of this software.
7 # the file COPYING.txt, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # stdlib
13 # stdlib
14 import re
14 import re
15 import sys
15 import sys
16 import types
16 import types
17 from datetime import datetime
17 from datetime import datetime
18
18
19 from IPython.utils import py3compat
19 from IPython.utils import py3compat
20 from IPython.utils import text
20 next_attr_name = '__next__' if py3compat.PY3 else 'next'
21 next_attr_name = '__next__' if py3compat.PY3 else 'next'
21
22
22 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
23 # Globals and constants
24 # Globals and constants
24 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
25
26
26 # timestamp formats
27 # timestamp formats
27 ISO8601="%Y-%m-%dT%H:%M:%S.%f"
28 ISO8601="%Y-%m-%dT%H:%M:%S.%f"
28 ISO8601_PAT=re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+$")
29 ISO8601_PAT=re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+$")
29
30
30 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
31 # Classes and functions
32 # Classes and functions
32 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
33
34
34 def rekey(dikt):
35 def rekey(dikt):
35 """Rekey a dict that has been forced to use str keys where there should be
36 """Rekey a dict that has been forced to use str keys where there should be
36 ints by json."""
37 ints by json."""
37 for k in dikt.iterkeys():
38 for k in dikt.iterkeys():
38 if isinstance(k, basestring):
39 if isinstance(k, basestring):
39 ik=fk=None
40 ik=fk=None
40 try:
41 try:
41 ik = int(k)
42 ik = int(k)
42 except ValueError:
43 except ValueError:
43 try:
44 try:
44 fk = float(k)
45 fk = float(k)
45 except ValueError:
46 except ValueError:
46 continue
47 continue
47 if ik is not None:
48 if ik is not None:
48 nk = ik
49 nk = ik
49 else:
50 else:
50 nk = fk
51 nk = fk
51 if nk in dikt:
52 if nk in dikt:
52 raise KeyError("already have key %r"%nk)
53 raise KeyError("already have key %r"%nk)
53 dikt[nk] = dikt.pop(k)
54 dikt[nk] = dikt.pop(k)
54 return dikt
55 return dikt
55
56
56
57
57 def extract_dates(obj):
58 def extract_dates(obj):
58 """extract ISO8601 dates from unpacked JSON"""
59 """extract ISO8601 dates from unpacked JSON"""
59 if isinstance(obj, dict):
60 if isinstance(obj, dict):
60 obj = dict(obj) # don't clobber
61 obj = dict(obj) # don't clobber
61 for k,v in obj.iteritems():
62 for k,v in obj.iteritems():
62 obj[k] = extract_dates(v)
63 obj[k] = extract_dates(v)
63 elif isinstance(obj, (list, tuple)):
64 elif isinstance(obj, (list, tuple)):
64 obj = [ extract_dates(o) for o in obj ]
65 obj = [ extract_dates(o) for o in obj ]
65 elif isinstance(obj, basestring):
66 elif isinstance(obj, basestring):
66 if ISO8601_PAT.match(obj):
67 if ISO8601_PAT.match(obj):
67 obj = datetime.strptime(obj, ISO8601)
68 obj = datetime.strptime(obj, ISO8601)
68 return obj
69 return obj
69
70
70 def squash_dates(obj):
71 def squash_dates(obj):
71 """squash datetime objects into ISO8601 strings"""
72 """squash datetime objects into ISO8601 strings"""
72 if isinstance(obj, dict):
73 if isinstance(obj, dict):
73 obj = dict(obj) # don't clobber
74 obj = dict(obj) # don't clobber
74 for k,v in obj.iteritems():
75 for k,v in obj.iteritems():
75 obj[k] = squash_dates(v)
76 obj[k] = squash_dates(v)
76 elif isinstance(obj, (list, tuple)):
77 elif isinstance(obj, (list, tuple)):
77 obj = [ squash_dates(o) for o in obj ]
78 obj = [ squash_dates(o) for o in obj ]
78 elif isinstance(obj, datetime):
79 elif isinstance(obj, datetime):
79 obj = obj.strftime(ISO8601)
80 obj = obj.strftime(ISO8601)
80 return obj
81 return obj
81
82
82 def date_default(obj):
83 def date_default(obj):
83 """default function for packing datetime objects in JSON."""
84 """default function for packing datetime objects in JSON."""
84 if isinstance(obj, datetime):
85 if isinstance(obj, datetime):
85 return obj.strftime(ISO8601)
86 return obj.strftime(ISO8601)
86 else:
87 else:
87 raise TypeError("%r is not JSON serializable"%obj)
88 raise TypeError("%r is not JSON serializable"%obj)
88
89
89
90
90
91
91 def json_clean(obj):
92 def json_clean(obj):
92 """Clean an object to ensure it's safe to encode in JSON.
93 """Clean an object to ensure it's safe to encode in JSON.
93
94
94 Atomic, immutable objects are returned unmodified. Sets and tuples are
95 Atomic, immutable objects are returned unmodified. Sets and tuples are
95 converted to lists, lists are copied and dicts are also copied.
96 converted to lists, lists are copied and dicts are also copied.
96
97
97 Note: dicts whose keys could cause collisions upon encoding (such as a dict
98 Note: dicts whose keys could cause collisions upon encoding (such as a dict
98 with both the number 1 and the string '1' as keys) will cause a ValueError
99 with both the number 1 and the string '1' as keys) will cause a ValueError
99 to be raised.
100 to be raised.
100
101
101 Parameters
102 Parameters
102 ----------
103 ----------
103 obj : any python object
104 obj : any python object
104
105
105 Returns
106 Returns
106 -------
107 -------
107 out : object
108 out : object
108
109
109 A version of the input which will not cause an encoding error when
110 A version of the input which will not cause an encoding error when
110 encoded as JSON. Note that this function does not *encode* its inputs,
111 encoded as JSON. Note that this function does not *encode* its inputs,
111 it simply sanitizes it so that there will be no encoding errors later.
112 it simply sanitizes it so that there will be no encoding errors later.
112
113
113 Examples
114 Examples
114 --------
115 --------
115 >>> json_clean(4)
116 >>> json_clean(4)
116 4
117 4
117 >>> json_clean(range(10))
118 >>> json_clean(range(10))
118 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
119 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
119 >>> json_clean(dict(x=1, y=2))
120 >>> json_clean(dict(x=1, y=2))
120 {'y': 2, 'x': 1}
121 {'y': 2, 'x': 1}
121 >>> json_clean(dict(x=1, y=2, z=[1,2,3]))
122 >>> json_clean(dict(x=1, y=2, z=[1,2,3]))
122 {'y': 2, 'x': 1, 'z': [1, 2, 3]}
123 {'y': 2, 'x': 1, 'z': [1, 2, 3]}
123 >>> json_clean(True)
124 >>> json_clean(True)
124 True
125 True
125 """
126 """
126 # types that are 'atomic' and ok in json as-is. bool doesn't need to be
127 # types that are 'atomic' and ok in json as-is. bool doesn't need to be
127 # listed explicitly because bools pass as int instances
128 # listed explicitly because bools pass as int instances
128 atomic_ok = (unicode, int, float, types.NoneType)
129 atomic_ok = (unicode, int, float, types.NoneType)
129
130
130 # containers that we need to convert into lists
131 # containers that we need to convert into lists
131 container_to_list = (tuple, set, types.GeneratorType)
132 container_to_list = (tuple, set, types.GeneratorType)
132
133
133 if isinstance(obj, atomic_ok):
134 if isinstance(obj, atomic_ok):
134 return obj
135 return obj
135
136
136 if isinstance(obj, bytes):
137 if isinstance(obj, bytes):
137 return obj.decode(sys.getdefaultencoding(), 'replace')
138 return obj.decode(text.getdefaultencoding(), 'replace')
138
139
139 if isinstance(obj, container_to_list) or (
140 if isinstance(obj, container_to_list) or (
140 hasattr(obj, '__iter__') and hasattr(obj, next_attr_name)):
141 hasattr(obj, '__iter__') and hasattr(obj, next_attr_name)):
141 obj = list(obj)
142 obj = list(obj)
142
143
143 if isinstance(obj, list):
144 if isinstance(obj, list):
144 return [json_clean(x) for x in obj]
145 return [json_clean(x) for x in obj]
145
146
146 if isinstance(obj, dict):
147 if isinstance(obj, dict):
147 # First, validate that the dict won't lose data in conversion due to
148 # First, validate that the dict won't lose data in conversion due to
148 # key collisions after stringification. This can happen with keys like
149 # key collisions after stringification. This can happen with keys like
149 # True and 'true' or 1 and '1', which collide in JSON.
150 # True and 'true' or 1 and '1', which collide in JSON.
150 nkeys = len(obj)
151 nkeys = len(obj)
151 nkeys_collapsed = len(set(map(str, obj)))
152 nkeys_collapsed = len(set(map(str, obj)))
152 if nkeys != nkeys_collapsed:
153 if nkeys != nkeys_collapsed:
153 raise ValueError('dict can not be safely converted to JSON: '
154 raise ValueError('dict can not be safely converted to JSON: '
154 'key collision would lead to dropped values')
155 'key collision would lead to dropped values')
155 # If all OK, proceed by making the new dict that will be json-safe
156 # If all OK, proceed by making the new dict that will be json-safe
156 out = {}
157 out = {}
157 for k,v in obj.iteritems():
158 for k,v in obj.iteritems():
158 out[str(k)] = json_clean(v)
159 out[str(k)] = json_clean(v)
159 return out
160 return out
160
161
161 # If we get here, we don't know how to handle the object, so we just get
162 # If we get here, we don't know how to handle the object, so we just get
162 # its repr and return that. This will catch lambdas, open sockets, class
163 # its repr and return that. This will catch lambdas, open sockets, class
163 # objects, and any other complicated contraption that json can't encode
164 # objects, and any other complicated contraption that json can't encode
164 return repr(obj)
165 return repr(obj)
@@ -1,715 +1,739 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for working with strings and text.
3 Utilities for working with strings and text.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2009 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 import __main__
17 import __main__
18
18
19 import locale
19 import os
20 import os
20 import re
21 import re
21 import shutil
22 import shutil
23 import sys
22 import textwrap
24 import textwrap
23 from string import Formatter
25 from string import Formatter
24
26
25 from IPython.external.path import path
27 from IPython.external.path import path
26 from IPython.utils import py3compat
28 from IPython.utils import py3compat
27 from IPython.utils.io import nlprint
29 from IPython.utils.io import nlprint
28 from IPython.utils.data import flatten
30 from IPython.utils.data import flatten
29
31
30 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
31 # Code
33 # Code
32 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
33
35
36 # Less conservative replacement for sys.getdefaultencoding, that will try
37 # to match the environment.
38 # Defined here as central function, so if we find better choices, we
39 # won't need to make changes all over IPython.
40 def getdefaultencoding():
41 """Return IPython's guess for the default encoding for bytes as text.
42
43 Asks for stdin.encoding first, to match the calling Terminal, but that
44 is often None for subprocesses. Fall back on locale.getpreferredencoding()
45 which should be a sensible platform default (that respects LANG environment),
46 and finally to sys.getdefaultencoding() which is the most conservative option,
47 and usually ASCII.
48 """
49 enc = sys.stdin.encoding
50 if not enc:
51 try:
52 # There are reports of getpreferredencoding raising errors
53 # in some cases, which may well be fixed, but let's be conservative here.
54 enc = locale.getpreferredencoding(False)
55 except Exception:
56 pass
57 return enc or sys.getdefaultencoding()
34
58
35 def unquote_ends(istr):
59 def unquote_ends(istr):
36 """Remove a single pair of quotes from the endpoints of a string."""
60 """Remove a single pair of quotes from the endpoints of a string."""
37
61
38 if not istr:
62 if not istr:
39 return istr
63 return istr
40 if (istr[0]=="'" and istr[-1]=="'") or \
64 if (istr[0]=="'" and istr[-1]=="'") or \
41 (istr[0]=='"' and istr[-1]=='"'):
65 (istr[0]=='"' and istr[-1]=='"'):
42 return istr[1:-1]
66 return istr[1:-1]
43 else:
67 else:
44 return istr
68 return istr
45
69
46
70
47 class LSString(str):
71 class LSString(str):
48 """String derivative with a special access attributes.
72 """String derivative with a special access attributes.
49
73
50 These are normal strings, but with the special attributes:
74 These are normal strings, but with the special attributes:
51
75
52 .l (or .list) : value as list (split on newlines).
76 .l (or .list) : value as list (split on newlines).
53 .n (or .nlstr): original value (the string itself).
77 .n (or .nlstr): original value (the string itself).
54 .s (or .spstr): value as whitespace-separated string.
78 .s (or .spstr): value as whitespace-separated string.
55 .p (or .paths): list of path objects
79 .p (or .paths): list of path objects
56
80
57 Any values which require transformations are computed only once and
81 Any values which require transformations are computed only once and
58 cached.
82 cached.
59
83
60 Such strings are very useful to efficiently interact with the shell, which
84 Such strings are very useful to efficiently interact with the shell, which
61 typically only understands whitespace-separated options for commands."""
85 typically only understands whitespace-separated options for commands."""
62
86
63 def get_list(self):
87 def get_list(self):
64 try:
88 try:
65 return self.__list
89 return self.__list
66 except AttributeError:
90 except AttributeError:
67 self.__list = self.split('\n')
91 self.__list = self.split('\n')
68 return self.__list
92 return self.__list
69
93
70 l = list = property(get_list)
94 l = list = property(get_list)
71
95
72 def get_spstr(self):
96 def get_spstr(self):
73 try:
97 try:
74 return self.__spstr
98 return self.__spstr
75 except AttributeError:
99 except AttributeError:
76 self.__spstr = self.replace('\n',' ')
100 self.__spstr = self.replace('\n',' ')
77 return self.__spstr
101 return self.__spstr
78
102
79 s = spstr = property(get_spstr)
103 s = spstr = property(get_spstr)
80
104
81 def get_nlstr(self):
105 def get_nlstr(self):
82 return self
106 return self
83
107
84 n = nlstr = property(get_nlstr)
108 n = nlstr = property(get_nlstr)
85
109
86 def get_paths(self):
110 def get_paths(self):
87 try:
111 try:
88 return self.__paths
112 return self.__paths
89 except AttributeError:
113 except AttributeError:
90 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
114 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
91 return self.__paths
115 return self.__paths
92
116
93 p = paths = property(get_paths)
117 p = paths = property(get_paths)
94
118
95 # FIXME: We need to reimplement type specific displayhook and then add this
119 # FIXME: We need to reimplement type specific displayhook and then add this
96 # back as a custom printer. This should also be moved outside utils into the
120 # back as a custom printer. This should also be moved outside utils into the
97 # core.
121 # core.
98
122
99 # def print_lsstring(arg):
123 # def print_lsstring(arg):
100 # """ Prettier (non-repr-like) and more informative printer for LSString """
124 # """ Prettier (non-repr-like) and more informative printer for LSString """
101 # print "LSString (.p, .n, .l, .s available). Value:"
125 # print "LSString (.p, .n, .l, .s available). Value:"
102 # print arg
126 # print arg
103 #
127 #
104 #
128 #
105 # print_lsstring = result_display.when_type(LSString)(print_lsstring)
129 # print_lsstring = result_display.when_type(LSString)(print_lsstring)
106
130
107
131
108 class SList(list):
132 class SList(list):
109 """List derivative with a special access attributes.
133 """List derivative with a special access attributes.
110
134
111 These are normal lists, but with the special attributes:
135 These are normal lists, but with the special attributes:
112
136
113 .l (or .list) : value as list (the list itself).
137 .l (or .list) : value as list (the list itself).
114 .n (or .nlstr): value as a string, joined on newlines.
138 .n (or .nlstr): value as a string, joined on newlines.
115 .s (or .spstr): value as a string, joined on spaces.
139 .s (or .spstr): value as a string, joined on spaces.
116 .p (or .paths): list of path objects
140 .p (or .paths): list of path objects
117
141
118 Any values which require transformations are computed only once and
142 Any values which require transformations are computed only once and
119 cached."""
143 cached."""
120
144
121 def get_list(self):
145 def get_list(self):
122 return self
146 return self
123
147
124 l = list = property(get_list)
148 l = list = property(get_list)
125
149
126 def get_spstr(self):
150 def get_spstr(self):
127 try:
151 try:
128 return self.__spstr
152 return self.__spstr
129 except AttributeError:
153 except AttributeError:
130 self.__spstr = ' '.join(self)
154 self.__spstr = ' '.join(self)
131 return self.__spstr
155 return self.__spstr
132
156
133 s = spstr = property(get_spstr)
157 s = spstr = property(get_spstr)
134
158
135 def get_nlstr(self):
159 def get_nlstr(self):
136 try:
160 try:
137 return self.__nlstr
161 return self.__nlstr
138 except AttributeError:
162 except AttributeError:
139 self.__nlstr = '\n'.join(self)
163 self.__nlstr = '\n'.join(self)
140 return self.__nlstr
164 return self.__nlstr
141
165
142 n = nlstr = property(get_nlstr)
166 n = nlstr = property(get_nlstr)
143
167
144 def get_paths(self):
168 def get_paths(self):
145 try:
169 try:
146 return self.__paths
170 return self.__paths
147 except AttributeError:
171 except AttributeError:
148 self.__paths = [path(p) for p in self if os.path.exists(p)]
172 self.__paths = [path(p) for p in self if os.path.exists(p)]
149 return self.__paths
173 return self.__paths
150
174
151 p = paths = property(get_paths)
175 p = paths = property(get_paths)
152
176
153 def grep(self, pattern, prune = False, field = None):
177 def grep(self, pattern, prune = False, field = None):
154 """ Return all strings matching 'pattern' (a regex or callable)
178 """ Return all strings matching 'pattern' (a regex or callable)
155
179
156 This is case-insensitive. If prune is true, return all items
180 This is case-insensitive. If prune is true, return all items
157 NOT matching the pattern.
181 NOT matching the pattern.
158
182
159 If field is specified, the match must occur in the specified
183 If field is specified, the match must occur in the specified
160 whitespace-separated field.
184 whitespace-separated field.
161
185
162 Examples::
186 Examples::
163
187
164 a.grep( lambda x: x.startswith('C') )
188 a.grep( lambda x: x.startswith('C') )
165 a.grep('Cha.*log', prune=1)
189 a.grep('Cha.*log', prune=1)
166 a.grep('chm', field=-1)
190 a.grep('chm', field=-1)
167 """
191 """
168
192
169 def match_target(s):
193 def match_target(s):
170 if field is None:
194 if field is None:
171 return s
195 return s
172 parts = s.split()
196 parts = s.split()
173 try:
197 try:
174 tgt = parts[field]
198 tgt = parts[field]
175 return tgt
199 return tgt
176 except IndexError:
200 except IndexError:
177 return ""
201 return ""
178
202
179 if isinstance(pattern, basestring):
203 if isinstance(pattern, basestring):
180 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
204 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
181 else:
205 else:
182 pred = pattern
206 pred = pattern
183 if not prune:
207 if not prune:
184 return SList([el for el in self if pred(match_target(el))])
208 return SList([el for el in self if pred(match_target(el))])
185 else:
209 else:
186 return SList([el for el in self if not pred(match_target(el))])
210 return SList([el for el in self if not pred(match_target(el))])
187
211
188 def fields(self, *fields):
212 def fields(self, *fields):
189 """ Collect whitespace-separated fields from string list
213 """ Collect whitespace-separated fields from string list
190
214
191 Allows quick awk-like usage of string lists.
215 Allows quick awk-like usage of string lists.
192
216
193 Example data (in var a, created by 'a = !ls -l')::
217 Example data (in var a, created by 'a = !ls -l')::
194 -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
218 -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
195 drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
219 drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
196
220
197 a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
221 a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
198 a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
222 a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
199 (note the joining by space).
223 (note the joining by space).
200 a.fields(-1) is ['ChangeLog', 'IPython']
224 a.fields(-1) is ['ChangeLog', 'IPython']
201
225
202 IndexErrors are ignored.
226 IndexErrors are ignored.
203
227
204 Without args, fields() just split()'s the strings.
228 Without args, fields() just split()'s the strings.
205 """
229 """
206 if len(fields) == 0:
230 if len(fields) == 0:
207 return [el.split() for el in self]
231 return [el.split() for el in self]
208
232
209 res = SList()
233 res = SList()
210 for el in [f.split() for f in self]:
234 for el in [f.split() for f in self]:
211 lineparts = []
235 lineparts = []
212
236
213 for fd in fields:
237 for fd in fields:
214 try:
238 try:
215 lineparts.append(el[fd])
239 lineparts.append(el[fd])
216 except IndexError:
240 except IndexError:
217 pass
241 pass
218 if lineparts:
242 if lineparts:
219 res.append(" ".join(lineparts))
243 res.append(" ".join(lineparts))
220
244
221 return res
245 return res
222
246
223 def sort(self,field= None, nums = False):
247 def sort(self,field= None, nums = False):
224 """ sort by specified fields (see fields())
248 """ sort by specified fields (see fields())
225
249
226 Example::
250 Example::
227 a.sort(1, nums = True)
251 a.sort(1, nums = True)
228
252
229 Sorts a by second field, in numerical order (so that 21 > 3)
253 Sorts a by second field, in numerical order (so that 21 > 3)
230
254
231 """
255 """
232
256
233 #decorate, sort, undecorate
257 #decorate, sort, undecorate
234 if field is not None:
258 if field is not None:
235 dsu = [[SList([line]).fields(field), line] for line in self]
259 dsu = [[SList([line]).fields(field), line] for line in self]
236 else:
260 else:
237 dsu = [[line, line] for line in self]
261 dsu = [[line, line] for line in self]
238 if nums:
262 if nums:
239 for i in range(len(dsu)):
263 for i in range(len(dsu)):
240 numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
264 numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
241 try:
265 try:
242 n = int(numstr)
266 n = int(numstr)
243 except ValueError:
267 except ValueError:
244 n = 0;
268 n = 0;
245 dsu[i][0] = n
269 dsu[i][0] = n
246
270
247
271
248 dsu.sort()
272 dsu.sort()
249 return SList([t[1] for t in dsu])
273 return SList([t[1] for t in dsu])
250
274
251
275
252 # FIXME: We need to reimplement type specific displayhook and then add this
276 # FIXME: We need to reimplement type specific displayhook and then add this
253 # back as a custom printer. This should also be moved outside utils into the
277 # back as a custom printer. This should also be moved outside utils into the
254 # core.
278 # core.
255
279
256 # def print_slist(arg):
280 # def print_slist(arg):
257 # """ Prettier (non-repr-like) and more informative printer for SList """
281 # """ Prettier (non-repr-like) and more informative printer for SList """
258 # print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
282 # print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
259 # if hasattr(arg, 'hideonce') and arg.hideonce:
283 # if hasattr(arg, 'hideonce') and arg.hideonce:
260 # arg.hideonce = False
284 # arg.hideonce = False
261 # return
285 # return
262 #
286 #
263 # nlprint(arg)
287 # nlprint(arg)
264 #
288 #
265 # print_slist = result_display.when_type(SList)(print_slist)
289 # print_slist = result_display.when_type(SList)(print_slist)
266
290
267
291
268 def esc_quotes(strng):
292 def esc_quotes(strng):
269 """Return the input string with single and double quotes escaped out"""
293 """Return the input string with single and double quotes escaped out"""
270
294
271 return strng.replace('"','\\"').replace("'","\\'")
295 return strng.replace('"','\\"').replace("'","\\'")
272
296
273
297
274 def make_quoted_expr(s):
298 def make_quoted_expr(s):
275 """Return string s in appropriate quotes, using raw string if possible.
299 """Return string s in appropriate quotes, using raw string if possible.
276
300
277 XXX - example removed because it caused encoding errors in documentation
301 XXX - example removed because it caused encoding errors in documentation
278 generation. We need a new example that doesn't contain invalid chars.
302 generation. We need a new example that doesn't contain invalid chars.
279
303
280 Note the use of raw string and padding at the end to allow trailing
304 Note the use of raw string and padding at the end to allow trailing
281 backslash.
305 backslash.
282 """
306 """
283
307
284 tail = ''
308 tail = ''
285 tailpadding = ''
309 tailpadding = ''
286 raw = ''
310 raw = ''
287 ucode = '' if py3compat.PY3 else 'u'
311 ucode = '' if py3compat.PY3 else 'u'
288 if "\\" in s:
312 if "\\" in s:
289 raw = 'r'
313 raw = 'r'
290 if s.endswith('\\'):
314 if s.endswith('\\'):
291 tail = '[:-1]'
315 tail = '[:-1]'
292 tailpadding = '_'
316 tailpadding = '_'
293 if '"' not in s:
317 if '"' not in s:
294 quote = '"'
318 quote = '"'
295 elif "'" not in s:
319 elif "'" not in s:
296 quote = "'"
320 quote = "'"
297 elif '"""' not in s and not s.endswith('"'):
321 elif '"""' not in s and not s.endswith('"'):
298 quote = '"""'
322 quote = '"""'
299 elif "'''" not in s and not s.endswith("'"):
323 elif "'''" not in s and not s.endswith("'"):
300 quote = "'''"
324 quote = "'''"
301 else:
325 else:
302 # give up, backslash-escaped string will do
326 # give up, backslash-escaped string will do
303 return '"%s"' % esc_quotes(s)
327 return '"%s"' % esc_quotes(s)
304 res = ucode + raw + quote + s + tailpadding + quote + tail
328 res = ucode + raw + quote + s + tailpadding + quote + tail
305 return res
329 return res
306
330
307
331
308 def qw(words,flat=0,sep=None,maxsplit=-1):
332 def qw(words,flat=0,sep=None,maxsplit=-1):
309 """Similar to Perl's qw() operator, but with some more options.
333 """Similar to Perl's qw() operator, but with some more options.
310
334
311 qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
335 qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
312
336
313 words can also be a list itself, and with flat=1, the output will be
337 words can also be a list itself, and with flat=1, the output will be
314 recursively flattened.
338 recursively flattened.
315
339
316 Examples:
340 Examples:
317
341
318 >>> qw('1 2')
342 >>> qw('1 2')
319 ['1', '2']
343 ['1', '2']
320
344
321 >>> qw(['a b','1 2',['m n','p q']])
345 >>> qw(['a b','1 2',['m n','p q']])
322 [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
346 [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
323
347
324 >>> qw(['a b','1 2',['m n','p q']],flat=1)
348 >>> qw(['a b','1 2',['m n','p q']],flat=1)
325 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
349 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
326 """
350 """
327
351
328 if isinstance(words, basestring):
352 if isinstance(words, basestring):
329 return [word.strip() for word in words.split(sep,maxsplit)
353 return [word.strip() for word in words.split(sep,maxsplit)
330 if word and not word.isspace() ]
354 if word and not word.isspace() ]
331 if flat:
355 if flat:
332 return flatten(map(qw,words,[1]*len(words)))
356 return flatten(map(qw,words,[1]*len(words)))
333 return map(qw,words)
357 return map(qw,words)
334
358
335
359
336 def qwflat(words,sep=None,maxsplit=-1):
360 def qwflat(words,sep=None,maxsplit=-1):
337 """Calls qw(words) in flat mode. It's just a convenient shorthand."""
361 """Calls qw(words) in flat mode. It's just a convenient shorthand."""
338 return qw(words,1,sep,maxsplit)
362 return qw(words,1,sep,maxsplit)
339
363
340
364
341 def qw_lol(indata):
365 def qw_lol(indata):
342 """qw_lol('a b') -> [['a','b']],
366 """qw_lol('a b') -> [['a','b']],
343 otherwise it's just a call to qw().
367 otherwise it's just a call to qw().
344
368
345 We need this to make sure the modules_some keys *always* end up as a
369 We need this to make sure the modules_some keys *always* end up as a
346 list of lists."""
370 list of lists."""
347
371
348 if isinstance(indata, basestring):
372 if isinstance(indata, basestring):
349 return [qw(indata)]
373 return [qw(indata)]
350 else:
374 else:
351 return qw(indata)
375 return qw(indata)
352
376
353
377
354 def grep(pat,list,case=1):
378 def grep(pat,list,case=1):
355 """Simple minded grep-like function.
379 """Simple minded grep-like function.
356 grep(pat,list) returns occurrences of pat in list, None on failure.
380 grep(pat,list) returns occurrences of pat in list, None on failure.
357
381
358 It only does simple string matching, with no support for regexps. Use the
382 It only does simple string matching, with no support for regexps. Use the
359 option case=0 for case-insensitive matching."""
383 option case=0 for case-insensitive matching."""
360
384
361 # This is pretty crude. At least it should implement copying only references
385 # This is pretty crude. At least it should implement copying only references
362 # to the original data in case it's big. Now it copies the data for output.
386 # to the original data in case it's big. Now it copies the data for output.
363 out=[]
387 out=[]
364 if case:
388 if case:
365 for term in list:
389 for term in list:
366 if term.find(pat)>-1: out.append(term)
390 if term.find(pat)>-1: out.append(term)
367 else:
391 else:
368 lpat=pat.lower()
392 lpat=pat.lower()
369 for term in list:
393 for term in list:
370 if term.lower().find(lpat)>-1: out.append(term)
394 if term.lower().find(lpat)>-1: out.append(term)
371
395
372 if len(out): return out
396 if len(out): return out
373 else: return None
397 else: return None
374
398
375
399
376 def dgrep(pat,*opts):
400 def dgrep(pat,*opts):
377 """Return grep() on dir()+dir(__builtins__).
401 """Return grep() on dir()+dir(__builtins__).
378
402
379 A very common use of grep() when working interactively."""
403 A very common use of grep() when working interactively."""
380
404
381 return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
405 return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
382
406
383
407
384 def idgrep(pat):
408 def idgrep(pat):
385 """Case-insensitive dgrep()"""
409 """Case-insensitive dgrep()"""
386
410
387 return dgrep(pat,0)
411 return dgrep(pat,0)
388
412
389
413
390 def igrep(pat,list):
414 def igrep(pat,list):
391 """Synonym for case-insensitive grep."""
415 """Synonym for case-insensitive grep."""
392
416
393 return grep(pat,list,case=0)
417 return grep(pat,list,case=0)
394
418
395
419
396 def indent(instr,nspaces=4, ntabs=0, flatten=False):
420 def indent(instr,nspaces=4, ntabs=0, flatten=False):
397 """Indent a string a given number of spaces or tabstops.
421 """Indent a string a given number of spaces or tabstops.
398
422
399 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
423 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
400
424
401 Parameters
425 Parameters
402 ----------
426 ----------
403
427
404 instr : basestring
428 instr : basestring
405 The string to be indented.
429 The string to be indented.
406 nspaces : int (default: 4)
430 nspaces : int (default: 4)
407 The number of spaces to be indented.
431 The number of spaces to be indented.
408 ntabs : int (default: 0)
432 ntabs : int (default: 0)
409 The number of tabs to be indented.
433 The number of tabs to be indented.
410 flatten : bool (default: False)
434 flatten : bool (default: False)
411 Whether to scrub existing indentation. If True, all lines will be
435 Whether to scrub existing indentation. If True, all lines will be
412 aligned to the same indentation. If False, existing indentation will
436 aligned to the same indentation. If False, existing indentation will
413 be strictly increased.
437 be strictly increased.
414
438
415 Returns
439 Returns
416 -------
440 -------
417
441
418 str|unicode : string indented by ntabs and nspaces.
442 str|unicode : string indented by ntabs and nspaces.
419
443
420 """
444 """
421 if instr is None:
445 if instr is None:
422 return
446 return
423 ind = '\t'*ntabs+' '*nspaces
447 ind = '\t'*ntabs+' '*nspaces
424 if flatten:
448 if flatten:
425 pat = re.compile(r'^\s*', re.MULTILINE)
449 pat = re.compile(r'^\s*', re.MULTILINE)
426 else:
450 else:
427 pat = re.compile(r'^', re.MULTILINE)
451 pat = re.compile(r'^', re.MULTILINE)
428 outstr = re.sub(pat, ind, instr)
452 outstr = re.sub(pat, ind, instr)
429 if outstr.endswith(os.linesep+ind):
453 if outstr.endswith(os.linesep+ind):
430 return outstr[:-len(ind)]
454 return outstr[:-len(ind)]
431 else:
455 else:
432 return outstr
456 return outstr
433
457
434 def native_line_ends(filename,backup=1):
458 def native_line_ends(filename,backup=1):
435 """Convert (in-place) a file to line-ends native to the current OS.
459 """Convert (in-place) a file to line-ends native to the current OS.
436
460
437 If the optional backup argument is given as false, no backup of the
461 If the optional backup argument is given as false, no backup of the
438 original file is left. """
462 original file is left. """
439
463
440 backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
464 backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
441
465
442 bak_filename = filename + backup_suffixes[os.name]
466 bak_filename = filename + backup_suffixes[os.name]
443
467
444 original = open(filename).read()
468 original = open(filename).read()
445 shutil.copy2(filename,bak_filename)
469 shutil.copy2(filename,bak_filename)
446 try:
470 try:
447 new = open(filename,'wb')
471 new = open(filename,'wb')
448 new.write(os.linesep.join(original.splitlines()))
472 new.write(os.linesep.join(original.splitlines()))
449 new.write(os.linesep) # ALWAYS put an eol at the end of the file
473 new.write(os.linesep) # ALWAYS put an eol at the end of the file
450 new.close()
474 new.close()
451 except:
475 except:
452 os.rename(bak_filename,filename)
476 os.rename(bak_filename,filename)
453 if not backup:
477 if not backup:
454 try:
478 try:
455 os.remove(bak_filename)
479 os.remove(bak_filename)
456 except:
480 except:
457 pass
481 pass
458
482
459
483
460 def list_strings(arg):
484 def list_strings(arg):
461 """Always return a list of strings, given a string or list of strings
485 """Always return a list of strings, given a string or list of strings
462 as input.
486 as input.
463
487
464 :Examples:
488 :Examples:
465
489
466 In [7]: list_strings('A single string')
490 In [7]: list_strings('A single string')
467 Out[7]: ['A single string']
491 Out[7]: ['A single string']
468
492
469 In [8]: list_strings(['A single string in a list'])
493 In [8]: list_strings(['A single string in a list'])
470 Out[8]: ['A single string in a list']
494 Out[8]: ['A single string in a list']
471
495
472 In [9]: list_strings(['A','list','of','strings'])
496 In [9]: list_strings(['A','list','of','strings'])
473 Out[9]: ['A', 'list', 'of', 'strings']
497 Out[9]: ['A', 'list', 'of', 'strings']
474 """
498 """
475
499
476 if isinstance(arg,basestring): return [arg]
500 if isinstance(arg,basestring): return [arg]
477 else: return arg
501 else: return arg
478
502
479
503
480 def marquee(txt='',width=78,mark='*'):
504 def marquee(txt='',width=78,mark='*'):
481 """Return the input string centered in a 'marquee'.
505 """Return the input string centered in a 'marquee'.
482
506
483 :Examples:
507 :Examples:
484
508
485 In [16]: marquee('A test',40)
509 In [16]: marquee('A test',40)
486 Out[16]: '**************** A test ****************'
510 Out[16]: '**************** A test ****************'
487
511
488 In [17]: marquee('A test',40,'-')
512 In [17]: marquee('A test',40,'-')
489 Out[17]: '---------------- A test ----------------'
513 Out[17]: '---------------- A test ----------------'
490
514
491 In [18]: marquee('A test',40,' ')
515 In [18]: marquee('A test',40,' ')
492 Out[18]: ' A test '
516 Out[18]: ' A test '
493
517
494 """
518 """
495 if not txt:
519 if not txt:
496 return (mark*width)[:width]
520 return (mark*width)[:width]
497 nmark = (width-len(txt)-2)//len(mark)//2
521 nmark = (width-len(txt)-2)//len(mark)//2
498 if nmark < 0: nmark =0
522 if nmark < 0: nmark =0
499 marks = mark*nmark
523 marks = mark*nmark
500 return '%s %s %s' % (marks,txt,marks)
524 return '%s %s %s' % (marks,txt,marks)
501
525
502
526
503 ini_spaces_re = re.compile(r'^(\s+)')
527 ini_spaces_re = re.compile(r'^(\s+)')
504
528
505 def num_ini_spaces(strng):
529 def num_ini_spaces(strng):
506 """Return the number of initial spaces in a string"""
530 """Return the number of initial spaces in a string"""
507
531
508 ini_spaces = ini_spaces_re.match(strng)
532 ini_spaces = ini_spaces_re.match(strng)
509 if ini_spaces:
533 if ini_spaces:
510 return ini_spaces.end()
534 return ini_spaces.end()
511 else:
535 else:
512 return 0
536 return 0
513
537
514
538
515 def format_screen(strng):
539 def format_screen(strng):
516 """Format a string for screen printing.
540 """Format a string for screen printing.
517
541
518 This removes some latex-type format codes."""
542 This removes some latex-type format codes."""
519 # Paragraph continue
543 # Paragraph continue
520 par_re = re.compile(r'\\$',re.MULTILINE)
544 par_re = re.compile(r'\\$',re.MULTILINE)
521 strng = par_re.sub('',strng)
545 strng = par_re.sub('',strng)
522 return strng
546 return strng
523
547
524 def dedent(text):
548 def dedent(text):
525 """Equivalent of textwrap.dedent that ignores unindented first line.
549 """Equivalent of textwrap.dedent that ignores unindented first line.
526
550
527 This means it will still dedent strings like:
551 This means it will still dedent strings like:
528 '''foo
552 '''foo
529 is a bar
553 is a bar
530 '''
554 '''
531
555
532 For use in wrap_paragraphs.
556 For use in wrap_paragraphs.
533 """
557 """
534
558
535 if text.startswith('\n'):
559 if text.startswith('\n'):
536 # text starts with blank line, don't ignore the first line
560 # text starts with blank line, don't ignore the first line
537 return textwrap.dedent(text)
561 return textwrap.dedent(text)
538
562
539 # split first line
563 # split first line
540 splits = text.split('\n',1)
564 splits = text.split('\n',1)
541 if len(splits) == 1:
565 if len(splits) == 1:
542 # only one line
566 # only one line
543 return textwrap.dedent(text)
567 return textwrap.dedent(text)
544
568
545 first, rest = splits
569 first, rest = splits
546 # dedent everything but the first line
570 # dedent everything but the first line
547 rest = textwrap.dedent(rest)
571 rest = textwrap.dedent(rest)
548 return '\n'.join([first, rest])
572 return '\n'.join([first, rest])
549
573
550 def wrap_paragraphs(text, ncols=80):
574 def wrap_paragraphs(text, ncols=80):
551 """Wrap multiple paragraphs to fit a specified width.
575 """Wrap multiple paragraphs to fit a specified width.
552
576
553 This is equivalent to textwrap.wrap, but with support for multiple
577 This is equivalent to textwrap.wrap, but with support for multiple
554 paragraphs, as separated by empty lines.
578 paragraphs, as separated by empty lines.
555
579
556 Returns
580 Returns
557 -------
581 -------
558
582
559 list of complete paragraphs, wrapped to fill `ncols` columns.
583 list of complete paragraphs, wrapped to fill `ncols` columns.
560 """
584 """
561 paragraph_re = re.compile(r'\n(\s*\n)+', re.MULTILINE)
585 paragraph_re = re.compile(r'\n(\s*\n)+', re.MULTILINE)
562 text = dedent(text).strip()
586 text = dedent(text).strip()
563 paragraphs = paragraph_re.split(text)[::2] # every other entry is space
587 paragraphs = paragraph_re.split(text)[::2] # every other entry is space
564 out_ps = []
588 out_ps = []
565 indent_re = re.compile(r'\n\s+', re.MULTILINE)
589 indent_re = re.compile(r'\n\s+', re.MULTILINE)
566 for p in paragraphs:
590 for p in paragraphs:
567 # presume indentation that survives dedent is meaningful formatting,
591 # presume indentation that survives dedent is meaningful formatting,
568 # so don't fill unless text is flush.
592 # so don't fill unless text is flush.
569 if indent_re.search(p) is None:
593 if indent_re.search(p) is None:
570 # wrap paragraph
594 # wrap paragraph
571 p = textwrap.fill(p, ncols)
595 p = textwrap.fill(p, ncols)
572 out_ps.append(p)
596 out_ps.append(p)
573 return out_ps
597 return out_ps
574
598
575
599
576
600
577 class EvalFormatter(Formatter):
601 class EvalFormatter(Formatter):
578 """A String Formatter that allows evaluation of simple expressions.
602 """A String Formatter that allows evaluation of simple expressions.
579
603
580 Any time a format key is not found in the kwargs,
604 Any time a format key is not found in the kwargs,
581 it will be tried as an expression in the kwargs namespace.
605 it will be tried as an expression in the kwargs namespace.
582
606
583 This is to be used in templating cases, such as the parallel batch
607 This is to be used in templating cases, such as the parallel batch
584 script templates, where simple arithmetic on arguments is useful.
608 script templates, where simple arithmetic on arguments is useful.
585
609
586 Examples
610 Examples
587 --------
611 --------
588
612
589 In [1]: f = EvalFormatter()
613 In [1]: f = EvalFormatter()
590 In [2]: f.format('{n//4}', n=8)
614 In [2]: f.format('{n//4}', n=8)
591 Out[2]: '2'
615 Out[2]: '2'
592
616
593 In [3]: f.format('{list(range(3))}')
617 In [3]: f.format('{list(range(3))}')
594 Out[3]: '[0, 1, 2]'
618 Out[3]: '[0, 1, 2]'
595
619
596 In [4]: f.format('{3*2}')
620 In [4]: f.format('{3*2}')
597 Out[4]: '6'
621 Out[4]: '6'
598 """
622 """
599
623
600 # should we allow slicing by disabling the format_spec feature?
624 # should we allow slicing by disabling the format_spec feature?
601 allow_slicing = True
625 allow_slicing = True
602
626
603 # copied from Formatter._vformat with minor changes to allow eval
627 # copied from Formatter._vformat with minor changes to allow eval
604 # and replace the format_spec code with slicing
628 # and replace the format_spec code with slicing
605 def _vformat(self, format_string, args, kwargs, used_args, recursion_depth):
629 def _vformat(self, format_string, args, kwargs, used_args, recursion_depth):
606 if recursion_depth < 0:
630 if recursion_depth < 0:
607 raise ValueError('Max string recursion exceeded')
631 raise ValueError('Max string recursion exceeded')
608 result = []
632 result = []
609 for literal_text, field_name, format_spec, conversion in \
633 for literal_text, field_name, format_spec, conversion in \
610 self.parse(format_string):
634 self.parse(format_string):
611
635
612 # output the literal text
636 # output the literal text
613 if literal_text:
637 if literal_text:
614 result.append(literal_text)
638 result.append(literal_text)
615
639
616 # if there's a field, output it
640 # if there's a field, output it
617 if field_name is not None:
641 if field_name is not None:
618 # this is some markup, find the object and do
642 # this is some markup, find the object and do
619 # the formatting
643 # the formatting
620
644
621 if self.allow_slicing and format_spec:
645 if self.allow_slicing and format_spec:
622 # override format spec, to allow slicing:
646 # override format spec, to allow slicing:
623 field_name = ':'.join([field_name, format_spec])
647 field_name = ':'.join([field_name, format_spec])
624 format_spec = ''
648 format_spec = ''
625
649
626 # eval the contents of the field for the object
650 # eval the contents of the field for the object
627 # to be formatted
651 # to be formatted
628 obj = eval(field_name, kwargs)
652 obj = eval(field_name, kwargs)
629
653
630 # do any conversion on the resulting object
654 # do any conversion on the resulting object
631 obj = self.convert_field(obj, conversion)
655 obj = self.convert_field(obj, conversion)
632
656
633 # expand the format spec, if needed
657 # expand the format spec, if needed
634 format_spec = self._vformat(format_spec, args, kwargs,
658 format_spec = self._vformat(format_spec, args, kwargs,
635 used_args, recursion_depth-1)
659 used_args, recursion_depth-1)
636
660
637 # format the object and append to the result
661 # format the object and append to the result
638 result.append(self.format_field(obj, format_spec))
662 result.append(self.format_field(obj, format_spec))
639
663
640 return ''.join(result)
664 return ''.join(result)
641
665
642
666
643 def columnize(items, separator=' ', displaywidth=80):
667 def columnize(items, separator=' ', displaywidth=80):
644 """ Transform a list of strings into a single string with columns.
668 """ Transform a list of strings into a single string with columns.
645
669
646 Parameters
670 Parameters
647 ----------
671 ----------
648 items : sequence of strings
672 items : sequence of strings
649 The strings to process.
673 The strings to process.
650
674
651 separator : str, optional [default is two spaces]
675 separator : str, optional [default is two spaces]
652 The string that separates columns.
676 The string that separates columns.
653
677
654 displaywidth : int, optional [default is 80]
678 displaywidth : int, optional [default is 80]
655 Width of the display in number of characters.
679 Width of the display in number of characters.
656
680
657 Returns
681 Returns
658 -------
682 -------
659 The formatted string.
683 The formatted string.
660 """
684 """
661 # Note: this code is adapted from columnize 0.3.2.
685 # Note: this code is adapted from columnize 0.3.2.
662 # See http://code.google.com/p/pycolumnize/
686 # See http://code.google.com/p/pycolumnize/
663
687
664 # Some degenerate cases.
688 # Some degenerate cases.
665 size = len(items)
689 size = len(items)
666 if size == 0:
690 if size == 0:
667 return '\n'
691 return '\n'
668 elif size == 1:
692 elif size == 1:
669 return '%s\n' % items[0]
693 return '%s\n' % items[0]
670
694
671 # Special case: if any item is longer than the maximum width, there's no
695 # Special case: if any item is longer than the maximum width, there's no
672 # point in triggering the logic below...
696 # point in triggering the logic below...
673 item_len = map(len, items) # save these, we can reuse them below
697 item_len = map(len, items) # save these, we can reuse them below
674 longest = max(item_len)
698 longest = max(item_len)
675 if longest >= displaywidth:
699 if longest >= displaywidth:
676 return '\n'.join(items+[''])
700 return '\n'.join(items+[''])
677
701
678 # Try every row count from 1 upwards
702 # Try every row count from 1 upwards
679 array_index = lambda nrows, row, col: nrows*col + row
703 array_index = lambda nrows, row, col: nrows*col + row
680 for nrows in range(1, size):
704 for nrows in range(1, size):
681 ncols = (size + nrows - 1) // nrows
705 ncols = (size + nrows - 1) // nrows
682 colwidths = []
706 colwidths = []
683 totwidth = -len(separator)
707 totwidth = -len(separator)
684 for col in range(ncols):
708 for col in range(ncols):
685 # Get max column width for this column
709 # Get max column width for this column
686 colwidth = 0
710 colwidth = 0
687 for row in range(nrows):
711 for row in range(nrows):
688 i = array_index(nrows, row, col)
712 i = array_index(nrows, row, col)
689 if i >= size: break
713 if i >= size: break
690 x, len_x = items[i], item_len[i]
714 x, len_x = items[i], item_len[i]
691 colwidth = max(colwidth, len_x)
715 colwidth = max(colwidth, len_x)
692 colwidths.append(colwidth)
716 colwidths.append(colwidth)
693 totwidth += colwidth + len(separator)
717 totwidth += colwidth + len(separator)
694 if totwidth > displaywidth:
718 if totwidth > displaywidth:
695 break
719 break
696 if totwidth <= displaywidth:
720 if totwidth <= displaywidth:
697 break
721 break
698
722
699 # The smallest number of rows computed and the max widths for each
723 # The smallest number of rows computed and the max widths for each
700 # column has been obtained. Now we just have to format each of the rows.
724 # column has been obtained. Now we just have to format each of the rows.
701 string = ''
725 string = ''
702 for row in range(nrows):
726 for row in range(nrows):
703 texts = []
727 texts = []
704 for col in range(ncols):
728 for col in range(ncols):
705 i = row + nrows*col
729 i = row + nrows*col
706 if i >= size:
730 if i >= size:
707 texts.append('')
731 texts.append('')
708 else:
732 else:
709 texts.append(items[i])
733 texts.append(items[i])
710 while texts and not texts[-1]:
734 while texts and not texts[-1]:
711 del texts[-1]
735 del texts[-1]
712 for col in range(len(texts)):
736 for col in range(len(texts)):
713 texts[col] = texts[col].ljust(colwidths[col])
737 texts[col] = texts[col].ljust(colwidths[col])
714 string += '%s\n' % separator.join(texts)
738 string += '%s\n' % separator.join(texts)
715 return string
739 return string
@@ -1,91 +1,91 b''
1 import sys
1 import sys
2 import time
2 import time
3 from io import StringIO
3 from io import StringIO
4
4
5 from session import extract_header, Message
5 from session import extract_header, Message
6
6
7 from IPython.utils import io
7 from IPython.utils import io, text
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Globals
10 # Globals
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Stream classes
14 # Stream classes
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 class OutStream(object):
17 class OutStream(object):
18 """A file like object that publishes the stream to a 0MQ PUB socket."""
18 """A file like object that publishes the stream to a 0MQ PUB socket."""
19
19
20 # The time interval between automatic flushes, in seconds.
20 # The time interval between automatic flushes, in seconds.
21 flush_interval = 0.05
21 flush_interval = 0.05
22 topic=None
22 topic=None
23
23
24 def __init__(self, session, pub_socket, name):
24 def __init__(self, session, pub_socket, name):
25 self.session = session
25 self.session = session
26 self.pub_socket = pub_socket
26 self.pub_socket = pub_socket
27 self.name = name
27 self.name = name
28 self.parent_header = {}
28 self.parent_header = {}
29 self._new_buffer()
29 self._new_buffer()
30
30
31 def set_parent(self, parent):
31 def set_parent(self, parent):
32 self.parent_header = extract_header(parent)
32 self.parent_header = extract_header(parent)
33
33
34 def close(self):
34 def close(self):
35 self.pub_socket = None
35 self.pub_socket = None
36
36
37 def flush(self):
37 def flush(self):
38 #io.rprint('>>>flushing output buffer: %s<<<' % self.name) # dbg
38 #io.rprint('>>>flushing output buffer: %s<<<' % self.name) # dbg
39 if self.pub_socket is None:
39 if self.pub_socket is None:
40 raise ValueError(u'I/O operation on closed file')
40 raise ValueError(u'I/O operation on closed file')
41 else:
41 else:
42 data = self._buffer.getvalue()
42 data = self._buffer.getvalue()
43 if data:
43 if data:
44 content = {u'name':self.name, u'data':data}
44 content = {u'name':self.name, u'data':data}
45 msg = self.session.send(self.pub_socket, u'stream', content=content,
45 msg = self.session.send(self.pub_socket, u'stream', content=content,
46 parent=self.parent_header, ident=self.topic)
46 parent=self.parent_header, ident=self.topic)
47
47
48 if hasattr(self.pub_socket, 'flush'):
48 if hasattr(self.pub_socket, 'flush'):
49 # socket itself has flush (presumably ZMQStream)
49 # socket itself has flush (presumably ZMQStream)
50 self.pub_socket.flush()
50 self.pub_socket.flush()
51 self._buffer.close()
51 self._buffer.close()
52 self._new_buffer()
52 self._new_buffer()
53
53
54 def isatty(self):
54 def isatty(self):
55 return False
55 return False
56
56
57 def next(self):
57 def next(self):
58 raise IOError('Read not supported on a write only stream.')
58 raise IOError('Read not supported on a write only stream.')
59
59
60 def read(self, size=-1):
60 def read(self, size=-1):
61 raise IOError('Read not supported on a write only stream.')
61 raise IOError('Read not supported on a write only stream.')
62
62
63 def readline(self, size=-1):
63 def readline(self, size=-1):
64 raise IOError('Read not supported on a write only stream.')
64 raise IOError('Read not supported on a write only stream.')
65
65
66 def write(self, string):
66 def write(self, string):
67 if self.pub_socket is None:
67 if self.pub_socket is None:
68 raise ValueError('I/O operation on closed file')
68 raise ValueError('I/O operation on closed file')
69 else:
69 else:
70 # Make sure that we're handling unicode
70 # Make sure that we're handling unicode
71 if not isinstance(string, unicode):
71 if not isinstance(string, unicode):
72 enc = sys.stdin.encoding or sys.getdefaultencoding()
72 enc = text.getdefaultencoding()
73 string = string.decode(enc, 'replace')
73 string = string.decode(enc, 'replace')
74
74
75 self._buffer.write(string)
75 self._buffer.write(string)
76 current_time = time.time()
76 current_time = time.time()
77 if self._start <= 0:
77 if self._start <= 0:
78 self._start = current_time
78 self._start = current_time
79 elif current_time - self._start > self.flush_interval:
79 elif current_time - self._start > self.flush_interval:
80 self.flush()
80 self.flush()
81
81
82 def writelines(self, sequence):
82 def writelines(self, sequence):
83 if self.pub_socket is None:
83 if self.pub_socket is None:
84 raise ValueError('I/O operation on closed file')
84 raise ValueError('I/O operation on closed file')
85 else:
85 else:
86 for string in sequence:
86 for string in sequence:
87 self.write(string)
87 self.write(string)
88
88
89 def _new_buffer(self):
89 def _new_buffer(self):
90 self._buffer = StringIO()
90 self._buffer = StringIO()
91 self._start = -1
91 self._start = -1
@@ -1,699 +1,702 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """A simple interactive kernel that talks to a frontend over 0MQ.
2 """A simple interactive kernel that talks to a frontend over 0MQ.
3
3
4 Things to do:
4 Things to do:
5
5
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
7 call set_parent on all the PUB objects with the message about to be executed.
7 call set_parent on all the PUB objects with the message about to be executed.
8 * Implement random port and security key logic.
8 * Implement random port and security key logic.
9 * Implement control messages.
9 * Implement control messages.
10 * Implement event loop and poll version.
10 * Implement event loop and poll version.
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Standard library imports.
18 # Standard library imports.
19 import __builtin__
19 import __builtin__
20 import atexit
20 import atexit
21 import sys
21 import sys
22 import time
22 import time
23 import traceback
23 import traceback
24 import logging
24 import logging
25 # System library imports.
25 # System library imports.
26 import zmq
26 import zmq
27
27
28 # Local imports.
28 # Local imports.
29 from IPython.config.configurable import Configurable
29 from IPython.config.configurable import Configurable
30 from IPython.config.application import boolean_flag
30 from IPython.config.application import boolean_flag
31 from IPython.core.application import ProfileDir
31 from IPython.core.application import ProfileDir
32 from IPython.core.shellapp import (
32 from IPython.core.shellapp import (
33 InteractiveShellApp, shell_flags, shell_aliases
33 InteractiveShellApp, shell_flags, shell_aliases
34 )
34 )
35 from IPython.utils import io
35 from IPython.utils import io
36 from IPython.utils import py3compat
36 from IPython.utils import py3compat
37 from IPython.utils.jsonutil import json_clean
37 from IPython.utils.jsonutil import json_clean
38 from IPython.lib import pylabtools
38 from IPython.lib import pylabtools
39 from IPython.utils.traitlets import (
39 from IPython.utils.traitlets import (
40 List, Instance, Float, Dict, Bool, Int, Unicode, CaselessStrEnum
40 List, Instance, Float, Dict, Bool, Int, Unicode, CaselessStrEnum
41 )
41 )
42
42
43 from entry_point import base_launch_kernel
43 from entry_point import base_launch_kernel
44 from kernelapp import KernelApp, kernel_flags, kernel_aliases
44 from kernelapp import KernelApp, kernel_flags, kernel_aliases
45 from iostream import OutStream
45 from iostream import OutStream
46 from session import Session, Message
46 from session import Session, Message
47 from zmqshell import ZMQInteractiveShell
47 from zmqshell import ZMQInteractiveShell
48
48
49
49
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51 # Main kernel class
51 # Main kernel class
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53
53
54 class Kernel(Configurable):
54 class Kernel(Configurable):
55
55
56 #---------------------------------------------------------------------------
56 #---------------------------------------------------------------------------
57 # Kernel interface
57 # Kernel interface
58 #---------------------------------------------------------------------------
58 #---------------------------------------------------------------------------
59
59
60 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
60 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
61 session = Instance(Session)
61 session = Instance(Session)
62 shell_socket = Instance('zmq.Socket')
62 shell_socket = Instance('zmq.Socket')
63 iopub_socket = Instance('zmq.Socket')
63 iopub_socket = Instance('zmq.Socket')
64 stdin_socket = Instance('zmq.Socket')
64 stdin_socket = Instance('zmq.Socket')
65 log = Instance(logging.Logger)
65 log = Instance(logging.Logger)
66
66
67 # Private interface
67 # Private interface
68
68
69 # Time to sleep after flushing the stdout/err buffers in each execute
69 # Time to sleep after flushing the stdout/err buffers in each execute
70 # cycle. While this introduces a hard limit on the minimal latency of the
70 # cycle. While this introduces a hard limit on the minimal latency of the
71 # execute cycle, it helps prevent output synchronization problems for
71 # execute cycle, it helps prevent output synchronization problems for
72 # clients.
72 # clients.
73 # Units are in seconds. The minimum zmq latency on local host is probably
73 # Units are in seconds. The minimum zmq latency on local host is probably
74 # ~150 microseconds, set this to 500us for now. We may need to increase it
74 # ~150 microseconds, set this to 500us for now. We may need to increase it
75 # a little if it's not enough after more interactive testing.
75 # a little if it's not enough after more interactive testing.
76 _execute_sleep = Float(0.0005, config=True)
76 _execute_sleep = Float(0.0005, config=True)
77
77
78 # Frequency of the kernel's event loop.
78 # Frequency of the kernel's event loop.
79 # Units are in seconds, kernel subclasses for GUI toolkits may need to
79 # Units are in seconds, kernel subclasses for GUI toolkits may need to
80 # adapt to milliseconds.
80 # adapt to milliseconds.
81 _poll_interval = Float(0.05, config=True)
81 _poll_interval = Float(0.05, config=True)
82
82
83 # If the shutdown was requested over the network, we leave here the
83 # If the shutdown was requested over the network, we leave here the
84 # necessary reply message so it can be sent by our registered atexit
84 # necessary reply message so it can be sent by our registered atexit
85 # handler. This ensures that the reply is only sent to clients truly at
85 # handler. This ensures that the reply is only sent to clients truly at
86 # the end of our shutdown process (which happens after the underlying
86 # the end of our shutdown process (which happens after the underlying
87 # IPython shell's own shutdown).
87 # IPython shell's own shutdown).
88 _shutdown_message = None
88 _shutdown_message = None
89
89
90 # This is a dict of port number that the kernel is listening on. It is set
90 # This is a dict of port number that the kernel is listening on. It is set
91 # by record_ports and used by connect_request.
91 # by record_ports and used by connect_request.
92 _recorded_ports = Dict()
92 _recorded_ports = Dict()
93
93
94
94
95
95
96 def __init__(self, **kwargs):
96 def __init__(self, **kwargs):
97 super(Kernel, self).__init__(**kwargs)
97 super(Kernel, self).__init__(**kwargs)
98
98
99 # Before we even start up the shell, register *first* our exit handlers
99 # Before we even start up the shell, register *first* our exit handlers
100 # so they come before the shell's
100 # so they come before the shell's
101 atexit.register(self._at_shutdown)
101 atexit.register(self._at_shutdown)
102
102
103 # Initialize the InteractiveShell subclass
103 # Initialize the InteractiveShell subclass
104 self.shell = ZMQInteractiveShell.instance(config=self.config)
104 self.shell = ZMQInteractiveShell.instance(config=self.config)
105 self.shell.displayhook.session = self.session
105 self.shell.displayhook.session = self.session
106 self.shell.displayhook.pub_socket = self.iopub_socket
106 self.shell.displayhook.pub_socket = self.iopub_socket
107 self.shell.display_pub.session = self.session
107 self.shell.display_pub.session = self.session
108 self.shell.display_pub.pub_socket = self.iopub_socket
108 self.shell.display_pub.pub_socket = self.iopub_socket
109
109
110 # TMP - hack while developing
110 # TMP - hack while developing
111 self.shell._reply_content = None
111 self.shell._reply_content = None
112
112
113 # Build dict of handlers for message types
113 # Build dict of handlers for message types
114 msg_types = [ 'execute_request', 'complete_request',
114 msg_types = [ 'execute_request', 'complete_request',
115 'object_info_request', 'history_request',
115 'object_info_request', 'history_request',
116 'connect_request', 'shutdown_request']
116 'connect_request', 'shutdown_request']
117 self.handlers = {}
117 self.handlers = {}
118 for msg_type in msg_types:
118 for msg_type in msg_types:
119 self.handlers[msg_type] = getattr(self, msg_type)
119 self.handlers[msg_type] = getattr(self, msg_type)
120
120
121 def do_one_iteration(self):
121 def do_one_iteration(self):
122 """Do one iteration of the kernel's evaluation loop.
122 """Do one iteration of the kernel's evaluation loop.
123 """
123 """
124 try:
124 try:
125 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
125 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
126 except Exception:
126 except Exception:
127 self.log.warn("Invalid Message:", exc_info=True)
127 self.log.warn("Invalid Message:", exc_info=True)
128 return
128 return
129 if msg is None:
129 if msg is None:
130 return
130 return
131
131
132 msg_type = msg['header']['msg_type']
132 msg_type = msg['header']['msg_type']
133
133
134 # This assert will raise in versions of zeromq 2.0.7 and lesser.
134 # This assert will raise in versions of zeromq 2.0.7 and lesser.
135 # We now require 2.0.8 or above, so we can uncomment for safety.
135 # We now require 2.0.8 or above, so we can uncomment for safety.
136 # print(ident,msg, file=sys.__stdout__)
136 # print(ident,msg, file=sys.__stdout__)
137 assert ident is not None, "Missing message part."
137 assert ident is not None, "Missing message part."
138
138
139 # Print some info about this message and leave a '--->' marker, so it's
139 # Print some info about this message and leave a '--->' marker, so it's
140 # easier to trace visually the message chain when debugging. Each
140 # easier to trace visually the message chain when debugging. Each
141 # handler prints its message at the end.
141 # handler prints its message at the end.
142 self.log.debug('\n*** MESSAGE TYPE:'+str(msg_type)+'***')
142 self.log.debug('\n*** MESSAGE TYPE:'+str(msg_type)+'***')
143 self.log.debug(' Content: '+str(msg['content'])+'\n --->\n ')
143 self.log.debug(' Content: '+str(msg['content'])+'\n --->\n ')
144
144
145 # Find and call actual handler for message
145 # Find and call actual handler for message
146 handler = self.handlers.get(msg_type, None)
146 handler = self.handlers.get(msg_type, None)
147 if handler is None:
147 if handler is None:
148 self.log.error("UNKNOWN MESSAGE TYPE:" +str(msg))
148 self.log.error("UNKNOWN MESSAGE TYPE:" +str(msg))
149 else:
149 else:
150 handler(ident, msg)
150 handler(ident, msg)
151
151
152 # Check whether we should exit, in case the incoming message set the
152 # Check whether we should exit, in case the incoming message set the
153 # exit flag on
153 # exit flag on
154 if self.shell.exit_now:
154 if self.shell.exit_now:
155 self.log.debug('\nExiting IPython kernel...')
155 self.log.debug('\nExiting IPython kernel...')
156 # We do a normal, clean exit, which allows any actions registered
156 # We do a normal, clean exit, which allows any actions registered
157 # via atexit (such as history saving) to take place.
157 # via atexit (such as history saving) to take place.
158 sys.exit(0)
158 sys.exit(0)
159
159
160
160
161 def start(self):
161 def start(self):
162 """ Start the kernel main loop.
162 """ Start the kernel main loop.
163 """
163 """
164 poller = zmq.Poller()
164 poller = zmq.Poller()
165 poller.register(self.shell_socket, zmq.POLLIN)
165 poller.register(self.shell_socket, zmq.POLLIN)
166 while True:
166 while True:
167 try:
167 try:
168 # scale by extra factor of 10, because there is no
168 # scale by extra factor of 10, because there is no
169 # reason for this to be anything less than ~ 0.1s
169 # reason for this to be anything less than ~ 0.1s
170 # since it is a real poller and will respond
170 # since it is a real poller and will respond
171 # to events immediately
171 # to events immediately
172
172
173 # double nested try/except, to properly catch KeyboardInterrupt
173 # double nested try/except, to properly catch KeyboardInterrupt
174 # due to pyzmq Issue #130
174 # due to pyzmq Issue #130
175 try:
175 try:
176 poller.poll(10*1000*self._poll_interval)
176 poller.poll(10*1000*self._poll_interval)
177 self.do_one_iteration()
177 self.do_one_iteration()
178 except:
178 except:
179 raise
179 raise
180 except KeyboardInterrupt:
180 except KeyboardInterrupt:
181 # Ctrl-C shouldn't crash the kernel
181 # Ctrl-C shouldn't crash the kernel
182 io.raw_print("KeyboardInterrupt caught in kernel")
182 io.raw_print("KeyboardInterrupt caught in kernel")
183
183
184 def record_ports(self, ports):
184 def record_ports(self, ports):
185 """Record the ports that this kernel is using.
185 """Record the ports that this kernel is using.
186
186
187 The creator of the Kernel instance must call this methods if they
187 The creator of the Kernel instance must call this methods if they
188 want the :meth:`connect_request` method to return the port numbers.
188 want the :meth:`connect_request` method to return the port numbers.
189 """
189 """
190 self._recorded_ports = ports
190 self._recorded_ports = ports
191
191
192 #---------------------------------------------------------------------------
192 #---------------------------------------------------------------------------
193 # Kernel request handlers
193 # Kernel request handlers
194 #---------------------------------------------------------------------------
194 #---------------------------------------------------------------------------
195
195
196 def _publish_pyin(self, code, parent):
196 def _publish_pyin(self, code, parent):
197 """Publish the code request on the pyin stream."""
197 """Publish the code request on the pyin stream."""
198
198
199 pyin_msg = self.session.send(self.iopub_socket, u'pyin',{u'code':code}, parent=parent)
199 pyin_msg = self.session.send(self.iopub_socket, u'pyin',{u'code':code}, parent=parent)
200
200
201 def execute_request(self, ident, parent):
201 def execute_request(self, ident, parent):
202
202
203 status_msg = self.session.send(self.iopub_socket,
203 status_msg = self.session.send(self.iopub_socket,
204 u'status',
204 u'status',
205 {u'execution_state':u'busy'},
205 {u'execution_state':u'busy'},
206 parent=parent
206 parent=parent
207 )
207 )
208
208
209 try:
209 try:
210 content = parent[u'content']
210 content = parent[u'content']
211 code = content[u'code']
211 code = content[u'code']
212 silent = content[u'silent']
212 silent = content[u'silent']
213 except:
213 except:
214 self.log.error("Got bad msg: ")
214 self.log.error("Got bad msg: ")
215 self.log.error(str(Message(parent)))
215 self.log.error(str(Message(parent)))
216 return
216 return
217
217
218 shell = self.shell # we'll need this a lot here
218 shell = self.shell # we'll need this a lot here
219
219
220 # Replace raw_input. Note that is not sufficient to replace
220 # Replace raw_input. Note that is not sufficient to replace
221 # raw_input in the user namespace.
221 # raw_input in the user namespace.
222 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
222 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
223 if py3compat.PY3:
223 if py3compat.PY3:
224 __builtin__.input = raw_input
224 __builtin__.input = raw_input
225 else:
225 else:
226 __builtin__.raw_input = raw_input
226 __builtin__.raw_input = raw_input
227
227
228 # Set the parent message of the display hook and out streams.
228 # Set the parent message of the display hook and out streams.
229 shell.displayhook.set_parent(parent)
229 shell.displayhook.set_parent(parent)
230 shell.display_pub.set_parent(parent)
230 shell.display_pub.set_parent(parent)
231 sys.stdout.set_parent(parent)
231 sys.stdout.set_parent(parent)
232 sys.stderr.set_parent(parent)
232 sys.stderr.set_parent(parent)
233
233
234 # Re-broadcast our input for the benefit of listening clients, and
234 # Re-broadcast our input for the benefit of listening clients, and
235 # start computing output
235 # start computing output
236 if not silent:
236 if not silent:
237 self._publish_pyin(code, parent)
237 self._publish_pyin(code, parent)
238
238
239 reply_content = {}
239 reply_content = {}
240 try:
240 try:
241 if silent:
241 if silent:
242 # run_code uses 'exec' mode, so no displayhook will fire, and it
242 # run_code uses 'exec' mode, so no displayhook will fire, and it
243 # doesn't call logging or history manipulations. Print
243 # doesn't call logging or history manipulations. Print
244 # statements in that code will obviously still execute.
244 # statements in that code will obviously still execute.
245 shell.run_code(code)
245 shell.run_code(code)
246 else:
246 else:
247 # FIXME: the shell calls the exception handler itself.
247 # FIXME: the shell calls the exception handler itself.
248 shell.run_cell(code)
248 shell.run_cell(code)
249 except:
249 except:
250 status = u'error'
250 status = u'error'
251 # FIXME: this code right now isn't being used yet by default,
251 # FIXME: this code right now isn't being used yet by default,
252 # because the run_cell() call above directly fires off exception
252 # because the run_cell() call above directly fires off exception
253 # reporting. This code, therefore, is only active in the scenario
253 # reporting. This code, therefore, is only active in the scenario
254 # where runlines itself has an unhandled exception. We need to
254 # where runlines itself has an unhandled exception. We need to
255 # uniformize this, for all exception construction to come from a
255 # uniformize this, for all exception construction to come from a
256 # single location in the codbase.
256 # single location in the codbase.
257 etype, evalue, tb = sys.exc_info()
257 etype, evalue, tb = sys.exc_info()
258 tb_list = traceback.format_exception(etype, evalue, tb)
258 tb_list = traceback.format_exception(etype, evalue, tb)
259 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
259 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
260 else:
260 else:
261 status = u'ok'
261 status = u'ok'
262
262
263 reply_content[u'status'] = status
263 reply_content[u'status'] = status
264
264
265 # Return the execution counter so clients can display prompts
265 # Return the execution counter so clients can display prompts
266 reply_content['execution_count'] = shell.execution_count -1
266 reply_content['execution_count'] = shell.execution_count -1
267
267
268 # FIXME - fish exception info out of shell, possibly left there by
268 # FIXME - fish exception info out of shell, possibly left there by
269 # runlines. We'll need to clean up this logic later.
269 # runlines. We'll need to clean up this logic later.
270 if shell._reply_content is not None:
270 if shell._reply_content is not None:
271 reply_content.update(shell._reply_content)
271 reply_content.update(shell._reply_content)
272 # reset after use
272 # reset after use
273 shell._reply_content = None
273 shell._reply_content = None
274
274
275 # At this point, we can tell whether the main code execution succeeded
275 # At this point, we can tell whether the main code execution succeeded
276 # or not. If it did, we proceed to evaluate user_variables/expressions
276 # or not. If it did, we proceed to evaluate user_variables/expressions
277 if reply_content['status'] == 'ok':
277 if reply_content['status'] == 'ok':
278 reply_content[u'user_variables'] = \
278 reply_content[u'user_variables'] = \
279 shell.user_variables(content[u'user_variables'])
279 shell.user_variables(content[u'user_variables'])
280 reply_content[u'user_expressions'] = \
280 reply_content[u'user_expressions'] = \
281 shell.user_expressions(content[u'user_expressions'])
281 shell.user_expressions(content[u'user_expressions'])
282 else:
282 else:
283 # If there was an error, don't even try to compute variables or
283 # If there was an error, don't even try to compute variables or
284 # expressions
284 # expressions
285 reply_content[u'user_variables'] = {}
285 reply_content[u'user_variables'] = {}
286 reply_content[u'user_expressions'] = {}
286 reply_content[u'user_expressions'] = {}
287
287
288 # Payloads should be retrieved regardless of outcome, so we can both
288 # Payloads should be retrieved regardless of outcome, so we can both
289 # recover partial output (that could have been generated early in a
289 # recover partial output (that could have been generated early in a
290 # block, before an error) and clear the payload system always.
290 # block, before an error) and clear the payload system always.
291 reply_content[u'payload'] = shell.payload_manager.read_payload()
291 reply_content[u'payload'] = shell.payload_manager.read_payload()
292 # Be agressive about clearing the payload because we don't want
292 # Be agressive about clearing the payload because we don't want
293 # it to sit in memory until the next execute_request comes in.
293 # it to sit in memory until the next execute_request comes in.
294 shell.payload_manager.clear_payload()
294 shell.payload_manager.clear_payload()
295
295
296 # Flush output before sending the reply.
296 # Flush output before sending the reply.
297 sys.stdout.flush()
297 sys.stdout.flush()
298 sys.stderr.flush()
298 sys.stderr.flush()
299 # FIXME: on rare occasions, the flush doesn't seem to make it to the
299 # FIXME: on rare occasions, the flush doesn't seem to make it to the
300 # clients... This seems to mitigate the problem, but we definitely need
300 # clients... This seems to mitigate the problem, but we definitely need
301 # to better understand what's going on.
301 # to better understand what's going on.
302 if self._execute_sleep:
302 if self._execute_sleep:
303 time.sleep(self._execute_sleep)
303 time.sleep(self._execute_sleep)
304
304
305 # Send the reply.
305 # Send the reply.
306 reply_content = json_clean(reply_content)
306 reply_msg = self.session.send(self.shell_socket, u'execute_reply',
307 reply_msg = self.session.send(self.shell_socket, u'execute_reply',
307 reply_content, parent, ident=ident)
308 reply_content, parent, ident=ident)
308 self.log.debug(str(reply_msg))
309 self.log.debug(str(reply_msg))
309
310
310 if reply_msg['content']['status'] == u'error':
311 if reply_msg['content']['status'] == u'error':
311 self._abort_queue()
312 self._abort_queue()
312
313
313 status_msg = self.session.send(self.iopub_socket,
314 status_msg = self.session.send(self.iopub_socket,
314 u'status',
315 u'status',
315 {u'execution_state':u'idle'},
316 {u'execution_state':u'idle'},
316 parent=parent
317 parent=parent
317 )
318 )
318
319
319 def complete_request(self, ident, parent):
320 def complete_request(self, ident, parent):
320 txt, matches = self._complete(parent)
321 txt, matches = self._complete(parent)
321 matches = {'matches' : matches,
322 matches = {'matches' : matches,
322 'matched_text' : txt,
323 'matched_text' : txt,
323 'status' : 'ok'}
324 'status' : 'ok'}
325 matches = json_clean(matches)
324 completion_msg = self.session.send(self.shell_socket, 'complete_reply',
326 completion_msg = self.session.send(self.shell_socket, 'complete_reply',
325 matches, parent, ident)
327 matches, parent, ident)
326 self.log.debug(str(completion_msg))
328 self.log.debug(str(completion_msg))
327
329
328 def object_info_request(self, ident, parent):
330 def object_info_request(self, ident, parent):
329 object_info = self.shell.object_inspect(parent['content']['oname'])
331 object_info = self.shell.object_inspect(parent['content']['oname'])
330 # Before we send this object over, we scrub it for JSON usage
332 # Before we send this object over, we scrub it for JSON usage
331 oinfo = json_clean(object_info)
333 oinfo = json_clean(object_info)
332 msg = self.session.send(self.shell_socket, 'object_info_reply',
334 msg = self.session.send(self.shell_socket, 'object_info_reply',
333 oinfo, parent, ident)
335 oinfo, parent, ident)
334 self.log.debug(msg)
336 self.log.debug(msg)
335
337
336 def history_request(self, ident, parent):
338 def history_request(self, ident, parent):
337 # We need to pull these out, as passing **kwargs doesn't work with
339 # We need to pull these out, as passing **kwargs doesn't work with
338 # unicode keys before Python 2.6.5.
340 # unicode keys before Python 2.6.5.
339 hist_access_type = parent['content']['hist_access_type']
341 hist_access_type = parent['content']['hist_access_type']
340 raw = parent['content']['raw']
342 raw = parent['content']['raw']
341 output = parent['content']['output']
343 output = parent['content']['output']
342 if hist_access_type == 'tail':
344 if hist_access_type == 'tail':
343 n = parent['content']['n']
345 n = parent['content']['n']
344 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
346 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
345 include_latest=True)
347 include_latest=True)
346
348
347 elif hist_access_type == 'range':
349 elif hist_access_type == 'range':
348 session = parent['content']['session']
350 session = parent['content']['session']
349 start = parent['content']['start']
351 start = parent['content']['start']
350 stop = parent['content']['stop']
352 stop = parent['content']['stop']
351 hist = self.shell.history_manager.get_range(session, start, stop,
353 hist = self.shell.history_manager.get_range(session, start, stop,
352 raw=raw, output=output)
354 raw=raw, output=output)
353
355
354 elif hist_access_type == 'search':
356 elif hist_access_type == 'search':
355 pattern = parent['content']['pattern']
357 pattern = parent['content']['pattern']
356 hist = self.shell.history_manager.search(pattern, raw=raw, output=output)
358 hist = self.shell.history_manager.search(pattern, raw=raw, output=output)
357
359
358 else:
360 else:
359 hist = []
361 hist = []
360 content = {'history' : list(hist)}
362 content = {'history' : list(hist)}
363 content = json_clean(content)
361 msg = self.session.send(self.shell_socket, 'history_reply',
364 msg = self.session.send(self.shell_socket, 'history_reply',
362 content, parent, ident)
365 content, parent, ident)
363 self.log.debug(str(msg))
366 self.log.debug(str(msg))
364
367
365 def connect_request(self, ident, parent):
368 def connect_request(self, ident, parent):
366 if self._recorded_ports is not None:
369 if self._recorded_ports is not None:
367 content = self._recorded_ports.copy()
370 content = self._recorded_ports.copy()
368 else:
371 else:
369 content = {}
372 content = {}
370 msg = self.session.send(self.shell_socket, 'connect_reply',
373 msg = self.session.send(self.shell_socket, 'connect_reply',
371 content, parent, ident)
374 content, parent, ident)
372 self.log.debug(msg)
375 self.log.debug(msg)
373
376
374 def shutdown_request(self, ident, parent):
377 def shutdown_request(self, ident, parent):
375 self.shell.exit_now = True
378 self.shell.exit_now = True
376 self._shutdown_message = self.session.msg(u'shutdown_reply', parent['content'], parent)
379 self._shutdown_message = self.session.msg(u'shutdown_reply', parent['content'], parent)
377 sys.exit(0)
380 sys.exit(0)
378
381
379 #---------------------------------------------------------------------------
382 #---------------------------------------------------------------------------
380 # Protected interface
383 # Protected interface
381 #---------------------------------------------------------------------------
384 #---------------------------------------------------------------------------
382
385
383 def _abort_queue(self):
386 def _abort_queue(self):
384 while True:
387 while True:
385 try:
388 try:
386 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
389 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
387 except Exception:
390 except Exception:
388 self.log.warn("Invalid Message:", exc_info=True)
391 self.log.warn("Invalid Message:", exc_info=True)
389 continue
392 continue
390 if msg is None:
393 if msg is None:
391 break
394 break
392 else:
395 else:
393 assert ident is not None, \
396 assert ident is not None, \
394 "Unexpected missing message part."
397 "Unexpected missing message part."
395
398
396 self.log.debug("Aborting:\n"+str(Message(msg)))
399 self.log.debug("Aborting:\n"+str(Message(msg)))
397 msg_type = msg['header']['msg_type']
400 msg_type = msg['header']['msg_type']
398 reply_type = msg_type.split('_')[0] + '_reply'
401 reply_type = msg_type.split('_')[0] + '_reply'
399 reply_msg = self.session.send(self.shell_socket, reply_type,
402 reply_msg = self.session.send(self.shell_socket, reply_type,
400 {'status' : 'aborted'}, msg, ident=ident)
403 {'status' : 'aborted'}, msg, ident=ident)
401 self.log.debug(reply_msg)
404 self.log.debug(reply_msg)
402 # We need to wait a bit for requests to come in. This can probably
405 # We need to wait a bit for requests to come in. This can probably
403 # be set shorter for true asynchronous clients.
406 # be set shorter for true asynchronous clients.
404 time.sleep(0.1)
407 time.sleep(0.1)
405
408
406 def _raw_input(self, prompt, ident, parent):
409 def _raw_input(self, prompt, ident, parent):
407 # Flush output before making the request.
410 # Flush output before making the request.
408 sys.stderr.flush()
411 sys.stderr.flush()
409 sys.stdout.flush()
412 sys.stdout.flush()
410
413
411 # Send the input request.
414 # Send the input request.
412 content = dict(prompt=prompt)
415 content = json_clean(dict(prompt=prompt))
413 msg = self.session.send(self.stdin_socket, u'input_request', content, parent)
416 msg = self.session.send(self.stdin_socket, u'input_request', content, parent)
414
417
415 # Await a response.
418 # Await a response.
416 while True:
419 while True:
417 try:
420 try:
418 ident, reply = self.session.recv(self.stdin_socket, 0)
421 ident, reply = self.session.recv(self.stdin_socket, 0)
419 except Exception:
422 except Exception:
420 self.log.warn("Invalid Message:", exc_info=True)
423 self.log.warn("Invalid Message:", exc_info=True)
421 else:
424 else:
422 break
425 break
423 try:
426 try:
424 value = reply['content']['value']
427 value = reply['content']['value']
425 except:
428 except:
426 self.log.error("Got bad raw_input reply: ")
429 self.log.error("Got bad raw_input reply: ")
427 self.log.error(str(Message(parent)))
430 self.log.error(str(Message(parent)))
428 value = ''
431 value = ''
429 return value
432 return value
430
433
431 def _complete(self, msg):
434 def _complete(self, msg):
432 c = msg['content']
435 c = msg['content']
433 try:
436 try:
434 cpos = int(c['cursor_pos'])
437 cpos = int(c['cursor_pos'])
435 except:
438 except:
436 # If we don't get something that we can convert to an integer, at
439 # If we don't get something that we can convert to an integer, at
437 # least attempt the completion guessing the cursor is at the end of
440 # least attempt the completion guessing the cursor is at the end of
438 # the text, if there's any, and otherwise of the line
441 # the text, if there's any, and otherwise of the line
439 cpos = len(c['text'])
442 cpos = len(c['text'])
440 if cpos==0:
443 if cpos==0:
441 cpos = len(c['line'])
444 cpos = len(c['line'])
442 return self.shell.complete(c['text'], c['line'], cpos)
445 return self.shell.complete(c['text'], c['line'], cpos)
443
446
444 def _object_info(self, context):
447 def _object_info(self, context):
445 symbol, leftover = self._symbol_from_context(context)
448 symbol, leftover = self._symbol_from_context(context)
446 if symbol is not None and not leftover:
449 if symbol is not None and not leftover:
447 doc = getattr(symbol, '__doc__', '')
450 doc = getattr(symbol, '__doc__', '')
448 else:
451 else:
449 doc = ''
452 doc = ''
450 object_info = dict(docstring = doc)
453 object_info = dict(docstring = doc)
451 return object_info
454 return object_info
452
455
453 def _symbol_from_context(self, context):
456 def _symbol_from_context(self, context):
454 if not context:
457 if not context:
455 return None, context
458 return None, context
456
459
457 base_symbol_string = context[0]
460 base_symbol_string = context[0]
458 symbol = self.shell.user_ns.get(base_symbol_string, None)
461 symbol = self.shell.user_ns.get(base_symbol_string, None)
459 if symbol is None:
462 if symbol is None:
460 symbol = __builtin__.__dict__.get(base_symbol_string, None)
463 symbol = __builtin__.__dict__.get(base_symbol_string, None)
461 if symbol is None:
464 if symbol is None:
462 return None, context
465 return None, context
463
466
464 context = context[1:]
467 context = context[1:]
465 for i, name in enumerate(context):
468 for i, name in enumerate(context):
466 new_symbol = getattr(symbol, name, None)
469 new_symbol = getattr(symbol, name, None)
467 if new_symbol is None:
470 if new_symbol is None:
468 return symbol, context[i:]
471 return symbol, context[i:]
469 else:
472 else:
470 symbol = new_symbol
473 symbol = new_symbol
471
474
472 return symbol, []
475 return symbol, []
473
476
474 def _at_shutdown(self):
477 def _at_shutdown(self):
475 """Actions taken at shutdown by the kernel, called by python's atexit.
478 """Actions taken at shutdown by the kernel, called by python's atexit.
476 """
479 """
477 # io.rprint("Kernel at_shutdown") # dbg
480 # io.rprint("Kernel at_shutdown") # dbg
478 if self._shutdown_message is not None:
481 if self._shutdown_message is not None:
479 self.session.send(self.shell_socket, self._shutdown_message)
482 self.session.send(self.shell_socket, self._shutdown_message)
480 self.session.send(self.iopub_socket, self._shutdown_message)
483 self.session.send(self.iopub_socket, self._shutdown_message)
481 self.log.debug(str(self._shutdown_message))
484 self.log.debug(str(self._shutdown_message))
482 # A very short sleep to give zmq time to flush its message buffers
485 # A very short sleep to give zmq time to flush its message buffers
483 # before Python truly shuts down.
486 # before Python truly shuts down.
484 time.sleep(0.01)
487 time.sleep(0.01)
485
488
486
489
487 class QtKernel(Kernel):
490 class QtKernel(Kernel):
488 """A Kernel subclass with Qt support."""
491 """A Kernel subclass with Qt support."""
489
492
490 def start(self):
493 def start(self):
491 """Start a kernel with QtPy4 event loop integration."""
494 """Start a kernel with QtPy4 event loop integration."""
492
495
493 from IPython.external.qt_for_kernel import QtCore
496 from IPython.external.qt_for_kernel import QtCore
494 from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
497 from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
495
498
496 self.app = get_app_qt4([" "])
499 self.app = get_app_qt4([" "])
497 self.app.setQuitOnLastWindowClosed(False)
500 self.app.setQuitOnLastWindowClosed(False)
498 self.timer = QtCore.QTimer()
501 self.timer = QtCore.QTimer()
499 self.timer.timeout.connect(self.do_one_iteration)
502 self.timer.timeout.connect(self.do_one_iteration)
500 # Units for the timer are in milliseconds
503 # Units for the timer are in milliseconds
501 self.timer.start(1000*self._poll_interval)
504 self.timer.start(1000*self._poll_interval)
502 start_event_loop_qt4(self.app)
505 start_event_loop_qt4(self.app)
503
506
504
507
505 class WxKernel(Kernel):
508 class WxKernel(Kernel):
506 """A Kernel subclass with Wx support."""
509 """A Kernel subclass with Wx support."""
507
510
508 def start(self):
511 def start(self):
509 """Start a kernel with wx event loop support."""
512 """Start a kernel with wx event loop support."""
510
513
511 import wx
514 import wx
512 from IPython.lib.guisupport import start_event_loop_wx
515 from IPython.lib.guisupport import start_event_loop_wx
513
516
514 doi = self.do_one_iteration
517 doi = self.do_one_iteration
515 # Wx uses milliseconds
518 # Wx uses milliseconds
516 poll_interval = int(1000*self._poll_interval)
519 poll_interval = int(1000*self._poll_interval)
517
520
518 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
521 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
519 # We make the Frame hidden when we create it in the main app below.
522 # We make the Frame hidden when we create it in the main app below.
520 class TimerFrame(wx.Frame):
523 class TimerFrame(wx.Frame):
521 def __init__(self, func):
524 def __init__(self, func):
522 wx.Frame.__init__(self, None, -1)
525 wx.Frame.__init__(self, None, -1)
523 self.timer = wx.Timer(self)
526 self.timer = wx.Timer(self)
524 # Units for the timer are in milliseconds
527 # Units for the timer are in milliseconds
525 self.timer.Start(poll_interval)
528 self.timer.Start(poll_interval)
526 self.Bind(wx.EVT_TIMER, self.on_timer)
529 self.Bind(wx.EVT_TIMER, self.on_timer)
527 self.func = func
530 self.func = func
528
531
529 def on_timer(self, event):
532 def on_timer(self, event):
530 self.func()
533 self.func()
531
534
532 # We need a custom wx.App to create our Frame subclass that has the
535 # We need a custom wx.App to create our Frame subclass that has the
533 # wx.Timer to drive the ZMQ event loop.
536 # wx.Timer to drive the ZMQ event loop.
534 class IPWxApp(wx.App):
537 class IPWxApp(wx.App):
535 def OnInit(self):
538 def OnInit(self):
536 self.frame = TimerFrame(doi)
539 self.frame = TimerFrame(doi)
537 self.frame.Show(False)
540 self.frame.Show(False)
538 return True
541 return True
539
542
540 # The redirect=False here makes sure that wx doesn't replace
543 # The redirect=False here makes sure that wx doesn't replace
541 # sys.stdout/stderr with its own classes.
544 # sys.stdout/stderr with its own classes.
542 self.app = IPWxApp(redirect=False)
545 self.app = IPWxApp(redirect=False)
543 start_event_loop_wx(self.app)
546 start_event_loop_wx(self.app)
544
547
545
548
546 class TkKernel(Kernel):
549 class TkKernel(Kernel):
547 """A Kernel subclass with Tk support."""
550 """A Kernel subclass with Tk support."""
548
551
549 def start(self):
552 def start(self):
550 """Start a Tk enabled event loop."""
553 """Start a Tk enabled event loop."""
551
554
552 import Tkinter
555 import Tkinter
553 doi = self.do_one_iteration
556 doi = self.do_one_iteration
554 # Tk uses milliseconds
557 # Tk uses milliseconds
555 poll_interval = int(1000*self._poll_interval)
558 poll_interval = int(1000*self._poll_interval)
556 # For Tkinter, we create a Tk object and call its withdraw method.
559 # For Tkinter, we create a Tk object and call its withdraw method.
557 class Timer(object):
560 class Timer(object):
558 def __init__(self, func):
561 def __init__(self, func):
559 self.app = Tkinter.Tk()
562 self.app = Tkinter.Tk()
560 self.app.withdraw()
563 self.app.withdraw()
561 self.func = func
564 self.func = func
562
565
563 def on_timer(self):
566 def on_timer(self):
564 self.func()
567 self.func()
565 self.app.after(poll_interval, self.on_timer)
568 self.app.after(poll_interval, self.on_timer)
566
569
567 def start(self):
570 def start(self):
568 self.on_timer() # Call it once to get things going.
571 self.on_timer() # Call it once to get things going.
569 self.app.mainloop()
572 self.app.mainloop()
570
573
571 self.timer = Timer(doi)
574 self.timer = Timer(doi)
572 self.timer.start()
575 self.timer.start()
573
576
574
577
575 class GTKKernel(Kernel):
578 class GTKKernel(Kernel):
576 """A Kernel subclass with GTK support."""
579 """A Kernel subclass with GTK support."""
577
580
578 def start(self):
581 def start(self):
579 """Start the kernel, coordinating with the GTK event loop"""
582 """Start the kernel, coordinating with the GTK event loop"""
580 from .gui.gtkembed import GTKEmbed
583 from .gui.gtkembed import GTKEmbed
581
584
582 gtk_kernel = GTKEmbed(self)
585 gtk_kernel = GTKEmbed(self)
583 gtk_kernel.start()
586 gtk_kernel.start()
584
587
585
588
586 #-----------------------------------------------------------------------------
589 #-----------------------------------------------------------------------------
587 # Aliases and Flags for the IPKernelApp
590 # Aliases and Flags for the IPKernelApp
588 #-----------------------------------------------------------------------------
591 #-----------------------------------------------------------------------------
589
592
590 flags = dict(kernel_flags)
593 flags = dict(kernel_flags)
591 flags.update(shell_flags)
594 flags.update(shell_flags)
592
595
593 addflag = lambda *args: flags.update(boolean_flag(*args))
596 addflag = lambda *args: flags.update(boolean_flag(*args))
594
597
595 flags['pylab'] = (
598 flags['pylab'] = (
596 {'IPKernelApp' : {'pylab' : 'auto'}},
599 {'IPKernelApp' : {'pylab' : 'auto'}},
597 """Pre-load matplotlib and numpy for interactive use with
600 """Pre-load matplotlib and numpy for interactive use with
598 the default matplotlib backend."""
601 the default matplotlib backend."""
599 )
602 )
600
603
601 aliases = dict(kernel_aliases)
604 aliases = dict(kernel_aliases)
602 aliases.update(shell_aliases)
605 aliases.update(shell_aliases)
603
606
604 # it's possible we don't want short aliases for *all* of these:
607 # it's possible we don't want short aliases for *all* of these:
605 aliases.update(dict(
608 aliases.update(dict(
606 pylab='IPKernelApp.pylab',
609 pylab='IPKernelApp.pylab',
607 ))
610 ))
608
611
609 #-----------------------------------------------------------------------------
612 #-----------------------------------------------------------------------------
610 # The IPKernelApp class
613 # The IPKernelApp class
611 #-----------------------------------------------------------------------------
614 #-----------------------------------------------------------------------------
612
615
613 class IPKernelApp(KernelApp, InteractiveShellApp):
616 class IPKernelApp(KernelApp, InteractiveShellApp):
614 name = 'ipkernel'
617 name = 'ipkernel'
615
618
616 aliases = Dict(aliases)
619 aliases = Dict(aliases)
617 flags = Dict(flags)
620 flags = Dict(flags)
618 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
621 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
619 # configurables
622 # configurables
620 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'],
623 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'],
621 config=True,
624 config=True,
622 help="""Pre-load matplotlib and numpy for interactive use,
625 help="""Pre-load matplotlib and numpy for interactive use,
623 selecting a particular matplotlib backend and loop integration.
626 selecting a particular matplotlib backend and loop integration.
624 """
627 """
625 )
628 )
626 def initialize(self, argv=None):
629 def initialize(self, argv=None):
627 super(IPKernelApp, self).initialize(argv)
630 super(IPKernelApp, self).initialize(argv)
628 self.init_shell()
631 self.init_shell()
629 self.init_extensions()
632 self.init_extensions()
630 self.init_code()
633 self.init_code()
631
634
632 def init_kernel(self):
635 def init_kernel(self):
633 kernel_factory = Kernel
636 kernel_factory = Kernel
634
637
635 kernel_map = {
638 kernel_map = {
636 'qt' : QtKernel,
639 'qt' : QtKernel,
637 'qt4': QtKernel,
640 'qt4': QtKernel,
638 'inline': Kernel,
641 'inline': Kernel,
639 'osx': TkKernel,
642 'osx': TkKernel,
640 'wx' : WxKernel,
643 'wx' : WxKernel,
641 'tk' : TkKernel,
644 'tk' : TkKernel,
642 'gtk': GTKKernel,
645 'gtk': GTKKernel,
643 }
646 }
644
647
645 if self.pylab:
648 if self.pylab:
646 key = None if self.pylab == 'auto' else self.pylab
649 key = None if self.pylab == 'auto' else self.pylab
647 gui, backend = pylabtools.find_gui_and_backend(key)
650 gui, backend = pylabtools.find_gui_and_backend(key)
648 kernel_factory = kernel_map.get(gui)
651 kernel_factory = kernel_map.get(gui)
649 if kernel_factory is None:
652 if kernel_factory is None:
650 raise ValueError('GUI is not supported: %r' % gui)
653 raise ValueError('GUI is not supported: %r' % gui)
651 pylabtools.activate_matplotlib(backend)
654 pylabtools.activate_matplotlib(backend)
652
655
653 kernel = kernel_factory(config=self.config, session=self.session,
656 kernel = kernel_factory(config=self.config, session=self.session,
654 shell_socket=self.shell_socket,
657 shell_socket=self.shell_socket,
655 iopub_socket=self.iopub_socket,
658 iopub_socket=self.iopub_socket,
656 stdin_socket=self.stdin_socket,
659 stdin_socket=self.stdin_socket,
657 log=self.log
660 log=self.log
658 )
661 )
659 self.kernel = kernel
662 self.kernel = kernel
660 kernel.record_ports(self.ports)
663 kernel.record_ports(self.ports)
661
664
662 if self.pylab:
665 if self.pylab:
663 import_all = self.pylab_import_all
666 import_all = self.pylab_import_all
664 pylabtools.import_pylab(kernel.shell.user_ns, backend, import_all,
667 pylabtools.import_pylab(kernel.shell.user_ns, backend, import_all,
665 shell=kernel.shell)
668 shell=kernel.shell)
666
669
667 def init_shell(self):
670 def init_shell(self):
668 self.shell = self.kernel.shell
671 self.shell = self.kernel.shell
669
672
670
673
671 #-----------------------------------------------------------------------------
674 #-----------------------------------------------------------------------------
672 # Kernel main and launch functions
675 # Kernel main and launch functions
673 #-----------------------------------------------------------------------------
676 #-----------------------------------------------------------------------------
674
677
675 def launch_kernel(*args, **kwargs):
678 def launch_kernel(*args, **kwargs):
676 """Launches a localhost IPython kernel, binding to the specified ports.
679 """Launches a localhost IPython kernel, binding to the specified ports.
677
680
678 This function simply calls entry_point.base_launch_kernel with the right first
681 This function simply calls entry_point.base_launch_kernel with the right first
679 command to start an ipkernel. See base_launch_kernel for arguments.
682 command to start an ipkernel. See base_launch_kernel for arguments.
680
683
681 Returns
684 Returns
682 -------
685 -------
683 A tuple of form:
686 A tuple of form:
684 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
687 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
685 where kernel_process is a Popen object and the ports are integers.
688 where kernel_process is a Popen object and the ports are integers.
686 """
689 """
687 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
690 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
688 *args, **kwargs)
691 *args, **kwargs)
689
692
690
693
691 def main():
694 def main():
692 """Run an IPKernel as an application"""
695 """Run an IPKernel as an application"""
693 app = IPKernelApp.instance()
696 app = IPKernelApp.instance()
694 app.initialize()
697 app.initialize()
695 app.start()
698 app.start()
696
699
697
700
698 if __name__ == '__main__':
701 if __name__ == '__main__':
699 main()
702 main()
@@ -1,441 +1,442 b''
1 """A ZMQ-based subclass of InteractiveShell.
1 """A ZMQ-based subclass of InteractiveShell.
2
2
3 This code is meant to ease the refactoring of the base InteractiveShell into
3 This code is meant to ease the refactoring of the base InteractiveShell into
4 something with a cleaner architecture for 2-process use, without actually
4 something with a cleaner architecture for 2-process use, without actually
5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
6 we subclass and override what we want to fix. Once this is working well, we
6 we subclass and override what we want to fix. Once this is working well, we
7 can go back to the base class and refactor the code for a cleaner inheritance
7 can go back to the base class and refactor the code for a cleaner inheritance
8 implementation that doesn't rely on so much monkeypatching.
8 implementation that doesn't rely on so much monkeypatching.
9
9
10 But this lets us maintain a fully working IPython as we develop the new
10 But this lets us maintain a fully working IPython as we develop the new
11 machinery. This should thus be thought of as scaffolding.
11 machinery. This should thus be thought of as scaffolding.
12 """
12 """
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Stdlib
18 # Stdlib
19 import inspect
19 import inspect
20 import os
20 import os
21
21
22 # Our own
22 # Our own
23 from IPython.core.interactiveshell import (
23 from IPython.core.interactiveshell import (
24 InteractiveShell, InteractiveShellABC
24 InteractiveShell, InteractiveShellABC
25 )
25 )
26 from IPython.core import page
26 from IPython.core import page
27 from IPython.core.autocall import ZMQExitAutocall
27 from IPython.core.autocall import ZMQExitAutocall
28 from IPython.core.displaypub import DisplayPublisher
28 from IPython.core.displaypub import DisplayPublisher
29 from IPython.core.macro import Macro
29 from IPython.core.macro import Macro
30 from IPython.core.magic import MacroToEdit
30 from IPython.core.magic import MacroToEdit
31 from IPython.core.payloadpage import install_payload_page
31 from IPython.core.payloadpage import install_payload_page
32 from IPython.utils import io
32 from IPython.utils import io
33 from IPython.utils.jsonutil import json_clean
33 from IPython.utils.path import get_py_filename
34 from IPython.utils.path import get_py_filename
34 from IPython.utils.traitlets import Instance, Type, Dict, CBool
35 from IPython.utils.traitlets import Instance, Type, Dict, CBool
35 from IPython.utils.warn import warn
36 from IPython.utils.warn import warn
36 from IPython.zmq.displayhook import ZMQShellDisplayHook, _encode_binary
37 from IPython.zmq.displayhook import ZMQShellDisplayHook, _encode_binary
37 from IPython.zmq.session import extract_header
38 from IPython.zmq.session import extract_header
38 from session import Session
39 from session import Session
39
40
40 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
41 # Globals and side-effects
42 # Globals and side-effects
42 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
43
44
44 # Install the payload version of page.
45 # Install the payload version of page.
45 install_payload_page()
46 install_payload_page()
46
47
47 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
48 # Functions and classes
49 # Functions and classes
49 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
50
51
51 class ZMQDisplayPublisher(DisplayPublisher):
52 class ZMQDisplayPublisher(DisplayPublisher):
52 """A display publisher that publishes data using a ZeroMQ PUB socket."""
53 """A display publisher that publishes data using a ZeroMQ PUB socket."""
53
54
54 session = Instance(Session)
55 session = Instance(Session)
55 pub_socket = Instance('zmq.Socket')
56 pub_socket = Instance('zmq.Socket')
56 parent_header = Dict({})
57 parent_header = Dict({})
57
58
58 def set_parent(self, parent):
59 def set_parent(self, parent):
59 """Set the parent for outbound messages."""
60 """Set the parent for outbound messages."""
60 self.parent_header = extract_header(parent)
61 self.parent_header = extract_header(parent)
61
62
62 def publish(self, source, data, metadata=None):
63 def publish(self, source, data, metadata=None):
63 if metadata is None:
64 if metadata is None:
64 metadata = {}
65 metadata = {}
65 self._validate_data(source, data, metadata)
66 self._validate_data(source, data, metadata)
66 content = {}
67 content = {}
67 content['source'] = source
68 content['source'] = source
68 _encode_binary(data)
69 _encode_binary(data)
69 content['data'] = data
70 content['data'] = data
70 content['metadata'] = metadata
71 content['metadata'] = metadata
71 self.session.send(
72 self.session.send(
72 self.pub_socket, u'display_data', content,
73 self.pub_socket, u'display_data', json_clean(content),
73 parent=self.parent_header
74 parent=self.parent_header
74 )
75 )
75
76
76
77
77 class ZMQInteractiveShell(InteractiveShell):
78 class ZMQInteractiveShell(InteractiveShell):
78 """A subclass of InteractiveShell for ZMQ."""
79 """A subclass of InteractiveShell for ZMQ."""
79
80
80 displayhook_class = Type(ZMQShellDisplayHook)
81 displayhook_class = Type(ZMQShellDisplayHook)
81 display_pub_class = Type(ZMQDisplayPublisher)
82 display_pub_class = Type(ZMQDisplayPublisher)
82
83
83 # Override the traitlet in the parent class, because there's no point using
84 # Override the traitlet in the parent class, because there's no point using
84 # readline for the kernel. Can be removed when the readline code is moved
85 # readline for the kernel. Can be removed when the readline code is moved
85 # to the terminal frontend.
86 # to the terminal frontend.
86
87
87 # FIXME. This is disabled for now, even though it may cause problems under
88 # FIXME. This is disabled for now, even though it may cause problems under
88 # Windows, because it breaks %run in the Qt console. See gh-617 for more
89 # Windows, because it breaks %run in the Qt console. See gh-617 for more
89 # details. Re-enable once we've fully tested that %run works in the Qt
90 # details. Re-enable once we've fully tested that %run works in the Qt
90 # console with syntax highlighting in tracebacks.
91 # console with syntax highlighting in tracebacks.
91 # readline_use = CBool(False)
92 # readline_use = CBool(False)
92 # /FIXME
93 # /FIXME
93
94
94 exiter = Instance(ZMQExitAutocall)
95 exiter = Instance(ZMQExitAutocall)
95 def _exiter_default(self):
96 def _exiter_default(self):
96 return ZMQExitAutocall(self)
97 return ZMQExitAutocall(self)
97
98
98 keepkernel_on_exit = None
99 keepkernel_on_exit = None
99
100
100 def init_environment(self):
101 def init_environment(self):
101 """Configure the user's environment.
102 """Configure the user's environment.
102
103
103 """
104 """
104 env = os.environ
105 env = os.environ
105 # These two ensure 'ls' produces nice coloring on BSD-derived systems
106 # These two ensure 'ls' produces nice coloring on BSD-derived systems
106 env['TERM'] = 'xterm-color'
107 env['TERM'] = 'xterm-color'
107 env['CLICOLOR'] = '1'
108 env['CLICOLOR'] = '1'
108 # Since normal pagers don't work at all (over pexpect we don't have
109 # Since normal pagers don't work at all (over pexpect we don't have
109 # single-key control of the subprocess), try to disable paging in
110 # single-key control of the subprocess), try to disable paging in
110 # subprocesses as much as possible.
111 # subprocesses as much as possible.
111 env['PAGER'] = 'cat'
112 env['PAGER'] = 'cat'
112 env['GIT_PAGER'] = 'cat'
113 env['GIT_PAGER'] = 'cat'
113
114
114 def auto_rewrite_input(self, cmd):
115 def auto_rewrite_input(self, cmd):
115 """Called to show the auto-rewritten input for autocall and friends.
116 """Called to show the auto-rewritten input for autocall and friends.
116
117
117 FIXME: this payload is currently not correctly processed by the
118 FIXME: this payload is currently not correctly processed by the
118 frontend.
119 frontend.
119 """
120 """
120 new = self.displayhook.prompt1.auto_rewrite() + cmd
121 new = self.displayhook.prompt1.auto_rewrite() + cmd
121 payload = dict(
122 payload = dict(
122 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
123 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
123 transformed_input=new,
124 transformed_input=new,
124 )
125 )
125 self.payload_manager.write_payload(payload)
126 self.payload_manager.write_payload(payload)
126
127
127 def ask_exit(self):
128 def ask_exit(self):
128 """Engage the exit actions."""
129 """Engage the exit actions."""
129 payload = dict(
130 payload = dict(
130 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
131 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
131 exit=True,
132 exit=True,
132 keepkernel=self.keepkernel_on_exit,
133 keepkernel=self.keepkernel_on_exit,
133 )
134 )
134 self.payload_manager.write_payload(payload)
135 self.payload_manager.write_payload(payload)
135
136
136 def _showtraceback(self, etype, evalue, stb):
137 def _showtraceback(self, etype, evalue, stb):
137
138
138 exc_content = {
139 exc_content = {
139 u'traceback' : stb,
140 u'traceback' : stb,
140 u'ename' : unicode(etype.__name__),
141 u'ename' : unicode(etype.__name__),
141 u'evalue' : unicode(evalue)
142 u'evalue' : unicode(evalue)
142 }
143 }
143
144
144 dh = self.displayhook
145 dh = self.displayhook
145 # Send exception info over pub socket for other clients than the caller
146 # Send exception info over pub socket for other clients than the caller
146 # to pick up
147 # to pick up
147 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', exc_content, dh.parent_header)
148 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header)
148
149
149 # FIXME - Hack: store exception info in shell object. Right now, the
150 # FIXME - Hack: store exception info in shell object. Right now, the
150 # caller is reading this info after the fact, we need to fix this logic
151 # caller is reading this info after the fact, we need to fix this logic
151 # to remove this hack. Even uglier, we need to store the error status
152 # to remove this hack. Even uglier, we need to store the error status
152 # here, because in the main loop, the logic that sets it is being
153 # here, because in the main loop, the logic that sets it is being
153 # skipped because runlines swallows the exceptions.
154 # skipped because runlines swallows the exceptions.
154 exc_content[u'status'] = u'error'
155 exc_content[u'status'] = u'error'
155 self._reply_content = exc_content
156 self._reply_content = exc_content
156 # /FIXME
157 # /FIXME
157
158
158 return exc_content
159 return exc_content
159
160
160 #------------------------------------------------------------------------
161 #------------------------------------------------------------------------
161 # Magic overrides
162 # Magic overrides
162 #------------------------------------------------------------------------
163 #------------------------------------------------------------------------
163 # Once the base class stops inheriting from magic, this code needs to be
164 # Once the base class stops inheriting from magic, this code needs to be
164 # moved into a separate machinery as well. For now, at least isolate here
165 # moved into a separate machinery as well. For now, at least isolate here
165 # the magics which this class needs to implement differently from the base
166 # the magics which this class needs to implement differently from the base
166 # class, or that are unique to it.
167 # class, or that are unique to it.
167
168
168 def magic_doctest_mode(self,parameter_s=''):
169 def magic_doctest_mode(self,parameter_s=''):
169 """Toggle doctest mode on and off.
170 """Toggle doctest mode on and off.
170
171
171 This mode is intended to make IPython behave as much as possible like a
172 This mode is intended to make IPython behave as much as possible like a
172 plain Python shell, from the perspective of how its prompts, exceptions
173 plain Python shell, from the perspective of how its prompts, exceptions
173 and output look. This makes it easy to copy and paste parts of a
174 and output look. This makes it easy to copy and paste parts of a
174 session into doctests. It does so by:
175 session into doctests. It does so by:
175
176
176 - Changing the prompts to the classic ``>>>`` ones.
177 - Changing the prompts to the classic ``>>>`` ones.
177 - Changing the exception reporting mode to 'Plain'.
178 - Changing the exception reporting mode to 'Plain'.
178 - Disabling pretty-printing of output.
179 - Disabling pretty-printing of output.
179
180
180 Note that IPython also supports the pasting of code snippets that have
181 Note that IPython also supports the pasting of code snippets that have
181 leading '>>>' and '...' prompts in them. This means that you can paste
182 leading '>>>' and '...' prompts in them. This means that you can paste
182 doctests from files or docstrings (even if they have leading
183 doctests from files or docstrings (even if they have leading
183 whitespace), and the code will execute correctly. You can then use
184 whitespace), and the code will execute correctly. You can then use
184 '%history -t' to see the translated history; this will give you the
185 '%history -t' to see the translated history; this will give you the
185 input after removal of all the leading prompts and whitespace, which
186 input after removal of all the leading prompts and whitespace, which
186 can be pasted back into an editor.
187 can be pasted back into an editor.
187
188
188 With these features, you can switch into this mode easily whenever you
189 With these features, you can switch into this mode easily whenever you
189 need to do testing and changes to doctests, without having to leave
190 need to do testing and changes to doctests, without having to leave
190 your existing IPython session.
191 your existing IPython session.
191 """
192 """
192
193
193 from IPython.utils.ipstruct import Struct
194 from IPython.utils.ipstruct import Struct
194
195
195 # Shorthands
196 # Shorthands
196 shell = self.shell
197 shell = self.shell
197 disp_formatter = self.shell.display_formatter
198 disp_formatter = self.shell.display_formatter
198 ptformatter = disp_formatter.formatters['text/plain']
199 ptformatter = disp_formatter.formatters['text/plain']
199 # dstore is a data store kept in the instance metadata bag to track any
200 # dstore is a data store kept in the instance metadata bag to track any
200 # changes we make, so we can undo them later.
201 # changes we make, so we can undo them later.
201 dstore = shell.meta.setdefault('doctest_mode', Struct())
202 dstore = shell.meta.setdefault('doctest_mode', Struct())
202 save_dstore = dstore.setdefault
203 save_dstore = dstore.setdefault
203
204
204 # save a few values we'll need to recover later
205 # save a few values we'll need to recover later
205 mode = save_dstore('mode', False)
206 mode = save_dstore('mode', False)
206 save_dstore('rc_pprint', ptformatter.pprint)
207 save_dstore('rc_pprint', ptformatter.pprint)
207 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
208 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
208 save_dstore('xmode', shell.InteractiveTB.mode)
209 save_dstore('xmode', shell.InteractiveTB.mode)
209
210
210 if mode == False:
211 if mode == False:
211 # turn on
212 # turn on
212 ptformatter.pprint = False
213 ptformatter.pprint = False
213 disp_formatter.plain_text_only = True
214 disp_formatter.plain_text_only = True
214 shell.magic_xmode('Plain')
215 shell.magic_xmode('Plain')
215 else:
216 else:
216 # turn off
217 # turn off
217 ptformatter.pprint = dstore.rc_pprint
218 ptformatter.pprint = dstore.rc_pprint
218 disp_formatter.plain_text_only = dstore.rc_plain_text_only
219 disp_formatter.plain_text_only = dstore.rc_plain_text_only
219 shell.magic_xmode(dstore.xmode)
220 shell.magic_xmode(dstore.xmode)
220
221
221 # Store new mode and inform on console
222 # Store new mode and inform on console
222 dstore.mode = bool(1-int(mode))
223 dstore.mode = bool(1-int(mode))
223 mode_label = ['OFF','ON'][dstore.mode]
224 mode_label = ['OFF','ON'][dstore.mode]
224 print('Doctest mode is:', mode_label)
225 print('Doctest mode is:', mode_label)
225
226
226 # Send the payload back so that clients can modify their prompt display
227 # Send the payload back so that clients can modify their prompt display
227 payload = dict(
228 payload = dict(
228 source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode',
229 source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode',
229 mode=dstore.mode)
230 mode=dstore.mode)
230 self.payload_manager.write_payload(payload)
231 self.payload_manager.write_payload(payload)
231
232
232 def magic_edit(self,parameter_s='',last_call=['','']):
233 def magic_edit(self,parameter_s='',last_call=['','']):
233 """Bring up an editor and execute the resulting code.
234 """Bring up an editor and execute the resulting code.
234
235
235 Usage:
236 Usage:
236 %edit [options] [args]
237 %edit [options] [args]
237
238
238 %edit runs an external text editor. You will need to set the command for
239 %edit runs an external text editor. You will need to set the command for
239 this editor via the ``TerminalInteractiveShell.editor`` option in your
240 this editor via the ``TerminalInteractiveShell.editor`` option in your
240 configuration file before it will work.
241 configuration file before it will work.
241
242
242 This command allows you to conveniently edit multi-line code right in
243 This command allows you to conveniently edit multi-line code right in
243 your IPython session.
244 your IPython session.
244
245
245 If called without arguments, %edit opens up an empty editor with a
246 If called without arguments, %edit opens up an empty editor with a
246 temporary file and will execute the contents of this file when you
247 temporary file and will execute the contents of this file when you
247 close it (don't forget to save it!).
248 close it (don't forget to save it!).
248
249
249
250
250 Options:
251 Options:
251
252
252 -n <number>: open the editor at a specified line number. By default,
253 -n <number>: open the editor at a specified line number. By default,
253 the IPython editor hook uses the unix syntax 'editor +N filename', but
254 the IPython editor hook uses the unix syntax 'editor +N filename', but
254 you can configure this by providing your own modified hook if your
255 you can configure this by providing your own modified hook if your
255 favorite editor supports line-number specifications with a different
256 favorite editor supports line-number specifications with a different
256 syntax.
257 syntax.
257
258
258 -p: this will call the editor with the same data as the previous time
259 -p: this will call the editor with the same data as the previous time
259 it was used, regardless of how long ago (in your current session) it
260 it was used, regardless of how long ago (in your current session) it
260 was.
261 was.
261
262
262 -r: use 'raw' input. This option only applies to input taken from the
263 -r: use 'raw' input. This option only applies to input taken from the
263 user's history. By default, the 'processed' history is used, so that
264 user's history. By default, the 'processed' history is used, so that
264 magics are loaded in their transformed version to valid Python. If
265 magics are loaded in their transformed version to valid Python. If
265 this option is given, the raw input as typed as the command line is
266 this option is given, the raw input as typed as the command line is
266 used instead. When you exit the editor, it will be executed by
267 used instead. When you exit the editor, it will be executed by
267 IPython's own processor.
268 IPython's own processor.
268
269
269 -x: do not execute the edited code immediately upon exit. This is
270 -x: do not execute the edited code immediately upon exit. This is
270 mainly useful if you are editing programs which need to be called with
271 mainly useful if you are editing programs which need to be called with
271 command line arguments, which you can then do using %run.
272 command line arguments, which you can then do using %run.
272
273
273
274
274 Arguments:
275 Arguments:
275
276
276 If arguments are given, the following possibilites exist:
277 If arguments are given, the following possibilites exist:
277
278
278 - The arguments are numbers or pairs of colon-separated numbers (like
279 - The arguments are numbers or pairs of colon-separated numbers (like
279 1 4:8 9). These are interpreted as lines of previous input to be
280 1 4:8 9). These are interpreted as lines of previous input to be
280 loaded into the editor. The syntax is the same of the %macro command.
281 loaded into the editor. The syntax is the same of the %macro command.
281
282
282 - If the argument doesn't start with a number, it is evaluated as a
283 - If the argument doesn't start with a number, it is evaluated as a
283 variable and its contents loaded into the editor. You can thus edit
284 variable and its contents loaded into the editor. You can thus edit
284 any string which contains python code (including the result of
285 any string which contains python code (including the result of
285 previous edits).
286 previous edits).
286
287
287 - If the argument is the name of an object (other than a string),
288 - If the argument is the name of an object (other than a string),
288 IPython will try to locate the file where it was defined and open the
289 IPython will try to locate the file where it was defined and open the
289 editor at the point where it is defined. You can use `%edit function`
290 editor at the point where it is defined. You can use `%edit function`
290 to load an editor exactly at the point where 'function' is defined,
291 to load an editor exactly at the point where 'function' is defined,
291 edit it and have the file be executed automatically.
292 edit it and have the file be executed automatically.
292
293
293 If the object is a macro (see %macro for details), this opens up your
294 If the object is a macro (see %macro for details), this opens up your
294 specified editor with a temporary file containing the macro's data.
295 specified editor with a temporary file containing the macro's data.
295 Upon exit, the macro is reloaded with the contents of the file.
296 Upon exit, the macro is reloaded with the contents of the file.
296
297
297 Note: opening at an exact line is only supported under Unix, and some
298 Note: opening at an exact line is only supported under Unix, and some
298 editors (like kedit and gedit up to Gnome 2.8) do not understand the
299 editors (like kedit and gedit up to Gnome 2.8) do not understand the
299 '+NUMBER' parameter necessary for this feature. Good editors like
300 '+NUMBER' parameter necessary for this feature. Good editors like
300 (X)Emacs, vi, jed, pico and joe all do.
301 (X)Emacs, vi, jed, pico and joe all do.
301
302
302 - If the argument is not found as a variable, IPython will look for a
303 - If the argument is not found as a variable, IPython will look for a
303 file with that name (adding .py if necessary) and load it into the
304 file with that name (adding .py if necessary) and load it into the
304 editor. It will execute its contents with execfile() when you exit,
305 editor. It will execute its contents with execfile() when you exit,
305 loading any code in the file into your interactive namespace.
306 loading any code in the file into your interactive namespace.
306
307
307 After executing your code, %edit will return as output the code you
308 After executing your code, %edit will return as output the code you
308 typed in the editor (except when it was an existing file). This way
309 typed in the editor (except when it was an existing file). This way
309 you can reload the code in further invocations of %edit as a variable,
310 you can reload the code in further invocations of %edit as a variable,
310 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
311 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
311 the output.
312 the output.
312
313
313 Note that %edit is also available through the alias %ed.
314 Note that %edit is also available through the alias %ed.
314
315
315 This is an example of creating a simple function inside the editor and
316 This is an example of creating a simple function inside the editor and
316 then modifying it. First, start up the editor:
317 then modifying it. First, start up the editor:
317
318
318 In [1]: ed
319 In [1]: ed
319 Editing... done. Executing edited code...
320 Editing... done. Executing edited code...
320 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
321 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
321
322
322 We can then call the function foo():
323 We can then call the function foo():
323
324
324 In [2]: foo()
325 In [2]: foo()
325 foo() was defined in an editing session
326 foo() was defined in an editing session
326
327
327 Now we edit foo. IPython automatically loads the editor with the
328 Now we edit foo. IPython automatically loads the editor with the
328 (temporary) file where foo() was previously defined:
329 (temporary) file where foo() was previously defined:
329
330
330 In [3]: ed foo
331 In [3]: ed foo
331 Editing... done. Executing edited code...
332 Editing... done. Executing edited code...
332
333
333 And if we call foo() again we get the modified version:
334 And if we call foo() again we get the modified version:
334
335
335 In [4]: foo()
336 In [4]: foo()
336 foo() has now been changed!
337 foo() has now been changed!
337
338
338 Here is an example of how to edit a code snippet successive
339 Here is an example of how to edit a code snippet successive
339 times. First we call the editor:
340 times. First we call the editor:
340
341
341 In [5]: ed
342 In [5]: ed
342 Editing... done. Executing edited code...
343 Editing... done. Executing edited code...
343 hello
344 hello
344 Out[5]: "print 'hello'n"
345 Out[5]: "print 'hello'n"
345
346
346 Now we call it again with the previous output (stored in _):
347 Now we call it again with the previous output (stored in _):
347
348
348 In [6]: ed _
349 In [6]: ed _
349 Editing... done. Executing edited code...
350 Editing... done. Executing edited code...
350 hello world
351 hello world
351 Out[6]: "print 'hello world'n"
352 Out[6]: "print 'hello world'n"
352
353
353 Now we call it with the output #8 (stored in _8, also as Out[8]):
354 Now we call it with the output #8 (stored in _8, also as Out[8]):
354
355
355 In [7]: ed _8
356 In [7]: ed _8
356 Editing... done. Executing edited code...
357 Editing... done. Executing edited code...
357 hello again
358 hello again
358 Out[7]: "print 'hello again'n"
359 Out[7]: "print 'hello again'n"
359 """
360 """
360
361
361 opts,args = self.parse_options(parameter_s,'prn:')
362 opts,args = self.parse_options(parameter_s,'prn:')
362
363
363 try:
364 try:
364 filename, lineno, _ = self._find_edit_target(args, opts, last_call)
365 filename, lineno, _ = self._find_edit_target(args, opts, last_call)
365 except MacroToEdit as e:
366 except MacroToEdit as e:
366 # TODO: Implement macro editing over 2 processes.
367 # TODO: Implement macro editing over 2 processes.
367 print("Macro editing not yet implemented in 2-process model.")
368 print("Macro editing not yet implemented in 2-process model.")
368 return
369 return
369
370
370 # Make sure we send to the client an absolute path, in case the working
371 # Make sure we send to the client an absolute path, in case the working
371 # directory of client and kernel don't match
372 # directory of client and kernel don't match
372 filename = os.path.abspath(filename)
373 filename = os.path.abspath(filename)
373
374
374 payload = {
375 payload = {
375 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
376 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
376 'filename' : filename,
377 'filename' : filename,
377 'line_number' : lineno
378 'line_number' : lineno
378 }
379 }
379 self.payload_manager.write_payload(payload)
380 self.payload_manager.write_payload(payload)
380
381
381 def magic_gui(self, *args, **kwargs):
382 def magic_gui(self, *args, **kwargs):
382 raise NotImplementedError(
383 raise NotImplementedError(
383 'Kernel GUI support is not implemented yet, except for --pylab.')
384 'Kernel GUI support is not implemented yet, except for --pylab.')
384
385
385 def magic_pylab(self, *args, **kwargs):
386 def magic_pylab(self, *args, **kwargs):
386 raise NotImplementedError(
387 raise NotImplementedError(
387 'pylab support must be enabled in command line options.')
388 'pylab support must be enabled in command line options.')
388
389
389 # A few magics that are adapted to the specifics of using pexpect and a
390 # A few magics that are adapted to the specifics of using pexpect and a
390 # remote terminal
391 # remote terminal
391
392
392 def magic_clear(self, arg_s):
393 def magic_clear(self, arg_s):
393 """Clear the terminal."""
394 """Clear the terminal."""
394 if os.name == 'posix':
395 if os.name == 'posix':
395 self.shell.system("clear")
396 self.shell.system("clear")
396 else:
397 else:
397 self.shell.system("cls")
398 self.shell.system("cls")
398
399
399 if os.name == 'nt':
400 if os.name == 'nt':
400 # This is the usual name in windows
401 # This is the usual name in windows
401 magic_cls = magic_clear
402 magic_cls = magic_clear
402
403
403 # Terminal pagers won't work over pexpect, but we do have our own pager
404 # Terminal pagers won't work over pexpect, but we do have our own pager
404
405
405 def magic_less(self, arg_s):
406 def magic_less(self, arg_s):
406 """Show a file through the pager.
407 """Show a file through the pager.
407
408
408 Files ending in .py are syntax-highlighted."""
409 Files ending in .py are syntax-highlighted."""
409 cont = open(arg_s).read()
410 cont = open(arg_s).read()
410 if arg_s.endswith('.py'):
411 if arg_s.endswith('.py'):
411 cont = self.shell.pycolorize(cont)
412 cont = self.shell.pycolorize(cont)
412 page.page(cont)
413 page.page(cont)
413
414
414 magic_more = magic_less
415 magic_more = magic_less
415
416
416 # Man calls a pager, so we also need to redefine it
417 # Man calls a pager, so we also need to redefine it
417 if os.name == 'posix':
418 if os.name == 'posix':
418 def magic_man(self, arg_s):
419 def magic_man(self, arg_s):
419 """Find the man page for the given command and display in pager."""
420 """Find the man page for the given command and display in pager."""
420 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
421 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
421 split=False))
422 split=False))
422
423
423 # FIXME: this is specific to the GUI, so we should let the gui app load
424 # FIXME: this is specific to the GUI, so we should let the gui app load
424 # magics at startup that are only for the gui. Once the gui app has proper
425 # magics at startup that are only for the gui. Once the gui app has proper
425 # profile and configuration management, we can have it initialize a kernel
426 # profile and configuration management, we can have it initialize a kernel
426 # with a special config file that provides these.
427 # with a special config file that provides these.
427 def magic_guiref(self, arg_s):
428 def magic_guiref(self, arg_s):
428 """Show a basic reference about the GUI console."""
429 """Show a basic reference about the GUI console."""
429 from IPython.core.usage import gui_reference
430 from IPython.core.usage import gui_reference
430 page.page(gui_reference, auto_html=True)
431 page.page(gui_reference, auto_html=True)
431
432
432 def set_next_input(self, text):
433 def set_next_input(self, text):
433 """Send the specified text to the frontend to be presented at the next
434 """Send the specified text to the frontend to be presented at the next
434 input cell."""
435 input cell."""
435 payload = dict(
436 payload = dict(
436 source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
437 source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
437 text=text
438 text=text
438 )
439 )
439 self.payload_manager.write_payload(payload)
440 self.payload_manager.write_payload(payload)
440
441
441 InteractiveShellABC.register(ZMQInteractiveShell)
442 InteractiveShellABC.register(ZMQInteractiveShell)
General Comments 0
You need to be logged in to leave comments. Login now