##// END OF EJS Templates
remove some other occurences of pylab
Matthias BUSSONNIER -
Show More
@@ -1,718 +1,718 b''
1 """A simple configuration system.
1 """A simple configuration system.
2
2
3 Inheritance diagram:
3 Inheritance diagram:
4
4
5 .. inheritance-diagram:: IPython.config.loader
5 .. inheritance-diagram:: IPython.config.loader
6 :parts: 3
6 :parts: 3
7
7
8 Authors
8 Authors
9 -------
9 -------
10 * Brian Granger
10 * Brian Granger
11 * Fernando Perez
11 * Fernando Perez
12 * Min RK
12 * Min RK
13 """
13 """
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Copyright (C) 2008-2011 The IPython Development Team
16 # Copyright (C) 2008-2011 The IPython Development Team
17 #
17 #
18 # Distributed under the terms of the BSD License. The full license is in
18 # Distributed under the terms of the BSD License. The full license is in
19 # the file COPYING, distributed as part of this software.
19 # the file COPYING, distributed as part of this software.
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Imports
23 # Imports
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 import __builtin__ as builtin_mod
26 import __builtin__ as builtin_mod
27 import os
27 import os
28 import re
28 import re
29 import sys
29 import sys
30
30
31 from IPython.external import argparse
31 from IPython.external import argparse
32 from IPython.utils.path import filefind, get_ipython_dir
32 from IPython.utils.path import filefind, get_ipython_dir
33 from IPython.utils import py3compat, warn
33 from IPython.utils import py3compat, warn
34 from IPython.utils.encoding import DEFAULT_ENCODING
34 from IPython.utils.encoding import DEFAULT_ENCODING
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Exceptions
37 # Exceptions
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40
40
41 class ConfigError(Exception):
41 class ConfigError(Exception):
42 pass
42 pass
43
43
44 class ConfigLoaderError(ConfigError):
44 class ConfigLoaderError(ConfigError):
45 pass
45 pass
46
46
47 class ConfigFileNotFound(ConfigError):
47 class ConfigFileNotFound(ConfigError):
48 pass
48 pass
49
49
50 class ArgumentError(ConfigLoaderError):
50 class ArgumentError(ConfigLoaderError):
51 pass
51 pass
52
52
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54 # Argparse fix
54 # Argparse fix
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56
56
57 # Unfortunately argparse by default prints help messages to stderr instead of
57 # Unfortunately argparse by default prints help messages to stderr instead of
58 # stdout. This makes it annoying to capture long help screens at the command
58 # stdout. This makes it annoying to capture long help screens at the command
59 # line, since one must know how to pipe stderr, which many users don't know how
59 # line, since one must know how to pipe stderr, which many users don't know how
60 # to do. So we override the print_help method with one that defaults to
60 # to do. So we override the print_help method with one that defaults to
61 # stdout and use our class instead.
61 # stdout and use our class instead.
62
62
63 class ArgumentParser(argparse.ArgumentParser):
63 class ArgumentParser(argparse.ArgumentParser):
64 """Simple argparse subclass that prints help to stdout by default."""
64 """Simple argparse subclass that prints help to stdout by default."""
65
65
66 def print_help(self, file=None):
66 def print_help(self, file=None):
67 if file is None:
67 if file is None:
68 file = sys.stdout
68 file = sys.stdout
69 return super(ArgumentParser, self).print_help(file)
69 return super(ArgumentParser, self).print_help(file)
70
70
71 print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__
71 print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__
72
72
73 #-----------------------------------------------------------------------------
73 #-----------------------------------------------------------------------------
74 # Config class for holding config information
74 # Config class for holding config information
75 #-----------------------------------------------------------------------------
75 #-----------------------------------------------------------------------------
76
76
77
77
78 class Config(dict):
78 class Config(dict):
79 """An attribute based dict that can do smart merges."""
79 """An attribute based dict that can do smart merges."""
80
80
81 def __init__(self, *args, **kwds):
81 def __init__(self, *args, **kwds):
82 dict.__init__(self, *args, **kwds)
82 dict.__init__(self, *args, **kwds)
83 # This sets self.__dict__ = self, but it has to be done this way
83 # This sets self.__dict__ = self, but it has to be done this way
84 # because we are also overriding __setattr__.
84 # because we are also overriding __setattr__.
85 dict.__setattr__(self, '__dict__', self)
85 dict.__setattr__(self, '__dict__', self)
86 self._ensure_subconfig()
86 self._ensure_subconfig()
87
87
88 def _ensure_subconfig(self):
88 def _ensure_subconfig(self):
89 """ensure that sub-dicts that should be Config objects are
89 """ensure that sub-dicts that should be Config objects are
90
90
91 casts dicts that are under section keys to Config objects,
91 casts dicts that are under section keys to Config objects,
92 which is necessary for constructing Config objects from dict literals.
92 which is necessary for constructing Config objects from dict literals.
93 """
93 """
94 for key in self:
94 for key in self:
95 obj = self[key]
95 obj = self[key]
96 if self._is_section_key(key) \
96 if self._is_section_key(key) \
97 and isinstance(obj, dict) \
97 and isinstance(obj, dict) \
98 and not isinstance(obj, Config):
98 and not isinstance(obj, Config):
99 dict.__setattr__(self, key, Config(obj))
99 dict.__setattr__(self, key, Config(obj))
100
100
101 def _merge(self, other):
101 def _merge(self, other):
102 """deprecated alias, use Config.merge()"""
102 """deprecated alias, use Config.merge()"""
103 self.merge(other)
103 self.merge(other)
104
104
105 def merge(self, other):
105 def merge(self, other):
106 """merge another config object into this one"""
106 """merge another config object into this one"""
107 to_update = {}
107 to_update = {}
108 for k, v in other.iteritems():
108 for k, v in other.iteritems():
109 if k not in self:
109 if k not in self:
110 to_update[k] = v
110 to_update[k] = v
111 else: # I have this key
111 else: # I have this key
112 if isinstance(v, Config) and isinstance(self[k], Config):
112 if isinstance(v, Config) and isinstance(self[k], Config):
113 # Recursively merge common sub Configs
113 # Recursively merge common sub Configs
114 self[k].merge(v)
114 self[k].merge(v)
115 else:
115 else:
116 # Plain updates for non-Configs
116 # Plain updates for non-Configs
117 to_update[k] = v
117 to_update[k] = v
118
118
119 self.update(to_update)
119 self.update(to_update)
120
120
121 def _is_section_key(self, key):
121 def _is_section_key(self, key):
122 if key[0].upper()==key[0] and not key.startswith('_'):
122 if key[0].upper()==key[0] and not key.startswith('_'):
123 return True
123 return True
124 else:
124 else:
125 return False
125 return False
126
126
127 def __contains__(self, key):
127 def __contains__(self, key):
128 if self._is_section_key(key):
128 if self._is_section_key(key):
129 return True
129 return True
130 else:
130 else:
131 return super(Config, self).__contains__(key)
131 return super(Config, self).__contains__(key)
132 # .has_key is deprecated for dictionaries.
132 # .has_key is deprecated for dictionaries.
133 has_key = __contains__
133 has_key = __contains__
134
134
135 def _has_section(self, key):
135 def _has_section(self, key):
136 if self._is_section_key(key):
136 if self._is_section_key(key):
137 if super(Config, self).__contains__(key):
137 if super(Config, self).__contains__(key):
138 return True
138 return True
139 return False
139 return False
140
140
141 def copy(self):
141 def copy(self):
142 return type(self)(dict.copy(self))
142 return type(self)(dict.copy(self))
143
143
144 def __copy__(self):
144 def __copy__(self):
145 return self.copy()
145 return self.copy()
146
146
147 def __deepcopy__(self, memo):
147 def __deepcopy__(self, memo):
148 import copy
148 import copy
149 return type(self)(copy.deepcopy(self.items()))
149 return type(self)(copy.deepcopy(self.items()))
150
150
151 def __getitem__(self, key):
151 def __getitem__(self, key):
152 # We cannot use directly self._is_section_key, because it triggers
152 # We cannot use directly self._is_section_key, because it triggers
153 # infinite recursion on top of PyPy. Instead, we manually fish the
153 # infinite recursion on top of PyPy. Instead, we manually fish the
154 # bound method.
154 # bound method.
155 is_section_key = self.__class__._is_section_key.__get__(self)
155 is_section_key = self.__class__._is_section_key.__get__(self)
156
156
157 # Because we use this for an exec namespace, we need to delegate
157 # Because we use this for an exec namespace, we need to delegate
158 # the lookup of names in __builtin__ to itself. This means
158 # the lookup of names in __builtin__ to itself. This means
159 # that you can't have section or attribute names that are
159 # that you can't have section or attribute names that are
160 # builtins.
160 # builtins.
161 try:
161 try:
162 return getattr(builtin_mod, key)
162 return getattr(builtin_mod, key)
163 except AttributeError:
163 except AttributeError:
164 pass
164 pass
165 if is_section_key(key):
165 if is_section_key(key):
166 try:
166 try:
167 return dict.__getitem__(self, key)
167 return dict.__getitem__(self, key)
168 except KeyError:
168 except KeyError:
169 c = Config()
169 c = Config()
170 dict.__setitem__(self, key, c)
170 dict.__setitem__(self, key, c)
171 return c
171 return c
172 else:
172 else:
173 return dict.__getitem__(self, key)
173 return dict.__getitem__(self, key)
174
174
175 def __setitem__(self, key, value):
175 def __setitem__(self, key, value):
176 if self._is_section_key(key):
176 if self._is_section_key(key):
177 if not isinstance(value, Config):
177 if not isinstance(value, Config):
178 raise ValueError('values whose keys begin with an uppercase '
178 raise ValueError('values whose keys begin with an uppercase '
179 'char must be Config instances: %r, %r' % (key, value))
179 'char must be Config instances: %r, %r' % (key, value))
180 else:
180 else:
181 dict.__setitem__(self, key, value)
181 dict.__setitem__(self, key, value)
182
182
183 def __getattr__(self, key):
183 def __getattr__(self, key):
184 try:
184 try:
185 return self.__getitem__(key)
185 return self.__getitem__(key)
186 except KeyError as e:
186 except KeyError as e:
187 raise AttributeError(e)
187 raise AttributeError(e)
188
188
189 def __setattr__(self, key, value):
189 def __setattr__(self, key, value):
190 try:
190 try:
191 self.__setitem__(key, value)
191 self.__setitem__(key, value)
192 except KeyError as e:
192 except KeyError as e:
193 raise AttributeError(e)
193 raise AttributeError(e)
194
194
195 def __delattr__(self, key):
195 def __delattr__(self, key):
196 try:
196 try:
197 dict.__delitem__(self, key)
197 dict.__delitem__(self, key)
198 except KeyError as e:
198 except KeyError as e:
199 raise AttributeError(e)
199 raise AttributeError(e)
200
200
201
201
202 #-----------------------------------------------------------------------------
202 #-----------------------------------------------------------------------------
203 # Config loading classes
203 # Config loading classes
204 #-----------------------------------------------------------------------------
204 #-----------------------------------------------------------------------------
205
205
206
206
207 class ConfigLoader(object):
207 class ConfigLoader(object):
208 """A object for loading configurations from just about anywhere.
208 """A object for loading configurations from just about anywhere.
209
209
210 The resulting configuration is packaged as a :class:`Struct`.
210 The resulting configuration is packaged as a :class:`Struct`.
211
211
212 Notes
212 Notes
213 -----
213 -----
214 A :class:`ConfigLoader` does one thing: load a config from a source
214 A :class:`ConfigLoader` does one thing: load a config from a source
215 (file, command line arguments) and returns the data as a :class:`Struct`.
215 (file, command line arguments) and returns the data as a :class:`Struct`.
216 There are lots of things that :class:`ConfigLoader` does not do. It does
216 There are lots of things that :class:`ConfigLoader` does not do. It does
217 not implement complex logic for finding config files. It does not handle
217 not implement complex logic for finding config files. It does not handle
218 default values or merge multiple configs. These things need to be
218 default values or merge multiple configs. These things need to be
219 handled elsewhere.
219 handled elsewhere.
220 """
220 """
221
221
222 def __init__(self):
222 def __init__(self):
223 """A base class for config loaders.
223 """A base class for config loaders.
224
224
225 Examples
225 Examples
226 --------
226 --------
227
227
228 >>> cl = ConfigLoader()
228 >>> cl = ConfigLoader()
229 >>> config = cl.load_config()
229 >>> config = cl.load_config()
230 >>> config
230 >>> config
231 {}
231 {}
232 """
232 """
233 self.clear()
233 self.clear()
234
234
235 def clear(self):
235 def clear(self):
236 self.config = Config()
236 self.config = Config()
237
237
238 def load_config(self):
238 def load_config(self):
239 """Load a config from somewhere, return a :class:`Config` instance.
239 """Load a config from somewhere, return a :class:`Config` instance.
240
240
241 Usually, this will cause self.config to be set and then returned.
241 Usually, this will cause self.config to be set and then returned.
242 However, in most cases, :meth:`ConfigLoader.clear` should be called
242 However, in most cases, :meth:`ConfigLoader.clear` should be called
243 to erase any previous state.
243 to erase any previous state.
244 """
244 """
245 self.clear()
245 self.clear()
246 return self.config
246 return self.config
247
247
248
248
249 class FileConfigLoader(ConfigLoader):
249 class FileConfigLoader(ConfigLoader):
250 """A base class for file based configurations.
250 """A base class for file based configurations.
251
251
252 As we add more file based config loaders, the common logic should go
252 As we add more file based config loaders, the common logic should go
253 here.
253 here.
254 """
254 """
255 pass
255 pass
256
256
257
257
258 class PyFileConfigLoader(FileConfigLoader):
258 class PyFileConfigLoader(FileConfigLoader):
259 """A config loader for pure python files.
259 """A config loader for pure python files.
260
260
261 This calls execfile on a plain python file and looks for attributes
261 This calls execfile on a plain python file and looks for attributes
262 that are all caps. These attribute are added to the config Struct.
262 that are all caps. These attribute are added to the config Struct.
263 """
263 """
264
264
265 def __init__(self, filename, path=None):
265 def __init__(self, filename, path=None):
266 """Build a config loader for a filename and path.
266 """Build a config loader for a filename and path.
267
267
268 Parameters
268 Parameters
269 ----------
269 ----------
270 filename : str
270 filename : str
271 The file name of the config file.
271 The file name of the config file.
272 path : str, list, tuple
272 path : str, list, tuple
273 The path to search for the config file on, or a sequence of
273 The path to search for the config file on, or a sequence of
274 paths to try in order.
274 paths to try in order.
275 """
275 """
276 super(PyFileConfigLoader, self).__init__()
276 super(PyFileConfigLoader, self).__init__()
277 self.filename = filename
277 self.filename = filename
278 self.path = path
278 self.path = path
279 self.full_filename = ''
279 self.full_filename = ''
280 self.data = None
280 self.data = None
281
281
282 def load_config(self):
282 def load_config(self):
283 """Load the config from a file and return it as a Struct."""
283 """Load the config from a file and return it as a Struct."""
284 self.clear()
284 self.clear()
285 try:
285 try:
286 self._find_file()
286 self._find_file()
287 except IOError as e:
287 except IOError as e:
288 raise ConfigFileNotFound(str(e))
288 raise ConfigFileNotFound(str(e))
289 self._read_file_as_dict()
289 self._read_file_as_dict()
290 self._convert_to_config()
290 self._convert_to_config()
291 return self.config
291 return self.config
292
292
293 def _find_file(self):
293 def _find_file(self):
294 """Try to find the file by searching the paths."""
294 """Try to find the file by searching the paths."""
295 self.full_filename = filefind(self.filename, self.path)
295 self.full_filename = filefind(self.filename, self.path)
296
296
297 def _read_file_as_dict(self):
297 def _read_file_as_dict(self):
298 """Load the config file into self.config, with recursive loading."""
298 """Load the config file into self.config, with recursive loading."""
299 # This closure is made available in the namespace that is used
299 # This closure is made available in the namespace that is used
300 # to exec the config file. It allows users to call
300 # to exec the config file. It allows users to call
301 # load_subconfig('myconfig.py') to load config files recursively.
301 # load_subconfig('myconfig.py') to load config files recursively.
302 # It needs to be a closure because it has references to self.path
302 # It needs to be a closure because it has references to self.path
303 # and self.config. The sub-config is loaded with the same path
303 # and self.config. The sub-config is loaded with the same path
304 # as the parent, but it uses an empty config which is then merged
304 # as the parent, but it uses an empty config which is then merged
305 # with the parents.
305 # with the parents.
306
306
307 # If a profile is specified, the config file will be loaded
307 # If a profile is specified, the config file will be loaded
308 # from that profile
308 # from that profile
309
309
310 def load_subconfig(fname, profile=None):
310 def load_subconfig(fname, profile=None):
311 # import here to prevent circular imports
311 # import here to prevent circular imports
312 from IPython.core.profiledir import ProfileDir, ProfileDirError
312 from IPython.core.profiledir import ProfileDir, ProfileDirError
313 if profile is not None:
313 if profile is not None:
314 try:
314 try:
315 profile_dir = ProfileDir.find_profile_dir_by_name(
315 profile_dir = ProfileDir.find_profile_dir_by_name(
316 get_ipython_dir(),
316 get_ipython_dir(),
317 profile,
317 profile,
318 )
318 )
319 except ProfileDirError:
319 except ProfileDirError:
320 return
320 return
321 path = profile_dir.location
321 path = profile_dir.location
322 else:
322 else:
323 path = self.path
323 path = self.path
324 loader = PyFileConfigLoader(fname, path)
324 loader = PyFileConfigLoader(fname, path)
325 try:
325 try:
326 sub_config = loader.load_config()
326 sub_config = loader.load_config()
327 except ConfigFileNotFound:
327 except ConfigFileNotFound:
328 # Pass silently if the sub config is not there. This happens
328 # Pass silently if the sub config is not there. This happens
329 # when a user s using a profile, but not the default config.
329 # when a user s using a profile, but not the default config.
330 pass
330 pass
331 else:
331 else:
332 self.config.merge(sub_config)
332 self.config.merge(sub_config)
333
333
334 # Again, this needs to be a closure and should be used in config
334 # Again, this needs to be a closure and should be used in config
335 # files to get the config being loaded.
335 # files to get the config being loaded.
336 def get_config():
336 def get_config():
337 return self.config
337 return self.config
338
338
339 namespace = dict(
339 namespace = dict(
340 load_subconfig=load_subconfig,
340 load_subconfig=load_subconfig,
341 get_config=get_config,
341 get_config=get_config,
342 __file__=self.full_filename,
342 __file__=self.full_filename,
343 )
343 )
344 fs_encoding = sys.getfilesystemencoding() or 'ascii'
344 fs_encoding = sys.getfilesystemencoding() or 'ascii'
345 conf_filename = self.full_filename.encode(fs_encoding)
345 conf_filename = self.full_filename.encode(fs_encoding)
346 py3compat.execfile(conf_filename, namespace)
346 py3compat.execfile(conf_filename, namespace)
347
347
348 def _convert_to_config(self):
348 def _convert_to_config(self):
349 if self.data is None:
349 if self.data is None:
350 ConfigLoaderError('self.data does not exist')
350 ConfigLoaderError('self.data does not exist')
351
351
352
352
353 class CommandLineConfigLoader(ConfigLoader):
353 class CommandLineConfigLoader(ConfigLoader):
354 """A config loader for command line arguments.
354 """A config loader for command line arguments.
355
355
356 As we add more command line based loaders, the common logic should go
356 As we add more command line based loaders, the common logic should go
357 here.
357 here.
358 """
358 """
359
359
360 def _exec_config_str(self, lhs, rhs):
360 def _exec_config_str(self, lhs, rhs):
361 """execute self.config.<lhs> = <rhs>
361 """execute self.config.<lhs> = <rhs>
362
362
363 * expands ~ with expanduser
363 * expands ~ with expanduser
364 * tries to assign with raw eval, otherwise assigns with just the string,
364 * tries to assign with raw eval, otherwise assigns with just the string,
365 allowing `--C.a=foobar` and `--C.a="foobar"` to be equivalent. *Not*
365 allowing `--C.a=foobar` and `--C.a="foobar"` to be equivalent. *Not*
366 equivalent are `--C.a=4` and `--C.a='4'`.
366 equivalent are `--C.a=4` and `--C.a='4'`.
367 """
367 """
368 rhs = os.path.expanduser(rhs)
368 rhs = os.path.expanduser(rhs)
369 try:
369 try:
370 # Try to see if regular Python syntax will work. This
370 # Try to see if regular Python syntax will work. This
371 # won't handle strings as the quote marks are removed
371 # won't handle strings as the quote marks are removed
372 # by the system shell.
372 # by the system shell.
373 value = eval(rhs)
373 value = eval(rhs)
374 except (NameError, SyntaxError):
374 except (NameError, SyntaxError):
375 # This case happens if the rhs is a string.
375 # This case happens if the rhs is a string.
376 value = rhs
376 value = rhs
377
377
378 exec u'self.config.%s = value' % lhs
378 exec u'self.config.%s = value' % lhs
379
379
380 def _load_flag(self, cfg):
380 def _load_flag(self, cfg):
381 """update self.config from a flag, which can be a dict or Config"""
381 """update self.config from a flag, which can be a dict or Config"""
382 if isinstance(cfg, (dict, Config)):
382 if isinstance(cfg, (dict, Config)):
383 # don't clobber whole config sections, update
383 # don't clobber whole config sections, update
384 # each section from config:
384 # each section from config:
385 for sec,c in cfg.iteritems():
385 for sec,c in cfg.iteritems():
386 self.config[sec].update(c)
386 self.config[sec].update(c)
387 else:
387 else:
388 raise TypeError("Invalid flag: %r" % cfg)
388 raise TypeError("Invalid flag: %r" % cfg)
389
389
390 # raw --identifier=value pattern
390 # raw --identifier=value pattern
391 # but *also* accept '-' as wordsep, for aliases
391 # but *also* accept '-' as wordsep, for aliases
392 # accepts: --foo=a
392 # accepts: --foo=a
393 # --Class.trait=value
393 # --Class.trait=value
394 # --alias-name=value
394 # --alias-name=value
395 # rejects: -foo=value
395 # rejects: -foo=value
396 # --foo
396 # --foo
397 # --Class.trait
397 # --Class.trait
398 kv_pattern = re.compile(r'\-\-[A-Za-z][\w\-]*(\.[\w\-]+)*\=.*')
398 kv_pattern = re.compile(r'\-\-[A-Za-z][\w\-]*(\.[\w\-]+)*\=.*')
399
399
400 # just flags, no assignments, with two *or one* leading '-'
400 # just flags, no assignments, with two *or one* leading '-'
401 # accepts: --foo
401 # accepts: --foo
402 # -foo-bar-again
402 # -foo-bar-again
403 # rejects: --anything=anything
403 # rejects: --anything=anything
404 # --two.word
404 # --two.word
405
405
406 flag_pattern = re.compile(r'\-\-?\w+[\-\w]*$')
406 flag_pattern = re.compile(r'\-\-?\w+[\-\w]*$')
407
407
408 class KeyValueConfigLoader(CommandLineConfigLoader):
408 class KeyValueConfigLoader(CommandLineConfigLoader):
409 """A config loader that loads key value pairs from the command line.
409 """A config loader that loads key value pairs from the command line.
410
410
411 This allows command line options to be gives in the following form::
411 This allows command line options to be gives in the following form::
412
412
413 ipython --profile="foo" --InteractiveShell.autocall=False
413 ipython --profile="foo" --InteractiveShell.autocall=False
414 """
414 """
415
415
416 def __init__(self, argv=None, aliases=None, flags=None):
416 def __init__(self, argv=None, aliases=None, flags=None):
417 """Create a key value pair config loader.
417 """Create a key value pair config loader.
418
418
419 Parameters
419 Parameters
420 ----------
420 ----------
421 argv : list
421 argv : list
422 A list that has the form of sys.argv[1:] which has unicode
422 A list that has the form of sys.argv[1:] which has unicode
423 elements of the form u"key=value". If this is None (default),
423 elements of the form u"key=value". If this is None (default),
424 then sys.argv[1:] will be used.
424 then sys.argv[1:] will be used.
425 aliases : dict
425 aliases : dict
426 A dict of aliases for configurable traits.
426 A dict of aliases for configurable traits.
427 Keys are the short aliases, Values are the resolved trait.
427 Keys are the short aliases, Values are the resolved trait.
428 Of the form: `{'alias' : 'Configurable.trait'}`
428 Of the form: `{'alias' : 'Configurable.trait'}`
429 flags : dict
429 flags : dict
430 A dict of flags, keyed by str name. Vaues can be Config objects,
430 A dict of flags, keyed by str name. Vaues can be Config objects,
431 dicts, or "key=value" strings. If Config or dict, when the flag
431 dicts, or "key=value" strings. If Config or dict, when the flag
432 is triggered, The flag is loaded as `self.config.update(m)`.
432 is triggered, The flag is loaded as `self.config.update(m)`.
433
433
434 Returns
434 Returns
435 -------
435 -------
436 config : Config
436 config : Config
437 The resulting Config object.
437 The resulting Config object.
438
438
439 Examples
439 Examples
440 --------
440 --------
441
441
442 >>> from IPython.config.loader import KeyValueConfigLoader
442 >>> from IPython.config.loader import KeyValueConfigLoader
443 >>> cl = KeyValueConfigLoader()
443 >>> cl = KeyValueConfigLoader()
444 >>> d = cl.load_config(["--A.name='brian'","--B.number=0"])
444 >>> d = cl.load_config(["--A.name='brian'","--B.number=0"])
445 >>> sorted(d.items())
445 >>> sorted(d.items())
446 [('A', {'name': 'brian'}), ('B', {'number': 0})]
446 [('A', {'name': 'brian'}), ('B', {'number': 0})]
447 """
447 """
448 self.clear()
448 self.clear()
449 if argv is None:
449 if argv is None:
450 argv = sys.argv[1:]
450 argv = sys.argv[1:]
451 self.argv = argv
451 self.argv = argv
452 self.aliases = aliases or {}
452 self.aliases = aliases or {}
453 self.flags = flags or {}
453 self.flags = flags or {}
454
454
455
455
456 def clear(self):
456 def clear(self):
457 super(KeyValueConfigLoader, self).clear()
457 super(KeyValueConfigLoader, self).clear()
458 self.extra_args = []
458 self.extra_args = []
459
459
460
460
461 def _decode_argv(self, argv, enc=None):
461 def _decode_argv(self, argv, enc=None):
462 """decode argv if bytes, using stin.encoding, falling back on default enc"""
462 """decode argv if bytes, using stin.encoding, falling back on default enc"""
463 uargv = []
463 uargv = []
464 if enc is None:
464 if enc is None:
465 enc = DEFAULT_ENCODING
465 enc = DEFAULT_ENCODING
466 for arg in argv:
466 for arg in argv:
467 if not isinstance(arg, unicode):
467 if not isinstance(arg, unicode):
468 # only decode if not already decoded
468 # only decode if not already decoded
469 arg = arg.decode(enc)
469 arg = arg.decode(enc)
470 uargv.append(arg)
470 uargv.append(arg)
471 return uargv
471 return uargv
472
472
473
473
474 def load_config(self, argv=None, aliases=None, flags=None):
474 def load_config(self, argv=None, aliases=None, flags=None):
475 """Parse the configuration and generate the Config object.
475 """Parse the configuration and generate the Config object.
476
476
477 After loading, any arguments that are not key-value or
477 After loading, any arguments that are not key-value or
478 flags will be stored in self.extra_args - a list of
478 flags will be stored in self.extra_args - a list of
479 unparsed command-line arguments. This is used for
479 unparsed command-line arguments. This is used for
480 arguments such as input files or subcommands.
480 arguments such as input files or subcommands.
481
481
482 Parameters
482 Parameters
483 ----------
483 ----------
484 argv : list, optional
484 argv : list, optional
485 A list that has the form of sys.argv[1:] which has unicode
485 A list that has the form of sys.argv[1:] which has unicode
486 elements of the form u"key=value". If this is None (default),
486 elements of the form u"key=value". If this is None (default),
487 then self.argv will be used.
487 then self.argv will be used.
488 aliases : dict
488 aliases : dict
489 A dict of aliases for configurable traits.
489 A dict of aliases for configurable traits.
490 Keys are the short aliases, Values are the resolved trait.
490 Keys are the short aliases, Values are the resolved trait.
491 Of the form: `{'alias' : 'Configurable.trait'}`
491 Of the form: `{'alias' : 'Configurable.trait'}`
492 flags : dict
492 flags : dict
493 A dict of flags, keyed by str name. Values can be Config objects
493 A dict of flags, keyed by str name. Values can be Config objects
494 or dicts. When the flag is triggered, The config is loaded as
494 or dicts. When the flag is triggered, The config is loaded as
495 `self.config.update(cfg)`.
495 `self.config.update(cfg)`.
496 """
496 """
497 self.clear()
497 self.clear()
498 if argv is None:
498 if argv is None:
499 argv = self.argv
499 argv = self.argv
500 if aliases is None:
500 if aliases is None:
501 aliases = self.aliases
501 aliases = self.aliases
502 if flags is None:
502 if flags is None:
503 flags = self.flags
503 flags = self.flags
504
504
505 # ensure argv is a list of unicode strings:
505 # ensure argv is a list of unicode strings:
506 uargv = self._decode_argv(argv)
506 uargv = self._decode_argv(argv)
507 for idx,raw in enumerate(uargv):
507 for idx,raw in enumerate(uargv):
508 # strip leading '-'
508 # strip leading '-'
509 item = raw.lstrip('-')
509 item = raw.lstrip('-')
510
510
511 if raw == '--':
511 if raw == '--':
512 # don't parse arguments after '--'
512 # don't parse arguments after '--'
513 # this is useful for relaying arguments to scripts, e.g.
513 # this is useful for relaying arguments to scripts, e.g.
514 # ipython -i foo.py --pylab=qt -- args after '--' go-to-foo.py
514 # ipython -i foo.py --matplotlib=qt -- args after '--' go-to-foo.py
515 self.extra_args.extend(uargv[idx+1:])
515 self.extra_args.extend(uargv[idx+1:])
516 break
516 break
517
517
518 if kv_pattern.match(raw):
518 if kv_pattern.match(raw):
519 lhs,rhs = item.split('=',1)
519 lhs,rhs = item.split('=',1)
520 # Substitute longnames for aliases.
520 # Substitute longnames for aliases.
521 if lhs in aliases:
521 if lhs in aliases:
522 lhs = aliases[lhs]
522 lhs = aliases[lhs]
523 if '.' not in lhs:
523 if '.' not in lhs:
524 # probably a mistyped alias, but not technically illegal
524 # probably a mistyped alias, but not technically illegal
525 warn.warn("Unrecognized alias: '%s', it will probably have no effect."%lhs)
525 warn.warn("Unrecognized alias: '%s', it will probably have no effect."%lhs)
526 try:
526 try:
527 self._exec_config_str(lhs, rhs)
527 self._exec_config_str(lhs, rhs)
528 except Exception:
528 except Exception:
529 raise ArgumentError("Invalid argument: '%s'" % raw)
529 raise ArgumentError("Invalid argument: '%s'" % raw)
530
530
531 elif flag_pattern.match(raw):
531 elif flag_pattern.match(raw):
532 if item in flags:
532 if item in flags:
533 cfg,help = flags[item]
533 cfg,help = flags[item]
534 self._load_flag(cfg)
534 self._load_flag(cfg)
535 else:
535 else:
536 raise ArgumentError("Unrecognized flag: '%s'"%raw)
536 raise ArgumentError("Unrecognized flag: '%s'"%raw)
537 elif raw.startswith('-'):
537 elif raw.startswith('-'):
538 kv = '--'+item
538 kv = '--'+item
539 if kv_pattern.match(kv):
539 if kv_pattern.match(kv):
540 raise ArgumentError("Invalid argument: '%s', did you mean '%s'?"%(raw, kv))
540 raise ArgumentError("Invalid argument: '%s', did you mean '%s'?"%(raw, kv))
541 else:
541 else:
542 raise ArgumentError("Invalid argument: '%s'"%raw)
542 raise ArgumentError("Invalid argument: '%s'"%raw)
543 else:
543 else:
544 # keep all args that aren't valid in a list,
544 # keep all args that aren't valid in a list,
545 # in case our parent knows what to do with them.
545 # in case our parent knows what to do with them.
546 self.extra_args.append(item)
546 self.extra_args.append(item)
547 return self.config
547 return self.config
548
548
549 class ArgParseConfigLoader(CommandLineConfigLoader):
549 class ArgParseConfigLoader(CommandLineConfigLoader):
550 """A loader that uses the argparse module to load from the command line."""
550 """A loader that uses the argparse module to load from the command line."""
551
551
552 def __init__(self, argv=None, aliases=None, flags=None, *parser_args, **parser_kw):
552 def __init__(self, argv=None, aliases=None, flags=None, *parser_args, **parser_kw):
553 """Create a config loader for use with argparse.
553 """Create a config loader for use with argparse.
554
554
555 Parameters
555 Parameters
556 ----------
556 ----------
557
557
558 argv : optional, list
558 argv : optional, list
559 If given, used to read command-line arguments from, otherwise
559 If given, used to read command-line arguments from, otherwise
560 sys.argv[1:] is used.
560 sys.argv[1:] is used.
561
561
562 parser_args : tuple
562 parser_args : tuple
563 A tuple of positional arguments that will be passed to the
563 A tuple of positional arguments that will be passed to the
564 constructor of :class:`argparse.ArgumentParser`.
564 constructor of :class:`argparse.ArgumentParser`.
565
565
566 parser_kw : dict
566 parser_kw : dict
567 A tuple of keyword arguments that will be passed to the
567 A tuple of keyword arguments that will be passed to the
568 constructor of :class:`argparse.ArgumentParser`.
568 constructor of :class:`argparse.ArgumentParser`.
569
569
570 Returns
570 Returns
571 -------
571 -------
572 config : Config
572 config : Config
573 The resulting Config object.
573 The resulting Config object.
574 """
574 """
575 super(CommandLineConfigLoader, self).__init__()
575 super(CommandLineConfigLoader, self).__init__()
576 self.clear()
576 self.clear()
577 if argv is None:
577 if argv is None:
578 argv = sys.argv[1:]
578 argv = sys.argv[1:]
579 self.argv = argv
579 self.argv = argv
580 self.aliases = aliases or {}
580 self.aliases = aliases or {}
581 self.flags = flags or {}
581 self.flags = flags or {}
582
582
583 self.parser_args = parser_args
583 self.parser_args = parser_args
584 self.version = parser_kw.pop("version", None)
584 self.version = parser_kw.pop("version", None)
585 kwargs = dict(argument_default=argparse.SUPPRESS)
585 kwargs = dict(argument_default=argparse.SUPPRESS)
586 kwargs.update(parser_kw)
586 kwargs.update(parser_kw)
587 self.parser_kw = kwargs
587 self.parser_kw = kwargs
588
588
589 def load_config(self, argv=None, aliases=None, flags=None):
589 def load_config(self, argv=None, aliases=None, flags=None):
590 """Parse command line arguments and return as a Config object.
590 """Parse command line arguments and return as a Config object.
591
591
592 Parameters
592 Parameters
593 ----------
593 ----------
594
594
595 args : optional, list
595 args : optional, list
596 If given, a list with the structure of sys.argv[1:] to parse
596 If given, a list with the structure of sys.argv[1:] to parse
597 arguments from. If not given, the instance's self.argv attribute
597 arguments from. If not given, the instance's self.argv attribute
598 (given at construction time) is used."""
598 (given at construction time) is used."""
599 self.clear()
599 self.clear()
600 if argv is None:
600 if argv is None:
601 argv = self.argv
601 argv = self.argv
602 if aliases is None:
602 if aliases is None:
603 aliases = self.aliases
603 aliases = self.aliases
604 if flags is None:
604 if flags is None:
605 flags = self.flags
605 flags = self.flags
606 self._create_parser(aliases, flags)
606 self._create_parser(aliases, flags)
607 self._parse_args(argv)
607 self._parse_args(argv)
608 self._convert_to_config()
608 self._convert_to_config()
609 return self.config
609 return self.config
610
610
611 def get_extra_args(self):
611 def get_extra_args(self):
612 if hasattr(self, 'extra_args'):
612 if hasattr(self, 'extra_args'):
613 return self.extra_args
613 return self.extra_args
614 else:
614 else:
615 return []
615 return []
616
616
617 def _create_parser(self, aliases=None, flags=None):
617 def _create_parser(self, aliases=None, flags=None):
618 self.parser = ArgumentParser(*self.parser_args, **self.parser_kw)
618 self.parser = ArgumentParser(*self.parser_args, **self.parser_kw)
619 self._add_arguments(aliases, flags)
619 self._add_arguments(aliases, flags)
620
620
621 def _add_arguments(self, aliases=None, flags=None):
621 def _add_arguments(self, aliases=None, flags=None):
622 raise NotImplementedError("subclasses must implement _add_arguments")
622 raise NotImplementedError("subclasses must implement _add_arguments")
623
623
624 def _parse_args(self, args):
624 def _parse_args(self, args):
625 """self.parser->self.parsed_data"""
625 """self.parser->self.parsed_data"""
626 # decode sys.argv to support unicode command-line options
626 # decode sys.argv to support unicode command-line options
627 enc = DEFAULT_ENCODING
627 enc = DEFAULT_ENCODING
628 uargs = [py3compat.cast_unicode(a, enc) for a in args]
628 uargs = [py3compat.cast_unicode(a, enc) for a in args]
629 self.parsed_data, self.extra_args = self.parser.parse_known_args(uargs)
629 self.parsed_data, self.extra_args = self.parser.parse_known_args(uargs)
630
630
631 def _convert_to_config(self):
631 def _convert_to_config(self):
632 """self.parsed_data->self.config"""
632 """self.parsed_data->self.config"""
633 for k, v in vars(self.parsed_data).iteritems():
633 for k, v in vars(self.parsed_data).iteritems():
634 exec "self.config.%s = v"%k in locals(), globals()
634 exec "self.config.%s = v"%k in locals(), globals()
635
635
636 class KVArgParseConfigLoader(ArgParseConfigLoader):
636 class KVArgParseConfigLoader(ArgParseConfigLoader):
637 """A config loader that loads aliases and flags with argparse,
637 """A config loader that loads aliases and flags with argparse,
638 but will use KVLoader for the rest. This allows better parsing
638 but will use KVLoader for the rest. This allows better parsing
639 of common args, such as `ipython -c 'print 5'`, but still gets
639 of common args, such as `ipython -c 'print 5'`, but still gets
640 arbitrary config with `ipython --InteractiveShell.use_readline=False`"""
640 arbitrary config with `ipython --InteractiveShell.use_readline=False`"""
641
641
642 def _add_arguments(self, aliases=None, flags=None):
642 def _add_arguments(self, aliases=None, flags=None):
643 self.alias_flags = {}
643 self.alias_flags = {}
644 # print aliases, flags
644 # print aliases, flags
645 if aliases is None:
645 if aliases is None:
646 aliases = self.aliases
646 aliases = self.aliases
647 if flags is None:
647 if flags is None:
648 flags = self.flags
648 flags = self.flags
649 paa = self.parser.add_argument
649 paa = self.parser.add_argument
650 for key,value in aliases.iteritems():
650 for key,value in aliases.iteritems():
651 if key in flags:
651 if key in flags:
652 # flags
652 # flags
653 nargs = '?'
653 nargs = '?'
654 else:
654 else:
655 nargs = None
655 nargs = None
656 if len(key) is 1:
656 if len(key) is 1:
657 paa('-'+key, '--'+key, type=unicode, dest=value, nargs=nargs)
657 paa('-'+key, '--'+key, type=unicode, dest=value, nargs=nargs)
658 else:
658 else:
659 paa('--'+key, type=unicode, dest=value, nargs=nargs)
659 paa('--'+key, type=unicode, dest=value, nargs=nargs)
660 for key, (value, help) in flags.iteritems():
660 for key, (value, help) in flags.iteritems():
661 if key in self.aliases:
661 if key in self.aliases:
662 #
662 #
663 self.alias_flags[self.aliases[key]] = value
663 self.alias_flags[self.aliases[key]] = value
664 continue
664 continue
665 if len(key) is 1:
665 if len(key) is 1:
666 paa('-'+key, '--'+key, action='append_const', dest='_flags', const=value)
666 paa('-'+key, '--'+key, action='append_const', dest='_flags', const=value)
667 else:
667 else:
668 paa('--'+key, action='append_const', dest='_flags', const=value)
668 paa('--'+key, action='append_const', dest='_flags', const=value)
669
669
670 def _convert_to_config(self):
670 def _convert_to_config(self):
671 """self.parsed_data->self.config, parse unrecognized extra args via KVLoader."""
671 """self.parsed_data->self.config, parse unrecognized extra args via KVLoader."""
672 # remove subconfigs list from namespace before transforming the Namespace
672 # remove subconfigs list from namespace before transforming the Namespace
673 if '_flags' in self.parsed_data:
673 if '_flags' in self.parsed_data:
674 subcs = self.parsed_data._flags
674 subcs = self.parsed_data._flags
675 del self.parsed_data._flags
675 del self.parsed_data._flags
676 else:
676 else:
677 subcs = []
677 subcs = []
678
678
679 for k, v in vars(self.parsed_data).iteritems():
679 for k, v in vars(self.parsed_data).iteritems():
680 if v is None:
680 if v is None:
681 # it was a flag that shares the name of an alias
681 # it was a flag that shares the name of an alias
682 subcs.append(self.alias_flags[k])
682 subcs.append(self.alias_flags[k])
683 else:
683 else:
684 # eval the KV assignment
684 # eval the KV assignment
685 self._exec_config_str(k, v)
685 self._exec_config_str(k, v)
686
686
687 for subc in subcs:
687 for subc in subcs:
688 self._load_flag(subc)
688 self._load_flag(subc)
689
689
690 if self.extra_args:
690 if self.extra_args:
691 sub_parser = KeyValueConfigLoader()
691 sub_parser = KeyValueConfigLoader()
692 sub_parser.load_config(self.extra_args)
692 sub_parser.load_config(self.extra_args)
693 self.config.merge(sub_parser.config)
693 self.config.merge(sub_parser.config)
694 self.extra_args = sub_parser.extra_args
694 self.extra_args = sub_parser.extra_args
695
695
696
696
697 def load_pyconfig_files(config_files, path):
697 def load_pyconfig_files(config_files, path):
698 """Load multiple Python config files, merging each of them in turn.
698 """Load multiple Python config files, merging each of them in turn.
699
699
700 Parameters
700 Parameters
701 ==========
701 ==========
702 config_files : list of str
702 config_files : list of str
703 List of config files names to load and merge into the config.
703 List of config files names to load and merge into the config.
704 path : unicode
704 path : unicode
705 The full path to the location of the config files.
705 The full path to the location of the config files.
706 """
706 """
707 config = Config()
707 config = Config()
708 for cf in config_files:
708 for cf in config_files:
709 loader = PyFileConfigLoader(cf, path=path)
709 loader = PyFileConfigLoader(cf, path=path)
710 try:
710 try:
711 next_config = loader.load_config()
711 next_config = loader.load_config()
712 except ConfigFileNotFound:
712 except ConfigFileNotFound:
713 pass
713 pass
714 except:
714 except:
715 raise
715 raise
716 else:
716 else:
717 config.merge(next_config)
717 config.merge(next_config)
718 return config
718 return config
@@ -1,84 +1,84 b''
1 """ Import Qt in a manner suitable for an IPython kernel.
1 """ Import Qt in a manner suitable for an IPython kernel.
2
2
3 This is the import used for the `gui=qt` or `pylab=qt` initialization.
3 This is the import used for the `gui=qt` or `matplotlib=qt` initialization.
4
4
5 Import Priority:
5 Import Priority:
6
6
7 if Qt4 has been imported anywhere else:
7 if Qt4 has been imported anywhere else:
8 use that
8 use that
9
9
10 if matplotlib has been imported and doesn't support v2 (<= 1.0.1):
10 if matplotlib has been imported and doesn't support v2 (<= 1.0.1):
11 use PyQt4 @v1
11 use PyQt4 @v1
12
12
13 Next, ask ETS' QT_API env variable
13 Next, ask ETS' QT_API env variable
14
14
15 if QT_API not set:
15 if QT_API not set:
16 ask matplotlib via rcParams['backend.qt4']
16 ask matplotlib via rcParams['backend.qt4']
17 if it said PyQt:
17 if it said PyQt:
18 use PyQt4 @v1
18 use PyQt4 @v1
19 elif it said PySide:
19 elif it said PySide:
20 use PySide
20 use PySide
21
21
22 else: (matplotlib said nothing)
22 else: (matplotlib said nothing)
23 # this is the default path - nobody told us anything
23 # this is the default path - nobody told us anything
24 try:
24 try:
25 PyQt @v1
25 PyQt @v1
26 except:
26 except:
27 fallback on PySide
27 fallback on PySide
28 else:
28 else:
29 use PyQt @v2 or PySide, depending on QT_API
29 use PyQt @v2 or PySide, depending on QT_API
30 because ETS doesn't work with PyQt @v1.
30 because ETS doesn't work with PyQt @v1.
31
31
32 """
32 """
33
33
34 import os
34 import os
35 import sys
35 import sys
36
36
37 from IPython.utils.warn import warn
37 from IPython.utils.warn import warn
38 from IPython.utils.version import check_version
38 from IPython.utils.version import check_version
39 from IPython.external.qt_loaders import (load_qt, QT_API_PYSIDE,
39 from IPython.external.qt_loaders import (load_qt, QT_API_PYSIDE,
40 QT_API_PYQT, QT_API_PYQT_DEFAULT,
40 QT_API_PYQT, QT_API_PYQT_DEFAULT,
41 loaded_api)
41 loaded_api)
42
42
43 #Constraints placed on an imported matplotlib
43 #Constraints placed on an imported matplotlib
44 def matplotlib_options(mpl):
44 def matplotlib_options(mpl):
45 if mpl is None:
45 if mpl is None:
46 return
46 return
47 mpqt = mpl.rcParams.get('backend.qt4', None)
47 mpqt = mpl.rcParams.get('backend.qt4', None)
48 if mpqt is None:
48 if mpqt is None:
49 return None
49 return None
50 if mpqt.lower() == 'pyside':
50 if mpqt.lower() == 'pyside':
51 return [QT_API_PYSIDE]
51 return [QT_API_PYSIDE]
52 elif mpqt.lower() == 'pyqt4':
52 elif mpqt.lower() == 'pyqt4':
53 return [QT_API_PYQT_DEFAULT]
53 return [QT_API_PYQT_DEFAULT]
54 raise ImportError("unhandled value for backend.qt4 from matplotlib: %r" %
54 raise ImportError("unhandled value for backend.qt4 from matplotlib: %r" %
55 mpqt)
55 mpqt)
56
56
57 def get_options():
57 def get_options():
58 """Return a list of acceptable QT APIs, in decreasing order of
58 """Return a list of acceptable QT APIs, in decreasing order of
59 preference
59 preference
60 """
60 """
61 #already imported Qt somewhere. Use that
61 #already imported Qt somewhere. Use that
62 loaded = loaded_api()
62 loaded = loaded_api()
63 if loaded is not None:
63 if loaded is not None:
64 return [loaded]
64 return [loaded]
65
65
66 mpl = sys.modules.get('matplotlib', None)
66 mpl = sys.modules.get('matplotlib', None)
67
67
68 if mpl is not None and not check_version(mpl.__version__, '1.0.2'):
68 if mpl is not None and not check_version(mpl.__version__, '1.0.2'):
69 #1.0.1 only supports PyQt4 v1
69 #1.0.1 only supports PyQt4 v1
70 return [QT_API_PYQT_DEFAULT]
70 return [QT_API_PYQT_DEFAULT]
71
71
72 if os.environ.get('QT_API', None) is None:
72 if os.environ.get('QT_API', None) is None:
73 #no ETS variable. Ask mpl, then use either
73 #no ETS variable. Ask mpl, then use either
74 return matplotlib_options(mpl) or [QT_API_PYQT_DEFAULT, QT_API_PYSIDE]
74 return matplotlib_options(mpl) or [QT_API_PYQT_DEFAULT, QT_API_PYSIDE]
75
75
76 #ETS variable present. Will fallback to external.qt
76 #ETS variable present. Will fallback to external.qt
77 return None
77 return None
78
78
79 api_opts = get_options()
79 api_opts = get_options()
80 if api_opts is not None:
80 if api_opts is not None:
81 QtCore, QtGui, QtSvg, QT_API = load_qt(api_opts)
81 QtCore, QtGui, QtSvg, QT_API = load_qt(api_opts)
82
82
83 else: # use ETS variable
83 else: # use ETS variable
84 from IPython.external.qt import QtCore, QtGui, QtSvg, QT_API
84 from IPython.external.qt import QtCore, QtGui, QtSvg, QT_API
@@ -1,392 +1,392 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The :class:`~IPython.core.application.Application` object for the command
4 The :class:`~IPython.core.application.Application` object for the command
5 line :command:`ipython` program.
5 line :command:`ipython` program.
6
6
7 Authors
7 Authors
8 -------
8 -------
9
9
10 * Brian Granger
10 * Brian Granger
11 * Fernando Perez
11 * Fernando Perez
12 * Min Ragan-Kelley
12 * Min Ragan-Kelley
13 """
13 """
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Copyright (C) 2008-2011 The IPython Development Team
16 # Copyright (C) 2008-2011 The IPython Development Team
17 #
17 #
18 # Distributed under the terms of the BSD License. The full license is in
18 # Distributed under the terms of the BSD License. The full license is in
19 # the file COPYING, distributed as part of this software.
19 # the file COPYING, distributed as part of this software.
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Imports
23 # Imports
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 from __future__ import absolute_import
26 from __future__ import absolute_import
27
27
28 import logging
28 import logging
29 import os
29 import os
30 import sys
30 import sys
31
31
32 from IPython.config.loader import (
32 from IPython.config.loader import (
33 Config, PyFileConfigLoader, ConfigFileNotFound
33 Config, PyFileConfigLoader, ConfigFileNotFound
34 )
34 )
35 from IPython.config.application import boolean_flag, catch_config_error
35 from IPython.config.application import boolean_flag, catch_config_error
36 from IPython.core import release
36 from IPython.core import release
37 from IPython.core import usage
37 from IPython.core import usage
38 from IPython.core.completer import IPCompleter
38 from IPython.core.completer import IPCompleter
39 from IPython.core.crashhandler import CrashHandler
39 from IPython.core.crashhandler import CrashHandler
40 from IPython.core.formatters import PlainTextFormatter
40 from IPython.core.formatters import PlainTextFormatter
41 from IPython.core.history import HistoryManager
41 from IPython.core.history import HistoryManager
42 from IPython.core.prompts import PromptManager
42 from IPython.core.prompts import PromptManager
43 from IPython.core.application import (
43 from IPython.core.application import (
44 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
44 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
45 )
45 )
46 from IPython.core.magics import ScriptMagics
46 from IPython.core.magics import ScriptMagics
47 from IPython.core.shellapp import (
47 from IPython.core.shellapp import (
48 InteractiveShellApp, shell_flags, shell_aliases
48 InteractiveShellApp, shell_flags, shell_aliases
49 )
49 )
50 from IPython.terminal.interactiveshell import TerminalInteractiveShell
50 from IPython.terminal.interactiveshell import TerminalInteractiveShell
51 from IPython.utils import warn
51 from IPython.utils import warn
52 from IPython.utils.path import get_ipython_dir, check_for_old_config
52 from IPython.utils.path import get_ipython_dir, check_for_old_config
53 from IPython.utils.traitlets import (
53 from IPython.utils.traitlets import (
54 Bool, List, Dict,
54 Bool, List, Dict,
55 )
55 )
56
56
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58 # Globals, utilities and helpers
58 # Globals, utilities and helpers
59 #-----------------------------------------------------------------------------
59 #-----------------------------------------------------------------------------
60
60
61 _examples = """
61 _examples = """
62 ipython --pylab # start in pylab mode
62 ipython --pylab # start in pylab mode
63 ipython --pylab=qt # start in pylab mode with the qt4 backend
63 ipython --pylab=qt # start in pylab mode with the qt4 backend
64 ipython --log-level=DEBUG # set logging to DEBUG
64 ipython --log-level=DEBUG # set logging to DEBUG
65 ipython --profile=foo # start with profile foo
65 ipython --profile=foo # start with profile foo
66
66
67 ipython qtconsole # start the qtconsole GUI application
67 ipython qtconsole # start the qtconsole GUI application
68 ipython help qtconsole # show the help for the qtconsole subcmd
68 ipython help qtconsole # show the help for the qtconsole subcmd
69
69
70 ipython console # start the terminal-based console application
70 ipython console # start the terminal-based console application
71 ipython help console # show the help for the console subcmd
71 ipython help console # show the help for the console subcmd
72
72
73 ipython notebook # start the IPython notebook
73 ipython notebook # start the IPython notebook
74 ipython help notebook # show the help for the notebook subcmd
74 ipython help notebook # show the help for the notebook subcmd
75
75
76 ipython profile create foo # create profile foo w/ default config files
76 ipython profile create foo # create profile foo w/ default config files
77 ipython help profile # show the help for the profile subcmd
77 ipython help profile # show the help for the profile subcmd
78
78
79 ipython locate # print the path to the IPython directory
79 ipython locate # print the path to the IPython directory
80 ipython locate profile foo # print the path to the directory for profile `foo`
80 ipython locate profile foo # print the path to the directory for profile `foo`
81
81
82 ipython nbconvert # convert notebooks to/from other formats
82 ipython nbconvert # convert notebooks to/from other formats
83 """
83 """
84
84
85 #-----------------------------------------------------------------------------
85 #-----------------------------------------------------------------------------
86 # Crash handler for this application
86 # Crash handler for this application
87 #-----------------------------------------------------------------------------
87 #-----------------------------------------------------------------------------
88
88
89 class IPAppCrashHandler(CrashHandler):
89 class IPAppCrashHandler(CrashHandler):
90 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
90 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
91
91
92 def __init__(self, app):
92 def __init__(self, app):
93 contact_name = release.author
93 contact_name = release.author
94 contact_email = release.author_email
94 contact_email = release.author_email
95 bug_tracker = 'https://github.com/ipython/ipython/issues'
95 bug_tracker = 'https://github.com/ipython/ipython/issues'
96 super(IPAppCrashHandler,self).__init__(
96 super(IPAppCrashHandler,self).__init__(
97 app, contact_name, contact_email, bug_tracker
97 app, contact_name, contact_email, bug_tracker
98 )
98 )
99
99
100 def make_report(self,traceback):
100 def make_report(self,traceback):
101 """Return a string containing a crash report."""
101 """Return a string containing a crash report."""
102
102
103 sec_sep = self.section_sep
103 sec_sep = self.section_sep
104 # Start with parent report
104 # Start with parent report
105 report = [super(IPAppCrashHandler, self).make_report(traceback)]
105 report = [super(IPAppCrashHandler, self).make_report(traceback)]
106 # Add interactive-specific info we may have
106 # Add interactive-specific info we may have
107 rpt_add = report.append
107 rpt_add = report.append
108 try:
108 try:
109 rpt_add(sec_sep+"History of session input:")
109 rpt_add(sec_sep+"History of session input:")
110 for line in self.app.shell.user_ns['_ih']:
110 for line in self.app.shell.user_ns['_ih']:
111 rpt_add(line)
111 rpt_add(line)
112 rpt_add('\n*** Last line of input (may not be in above history):\n')
112 rpt_add('\n*** Last line of input (may not be in above history):\n')
113 rpt_add(self.app.shell._last_input_line+'\n')
113 rpt_add(self.app.shell._last_input_line+'\n')
114 except:
114 except:
115 pass
115 pass
116
116
117 return ''.join(report)
117 return ''.join(report)
118
118
119 #-----------------------------------------------------------------------------
119 #-----------------------------------------------------------------------------
120 # Aliases and Flags
120 # Aliases and Flags
121 #-----------------------------------------------------------------------------
121 #-----------------------------------------------------------------------------
122 flags = dict(base_flags)
122 flags = dict(base_flags)
123 flags.update(shell_flags)
123 flags.update(shell_flags)
124 frontend_flags = {}
124 frontend_flags = {}
125 addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
125 addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
126 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
126 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
127 'Turn on auto editing of files with syntax errors.',
127 'Turn on auto editing of files with syntax errors.',
128 'Turn off auto editing of files with syntax errors.'
128 'Turn off auto editing of files with syntax errors.'
129 )
129 )
130 addflag('banner', 'TerminalIPythonApp.display_banner',
130 addflag('banner', 'TerminalIPythonApp.display_banner',
131 "Display a banner upon starting IPython.",
131 "Display a banner upon starting IPython.",
132 "Don't display a banner upon starting IPython."
132 "Don't display a banner upon starting IPython."
133 )
133 )
134 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
134 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
135 """Set to confirm when you try to exit IPython with an EOF (Control-D
135 """Set to confirm when you try to exit IPython with an EOF (Control-D
136 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
136 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
137 you can force a direct exit without any confirmation.""",
137 you can force a direct exit without any confirmation.""",
138 "Don't prompt the user when exiting."
138 "Don't prompt the user when exiting."
139 )
139 )
140 addflag('term-title', 'TerminalInteractiveShell.term_title',
140 addflag('term-title', 'TerminalInteractiveShell.term_title',
141 "Enable auto setting the terminal title.",
141 "Enable auto setting the terminal title.",
142 "Disable auto setting the terminal title."
142 "Disable auto setting the terminal title."
143 )
143 )
144 classic_config = Config()
144 classic_config = Config()
145 classic_config.InteractiveShell.cache_size = 0
145 classic_config.InteractiveShell.cache_size = 0
146 classic_config.PlainTextFormatter.pprint = False
146 classic_config.PlainTextFormatter.pprint = False
147 classic_config.PromptManager.in_template = '>>> '
147 classic_config.PromptManager.in_template = '>>> '
148 classic_config.PromptManager.in2_template = '... '
148 classic_config.PromptManager.in2_template = '... '
149 classic_config.PromptManager.out_template = ''
149 classic_config.PromptManager.out_template = ''
150 classic_config.InteractiveShell.separate_in = ''
150 classic_config.InteractiveShell.separate_in = ''
151 classic_config.InteractiveShell.separate_out = ''
151 classic_config.InteractiveShell.separate_out = ''
152 classic_config.InteractiveShell.separate_out2 = ''
152 classic_config.InteractiveShell.separate_out2 = ''
153 classic_config.InteractiveShell.colors = 'NoColor'
153 classic_config.InteractiveShell.colors = 'NoColor'
154 classic_config.InteractiveShell.xmode = 'Plain'
154 classic_config.InteractiveShell.xmode = 'Plain'
155
155
156 frontend_flags['classic']=(
156 frontend_flags['classic']=(
157 classic_config,
157 classic_config,
158 "Gives IPython a similar feel to the classic Python prompt."
158 "Gives IPython a similar feel to the classic Python prompt."
159 )
159 )
160 # # log doesn't make so much sense this way anymore
160 # # log doesn't make so much sense this way anymore
161 # paa('--log','-l',
161 # paa('--log','-l',
162 # action='store_true', dest='InteractiveShell.logstart',
162 # action='store_true', dest='InteractiveShell.logstart',
163 # help="Start logging to the default log file (./ipython_log.py).")
163 # help="Start logging to the default log file (./ipython_log.py).")
164 #
164 #
165 # # quick is harder to implement
165 # # quick is harder to implement
166 frontend_flags['quick']=(
166 frontend_flags['quick']=(
167 {'TerminalIPythonApp' : {'quick' : True}},
167 {'TerminalIPythonApp' : {'quick' : True}},
168 "Enable quick startup with no config files."
168 "Enable quick startup with no config files."
169 )
169 )
170
170
171 frontend_flags['i'] = (
171 frontend_flags['i'] = (
172 {'TerminalIPythonApp' : {'force_interact' : True}},
172 {'TerminalIPythonApp' : {'force_interact' : True}},
173 """If running code from the command line, become interactive afterwards.
173 """If running code from the command line, become interactive afterwards.
174 Note: can also be given simply as '-i.'"""
174 Note: can also be given simply as '-i.'"""
175 )
175 )
176 flags.update(frontend_flags)
176 flags.update(frontend_flags)
177
177
178 aliases = dict(base_aliases)
178 aliases = dict(base_aliases)
179 aliases.update(shell_aliases)
179 aliases.update(shell_aliases)
180
180
181 #-----------------------------------------------------------------------------
181 #-----------------------------------------------------------------------------
182 # Main classes and functions
182 # Main classes and functions
183 #-----------------------------------------------------------------------------
183 #-----------------------------------------------------------------------------
184
184
185
185
186 class LocateIPythonApp(BaseIPythonApplication):
186 class LocateIPythonApp(BaseIPythonApplication):
187 description = """print the path to the IPython dir"""
187 description = """print the path to the IPython dir"""
188 subcommands = Dict(dict(
188 subcommands = Dict(dict(
189 profile=('IPython.core.profileapp.ProfileLocate',
189 profile=('IPython.core.profileapp.ProfileLocate',
190 "print the path to an IPython profile directory",
190 "print the path to an IPython profile directory",
191 ),
191 ),
192 ))
192 ))
193 def start(self):
193 def start(self):
194 if self.subapp is not None:
194 if self.subapp is not None:
195 return self.subapp.start()
195 return self.subapp.start()
196 else:
196 else:
197 print self.ipython_dir
197 print self.ipython_dir
198
198
199
199
200 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
200 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
201 name = u'ipython'
201 name = u'ipython'
202 description = usage.cl_usage
202 description = usage.cl_usage
203 crash_handler_class = IPAppCrashHandler
203 crash_handler_class = IPAppCrashHandler
204 examples = _examples
204 examples = _examples
205
205
206 flags = Dict(flags)
206 flags = Dict(flags)
207 aliases = Dict(aliases)
207 aliases = Dict(aliases)
208 classes = List()
208 classes = List()
209 def _classes_default(self):
209 def _classes_default(self):
210 """This has to be in a method, for TerminalIPythonApp to be available."""
210 """This has to be in a method, for TerminalIPythonApp to be available."""
211 return [
211 return [
212 InteractiveShellApp, # ShellApp comes before TerminalApp, because
212 InteractiveShellApp, # ShellApp comes before TerminalApp, because
213 self.__class__, # it will also affect subclasses (e.g. QtConsole)
213 self.__class__, # it will also affect subclasses (e.g. QtConsole)
214 TerminalInteractiveShell,
214 TerminalInteractiveShell,
215 PromptManager,
215 PromptManager,
216 HistoryManager,
216 HistoryManager,
217 ProfileDir,
217 ProfileDir,
218 PlainTextFormatter,
218 PlainTextFormatter,
219 IPCompleter,
219 IPCompleter,
220 ScriptMagics,
220 ScriptMagics,
221 ]
221 ]
222
222
223 subcommands = Dict(dict(
223 subcommands = Dict(dict(
224 qtconsole=('IPython.qt.console.qtconsoleapp.IPythonQtConsoleApp',
224 qtconsole=('IPython.qt.console.qtconsoleapp.IPythonQtConsoleApp',
225 """Launch the IPython Qt Console."""
225 """Launch the IPython Qt Console."""
226 ),
226 ),
227 notebook=('IPython.html.notebookapp.NotebookApp',
227 notebook=('IPython.html.notebookapp.NotebookApp',
228 """Launch the IPython HTML Notebook Server."""
228 """Launch the IPython HTML Notebook Server."""
229 ),
229 ),
230 profile = ("IPython.core.profileapp.ProfileApp",
230 profile = ("IPython.core.profileapp.ProfileApp",
231 "Create and manage IPython profiles."
231 "Create and manage IPython profiles."
232 ),
232 ),
233 kernel = ("IPython.kernel.zmq.kernelapp.IPKernelApp",
233 kernel = ("IPython.kernel.zmq.kernelapp.IPKernelApp",
234 "Start a kernel without an attached frontend."
234 "Start a kernel without an attached frontend."
235 ),
235 ),
236 console=('IPython.terminal.console.app.ZMQTerminalIPythonApp',
236 console=('IPython.terminal.console.app.ZMQTerminalIPythonApp',
237 """Launch the IPython terminal-based Console."""
237 """Launch the IPython terminal-based Console."""
238 ),
238 ),
239 locate=('IPython.terminal.ipapp.LocateIPythonApp',
239 locate=('IPython.terminal.ipapp.LocateIPythonApp',
240 LocateIPythonApp.description
240 LocateIPythonApp.description
241 ),
241 ),
242 history=('IPython.core.historyapp.HistoryApp',
242 history=('IPython.core.historyapp.HistoryApp',
243 "Manage the IPython history database."
243 "Manage the IPython history database."
244 ),
244 ),
245 nbconvert=('IPython.nbconvert.nbconvertapp.NbConvertApp',
245 nbconvert=('IPython.nbconvert.nbconvertapp.NbConvertApp',
246 "Convert notebooks to/from other formats."
246 "Convert notebooks to/from other formats."
247 ),
247 ),
248 ))
248 ))
249
249
250 # *do* autocreate requested profile, but don't create the config file.
250 # *do* autocreate requested profile, but don't create the config file.
251 auto_create=Bool(True)
251 auto_create=Bool(True)
252 # configurables
252 # configurables
253 ignore_old_config=Bool(False, config=True,
253 ignore_old_config=Bool(False, config=True,
254 help="Suppress warning messages about legacy config files"
254 help="Suppress warning messages about legacy config files"
255 )
255 )
256 quick = Bool(False, config=True,
256 quick = Bool(False, config=True,
257 help="""Start IPython quickly by skipping the loading of config files."""
257 help="""Start IPython quickly by skipping the loading of config files."""
258 )
258 )
259 def _quick_changed(self, name, old, new):
259 def _quick_changed(self, name, old, new):
260 if new:
260 if new:
261 self.load_config_file = lambda *a, **kw: None
261 self.load_config_file = lambda *a, **kw: None
262 self.ignore_old_config=True
262 self.ignore_old_config=True
263
263
264 display_banner = Bool(True, config=True,
264 display_banner = Bool(True, config=True,
265 help="Whether to display a banner upon starting IPython."
265 help="Whether to display a banner upon starting IPython."
266 )
266 )
267
267
268 # if there is code of files to run from the cmd line, don't interact
268 # if there is code of files to run from the cmd line, don't interact
269 # unless the --i flag (App.force_interact) is true.
269 # unless the --i flag (App.force_interact) is true.
270 force_interact = Bool(False, config=True,
270 force_interact = Bool(False, config=True,
271 help="""If a command or file is given via the command-line,
271 help="""If a command or file is given via the command-line,
272 e.g. 'ipython foo.py"""
272 e.g. 'ipython foo.py"""
273 )
273 )
274 def _force_interact_changed(self, name, old, new):
274 def _force_interact_changed(self, name, old, new):
275 if new:
275 if new:
276 self.interact = True
276 self.interact = True
277
277
278 def _file_to_run_changed(self, name, old, new):
278 def _file_to_run_changed(self, name, old, new):
279 if new:
279 if new:
280 self.something_to_run = True
280 self.something_to_run = True
281 if new and not self.force_interact:
281 if new and not self.force_interact:
282 self.interact = False
282 self.interact = False
283 _code_to_run_changed = _file_to_run_changed
283 _code_to_run_changed = _file_to_run_changed
284 _module_to_run_changed = _file_to_run_changed
284 _module_to_run_changed = _file_to_run_changed
285
285
286 # internal, not-configurable
286 # internal, not-configurable
287 interact=Bool(True)
287 interact=Bool(True)
288 something_to_run=Bool(False)
288 something_to_run=Bool(False)
289
289
290 def parse_command_line(self, argv=None):
290 def parse_command_line(self, argv=None):
291 """override to allow old '-pylab' flag with deprecation warning"""
291 """override to allow old '-pylab' flag with deprecation warning"""
292
292
293 argv = sys.argv[1:] if argv is None else argv
293 argv = sys.argv[1:] if argv is None else argv
294
294
295 if '-pylab' in argv:
295 if '-pylab' in argv:
296 # deprecated `-pylab` given,
296 # deprecated `-pylab` given,
297 # warn and transform into current syntax
297 # warn and transform into current syntax
298 argv = argv[:] # copy, don't clobber
298 argv = argv[:] # copy, don't clobber
299 idx = argv.index('-pylab')
299 idx = argv.index('-pylab')
300 warn.warn("`-pylab` flag has been deprecated.\n"
300 warn.warn("`-pylab` and `--pylab` flags have been deprecated.\n"
301 " Use `--pylab` instead, or `--pylab=foo` to specify a backend.")
301 " Use `--matplotlib=<backend>` and import pylab manually.")
302 sub = '--pylab'
302 sub = '--pylab'
303 if len(argv) > idx+1:
303 if len(argv) > idx+1:
304 # check for gui arg, as in '-pylab qt'
304 # check for gui arg, as in '-pylab qt'
305 gui = argv[idx+1]
305 gui = argv[idx+1]
306 if gui in ('wx', 'qt', 'qt4', 'gtk', 'auto'):
306 if gui in ('wx', 'qt', 'qt4', 'gtk', 'auto'):
307 sub = '--pylab='+gui
307 sub = '--pylab='+gui
308 argv.pop(idx+1)
308 argv.pop(idx+1)
309 argv[idx] = sub
309 argv[idx] = sub
310
310
311 return super(TerminalIPythonApp, self).parse_command_line(argv)
311 return super(TerminalIPythonApp, self).parse_command_line(argv)
312
312
313 @catch_config_error
313 @catch_config_error
314 def initialize(self, argv=None):
314 def initialize(self, argv=None):
315 """Do actions after construct, but before starting the app."""
315 """Do actions after construct, but before starting the app."""
316 super(TerminalIPythonApp, self).initialize(argv)
316 super(TerminalIPythonApp, self).initialize(argv)
317 if self.subapp is not None:
317 if self.subapp is not None:
318 # don't bother initializing further, starting subapp
318 # don't bother initializing further, starting subapp
319 return
319 return
320 if not self.ignore_old_config:
320 if not self.ignore_old_config:
321 check_for_old_config(self.ipython_dir)
321 check_for_old_config(self.ipython_dir)
322 # print self.extra_args
322 # print self.extra_args
323 if self.extra_args and not self.something_to_run:
323 if self.extra_args and not self.something_to_run:
324 self.file_to_run = self.extra_args[0]
324 self.file_to_run = self.extra_args[0]
325 self.init_path()
325 self.init_path()
326 # create the shell
326 # create the shell
327 self.init_shell()
327 self.init_shell()
328 # and draw the banner
328 # and draw the banner
329 self.init_banner()
329 self.init_banner()
330 # Now a variety of things that happen after the banner is printed.
330 # Now a variety of things that happen after the banner is printed.
331 self.init_gui_pylab()
331 self.init_gui_pylab()
332 self.init_extensions()
332 self.init_extensions()
333 self.init_code()
333 self.init_code()
334
334
335 def init_shell(self):
335 def init_shell(self):
336 """initialize the InteractiveShell instance"""
336 """initialize the InteractiveShell instance"""
337 # Create an InteractiveShell instance.
337 # Create an InteractiveShell instance.
338 # shell.display_banner should always be False for the terminal
338 # shell.display_banner should always be False for the terminal
339 # based app, because we call shell.show_banner() by hand below
339 # based app, because we call shell.show_banner() by hand below
340 # so the banner shows *before* all extension loading stuff.
340 # so the banner shows *before* all extension loading stuff.
341 self.shell = TerminalInteractiveShell.instance(parent=self,
341 self.shell = TerminalInteractiveShell.instance(parent=self,
342 display_banner=False, profile_dir=self.profile_dir,
342 display_banner=False, profile_dir=self.profile_dir,
343 ipython_dir=self.ipython_dir)
343 ipython_dir=self.ipython_dir)
344 self.shell.configurables.append(self)
344 self.shell.configurables.append(self)
345
345
346 def init_banner(self):
346 def init_banner(self):
347 """optionally display the banner"""
347 """optionally display the banner"""
348 if self.display_banner and self.interact:
348 if self.display_banner and self.interact:
349 self.shell.show_banner()
349 self.shell.show_banner()
350 # Make sure there is a space below the banner.
350 # Make sure there is a space below the banner.
351 if self.log_level <= logging.INFO: print
351 if self.log_level <= logging.INFO: print
352
352
353 def _pylab_changed(self, name, old, new):
353 def _pylab_changed(self, name, old, new):
354 """Replace --pylab='inline' with --pylab='auto'"""
354 """Replace --pylab='inline' with --pylab='auto'"""
355 if new == 'inline':
355 if new == 'inline':
356 warn.warn("'inline' not available as pylab backend, "
356 warn.warn("'inline' not available as pylab backend, "
357 "using 'auto' instead.")
357 "using 'auto' instead.")
358 self.pylab = 'auto'
358 self.pylab = 'auto'
359
359
360 def start(self):
360 def start(self):
361 if self.subapp is not None:
361 if self.subapp is not None:
362 return self.subapp.start()
362 return self.subapp.start()
363 # perform any prexec steps:
363 # perform any prexec steps:
364 if self.interact:
364 if self.interact:
365 self.log.debug("Starting IPython's mainloop...")
365 self.log.debug("Starting IPython's mainloop...")
366 self.shell.mainloop()
366 self.shell.mainloop()
367 else:
367 else:
368 self.log.debug("IPython not interactive...")
368 self.log.debug("IPython not interactive...")
369
369
370
370
371 def load_default_config(ipython_dir=None):
371 def load_default_config(ipython_dir=None):
372 """Load the default config file from the default ipython_dir.
372 """Load the default config file from the default ipython_dir.
373
373
374 This is useful for embedded shells.
374 This is useful for embedded shells.
375 """
375 """
376 if ipython_dir is None:
376 if ipython_dir is None:
377 ipython_dir = get_ipython_dir()
377 ipython_dir = get_ipython_dir()
378 profile_dir = os.path.join(ipython_dir, 'profile_default')
378 profile_dir = os.path.join(ipython_dir, 'profile_default')
379 cl = PyFileConfigLoader("ipython_config.py", profile_dir)
379 cl = PyFileConfigLoader("ipython_config.py", profile_dir)
380 try:
380 try:
381 config = cl.load_config()
381 config = cl.load_config()
382 except ConfigFileNotFound:
382 except ConfigFileNotFound:
383 # no config found
383 # no config found
384 config = Config()
384 config = Config()
385 return config
385 return config
386
386
387
387
388 launch_new_instance = TerminalIPythonApp.launch_instance
388 launch_new_instance = TerminalIPythonApp.launch_instance
389
389
390
390
391 if __name__ == '__main__':
391 if __name__ == '__main__':
392 launch_new_instance()
392 launch_new_instance()
@@ -1,106 +1,106 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """
2 """
3 A Simple wx example to test IPython's event loop integration.
3 A Simple wx example to test IPython's event loop integration.
4
4
5 To run this do:
5 To run this do:
6
6
7 In [5]: %gui wx # or start IPython with '--gui wx' or '--pylab wx'
7 In [5]: %gui wx # or start IPython with '--gui wx'
8
8
9 In [6]: %run gui-wx.py
9 In [6]: %run gui-wx.py
10
10
11 Ref: Modified from wxPython source code wxPython/samples/simple/simple.py
11 Ref: Modified from wxPython source code wxPython/samples/simple/simple.py
12 """
12 """
13
13
14 import wx
14 import wx
15
15
16
16
17 class MyFrame(wx.Frame):
17 class MyFrame(wx.Frame):
18 """
18 """
19 This is MyFrame. It just shows a few controls on a wxPanel,
19 This is MyFrame. It just shows a few controls on a wxPanel,
20 and has a simple menu.
20 and has a simple menu.
21 """
21 """
22 def __init__(self, parent, title):
22 def __init__(self, parent, title):
23 wx.Frame.__init__(self, parent, -1, title,
23 wx.Frame.__init__(self, parent, -1, title,
24 pos=(150, 150), size=(350, 200))
24 pos=(150, 150), size=(350, 200))
25
25
26 # Create the menubar
26 # Create the menubar
27 menuBar = wx.MenuBar()
27 menuBar = wx.MenuBar()
28
28
29 # and a menu
29 # and a menu
30 menu = wx.Menu()
30 menu = wx.Menu()
31
31
32 # add an item to the menu, using \tKeyName automatically
32 # add an item to the menu, using \tKeyName automatically
33 # creates an accelerator, the third param is some help text
33 # creates an accelerator, the third param is some help text
34 # that will show up in the statusbar
34 # that will show up in the statusbar
35 menu.Append(wx.ID_EXIT, "E&xit\tAlt-X", "Exit this simple sample")
35 menu.Append(wx.ID_EXIT, "E&xit\tAlt-X", "Exit this simple sample")
36
36
37 # bind the menu event to an event handler
37 # bind the menu event to an event handler
38 self.Bind(wx.EVT_MENU, self.OnTimeToClose, id=wx.ID_EXIT)
38 self.Bind(wx.EVT_MENU, self.OnTimeToClose, id=wx.ID_EXIT)
39
39
40 # and put the menu on the menubar
40 # and put the menu on the menubar
41 menuBar.Append(menu, "&File")
41 menuBar.Append(menu, "&File")
42 self.SetMenuBar(menuBar)
42 self.SetMenuBar(menuBar)
43
43
44 self.CreateStatusBar()
44 self.CreateStatusBar()
45
45
46 # Now create the Panel to put the other controls on.
46 # Now create the Panel to put the other controls on.
47 panel = wx.Panel(self)
47 panel = wx.Panel(self)
48
48
49 # and a few controls
49 # and a few controls
50 text = wx.StaticText(panel, -1, "Hello World!")
50 text = wx.StaticText(panel, -1, "Hello World!")
51 text.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD))
51 text.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD))
52 text.SetSize(text.GetBestSize())
52 text.SetSize(text.GetBestSize())
53 btn = wx.Button(panel, -1, "Close")
53 btn = wx.Button(panel, -1, "Close")
54 funbtn = wx.Button(panel, -1, "Just for fun...")
54 funbtn = wx.Button(panel, -1, "Just for fun...")
55
55
56 # bind the button events to handlers
56 # bind the button events to handlers
57 self.Bind(wx.EVT_BUTTON, self.OnTimeToClose, btn)
57 self.Bind(wx.EVT_BUTTON, self.OnTimeToClose, btn)
58 self.Bind(wx.EVT_BUTTON, self.OnFunButton, funbtn)
58 self.Bind(wx.EVT_BUTTON, self.OnFunButton, funbtn)
59
59
60 # Use a sizer to layout the controls, stacked vertically and with
60 # Use a sizer to layout the controls, stacked vertically and with
61 # a 10 pixel border around each
61 # a 10 pixel border around each
62 sizer = wx.BoxSizer(wx.VERTICAL)
62 sizer = wx.BoxSizer(wx.VERTICAL)
63 sizer.Add(text, 0, wx.ALL, 10)
63 sizer.Add(text, 0, wx.ALL, 10)
64 sizer.Add(btn, 0, wx.ALL, 10)
64 sizer.Add(btn, 0, wx.ALL, 10)
65 sizer.Add(funbtn, 0, wx.ALL, 10)
65 sizer.Add(funbtn, 0, wx.ALL, 10)
66 panel.SetSizer(sizer)
66 panel.SetSizer(sizer)
67 panel.Layout()
67 panel.Layout()
68
68
69
69
70 def OnTimeToClose(self, evt):
70 def OnTimeToClose(self, evt):
71 """Event handler for the button click."""
71 """Event handler for the button click."""
72 print("See ya later!")
72 print("See ya later!")
73 self.Close()
73 self.Close()
74
74
75 def OnFunButton(self, evt):
75 def OnFunButton(self, evt):
76 """Event handler for the button click."""
76 """Event handler for the button click."""
77 print("Having fun yet?")
77 print("Having fun yet?")
78
78
79
79
80 class MyApp(wx.App):
80 class MyApp(wx.App):
81 def OnInit(self):
81 def OnInit(self):
82 frame = MyFrame(None, "Simple wxPython App")
82 frame = MyFrame(None, "Simple wxPython App")
83 self.SetTopWindow(frame)
83 self.SetTopWindow(frame)
84
84
85 print("Print statements go to this stdout window by default.")
85 print("Print statements go to this stdout window by default.")
86
86
87 frame.Show(True)
87 frame.Show(True)
88 return True
88 return True
89
89
90
90
91 if __name__ == '__main__':
91 if __name__ == '__main__':
92
92
93 app = wx.GetApp()
93 app = wx.GetApp()
94 if app is None:
94 if app is None:
95 app = MyApp(redirect=False, clearSigInt=False)
95 app = MyApp(redirect=False, clearSigInt=False)
96 else:
96 else:
97 frame = MyFrame(None, "Simple wxPython App")
97 frame = MyFrame(None, "Simple wxPython App")
98 app.SetTopWindow(frame)
98 app.SetTopWindow(frame)
99 print("Print statements go to this stdout window by default.")
99 print("Print statements go to this stdout window by default.")
100 frame.Show(True)
100 frame.Show(True)
101
101
102 try:
102 try:
103 from IPython.lib.inputhook import enable_wx
103 from IPython.lib.inputhook import enable_wx
104 enable_wx(app)
104 enable_wx(app)
105 except ImportError:
105 except ImportError:
106 app.MainLoop()
106 app.MainLoop()
General Comments 0
You need to be logged in to leave comments. Login now