##// END OF EJS Templates
Semi-final Application and minor work on traitlets.
Brian Granger -
Show More
@@ -1,198 +1,200 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """A factory for creating configuration objects.
3 """A factory for creating configuration objects.
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 os
17 import os
18 import sys
18 import sys
19
19
20 from IPython.external import argparse
20 from IPython.external import argparse
21 from IPython.utils.ipstruct import Struct
21 from IPython.utils.ipstruct import Struct
22 from IPython.utils.genutils import filefind
22
23
23 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
24 # Code
25 # Code
25 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
26
27
27
28
28 class ConfigLoaderError(Exception):
29 class ConfigLoaderError(Exception):
29 pass
30 pass
30
31
31
32
32 class ConfigLoader(object):
33 class ConfigLoader(object):
33 """A object for loading configurations from just about anywhere.
34 """A object for loading configurations from just about anywhere.
34
35
35 The resulting configuration is packaged as a :class:`Struct`.
36 The resulting configuration is packaged as a :class:`Struct`.
36
37
37 Notes
38 Notes
38 -----
39 -----
39 A :class:`ConfigLoader` does one thing: load a config from a source
40 A :class:`ConfigLoader` does one thing: load a config from a source
40 (file, command line arguments) and returns the data as a :class:`Struct`.
41 (file, command line arguments) and returns the data as a :class:`Struct`.
41 There are lots of things that :class:`ConfigLoader` does not do. It does
42 There are lots of things that :class:`ConfigLoader` does not do. It does
42 not implement complex logic for finding config files. It does not handle
43 not implement complex logic for finding config files. It does not handle
43 default values or merge multiple configs. These things need to be
44 default values or merge multiple configs. These things need to be
44 handled elsewhere.
45 handled elsewhere.
45 """
46 """
46
47
47 def __init__(self):
48 def __init__(self):
48 """A base class for config loaders.
49 """A base class for config loaders.
49
50
50 Examples
51 Examples
51 --------
52 --------
52
53
53 >>> cl = ConfigLoader()
54 >>> cl = ConfigLoader()
54 >>> config = cl.load_config()
55 >>> config = cl.load_config()
55 >>> config
56 >>> config
56 {}
57 {}
57 """
58 """
58 self.clear()
59 self.clear()
59
60
60 def clear(self):
61 def clear(self):
61 self.config = Struct()
62 self.config = Struct()
62
63
63 def load_config(self):
64 def load_config(self):
64 """Load a config from somewhere, return a Struct.
65 """Load a config from somewhere, return a Struct.
65
66
66 Usually, this will cause self.config to be set and then returned.
67 Usually, this will cause self.config to be set and then returned.
67 """
68 """
68 return self.config
69 return self.config
69
70
70
71
71 class FileConfigLoader(ConfigLoader):
72 class FileConfigLoader(ConfigLoader):
72 """A base class for file based configurations.
73 """A base class for file based configurations.
73
74
74 As we add more file based config loaders, the common logic should go
75 As we add more file based config loaders, the common logic should go
75 here.
76 here.
76 """
77 """
77 pass
78 pass
78
79
79
80
80 class PyFileConfigLoader(FileConfigLoader):
81 class PyFileConfigLoader(FileConfigLoader):
81 """A config loader for pure python files.
82 """A config loader for pure python files.
82
83
83 This calls execfile on a plain python file and looks for attributes
84 This calls execfile on a plain python file and looks for attributes
84 that are all caps. These attribute are added to the config Struct.
85 that are all caps. These attribute are added to the config Struct.
85 """
86 """
86
87
87 def __init__(self, filename, path='.'):
88 def __init__(self, filename, path=None):
88 """Build a config loader for a filename and path.
89 """Build a config loader for a filename and path.
89
90
90 Parameters
91 Parameters
91 ----------
92 ----------
92 filename : str
93 filename : str
93 The file name of the config file.
94 The file name of the config file.
94 path : str, list, tuple
95 path : str, list, tuple
95 The path to search for the config file on, or a sequence of
96 The path to search for the config file on, or a sequence of
96 paths to try in order.
97 paths to try in order.
97 """
98 """
98 super(PyFileConfigLoader, self).__init__()
99 super(PyFileConfigLoader, self).__init__()
99 self.filename = filename
100 self.filename = filename
100 self.path = path
101 self.path = path
101 self.full_filename = ''
102 self.full_filename = ''
102 self.data = None
103 self.data = None
103
104
104 def load_config(self):
105 def load_config(self):
105 """Load the config from a file and return it as a Struct."""
106 """Load the config from a file and return it as a Struct."""
106 self._find_file()
107 self._find_file()
107 self._read_file_as_dict()
108 self._read_file_as_dict()
108 self._convert_to_struct()
109 self._convert_to_struct()
109 return self.config
110 return self.config
110
111
111 def _find_file(self):
112 def _find_file(self):
112 """Try to find the file by searching the paths."""
113 """Try to find the file by searching the paths."""
113 if os.path.isfile(os.path.expanduser(self.filename)):
114 self.full_filename = filefind(self.filename, self.path)
114 self.full_filename = os.path.expanduser(self.filename)
115 return
116 if self.path == '.':
117 self.path = [os.getcwd()]
118 if not isinstance(path, (list, tuple)):
119 raise TypeError("path must be a list or tuple, got: %r" % self.path)
120 for p in self.path:
121 if p == '.': p = os.getcwd()
122 full_filename = os.path.expanduser(os.path.join(p, self.filename))
123 if os.path.isfile(full_filename):
124 self.full_filename = full_filename
125 return
126 raise IOError("Config file does not exist in any "
127 "of the search paths: %r, %r" % \
128 (self.filename, self.path))
129
115
130 def _read_file_as_dict(self):
116 def _read_file_as_dict(self):
131 self.data = {}
117 self.data = {}
132 execfile(self.full_filename, self.data)
118 execfile(self.full_filename, self.data)
133
119
134 def _convert_to_struct(self):
120 def _convert_to_struct(self):
135 if self.data is None:
121 if self.data is None:
136 ConfigLoaderError('self.data does not exist')
122 ConfigLoaderError('self.data does not exist')
137 for k, v in self.data.iteritems():
123 for k, v in self.data.iteritems():
138 if k == k.upper():
124 if k == k.upper():
139 self.config[k] = v
125 self.config[k] = v
140
126
141
127
142 class CommandLineConfigLoader(ConfigLoader):
128 class CommandLineConfigLoader(ConfigLoader):
143 """A config loader for command line arguments.
129 """A config loader for command line arguments.
144
130
145 As we add more command line based loaders, the common logic should go
131 As we add more command line based loaders, the common logic should go
146 here.
132 here.
147 """
133 """
148
134
149
135
150 class NoDefault(object): pass
136 class NoDefault(object): pass
151 NoDefault = NoDefault()
137 NoDefault = NoDefault()
152
138
153 class ArgParseConfigLoader(CommandLineConfigLoader):
139 class ArgParseConfigLoader(CommandLineConfigLoader):
154
140
155 # arguments = [(('-f','--file'),dict(type=str,dest='file'))]
141 # arguments = [(('-f','--file'),dict(type=str,dest='file'))]
156 arguments = ()
142 arguments = ()
157
143
158 def __init__(self, *args, **kw):
144 def __init__(self, *args, **kw):
159 """Create a config loader for use with argparse.
145 """Create a config loader for use with argparse.
160
146
161 The args and kwargs arguments here are passed onto the constructor
147 The args and kwargs arguments here are passed onto the constructor
162 of :class:`argparse.ArgumentParser`.
148 of :class:`argparse.ArgumentParser`.
163 """
149 """
164 super(CommandLineConfigLoader, self).__init__()
150 super(CommandLineConfigLoader, self).__init__()
165 self.args = args
151 self.args = args
166 self.kw = kw
152 self.kw = kw
167
153
168 def load_config(self, args=None):
154 def load_config(self, args=None):
169 """Parse command line arguments and return as a Struct."""
155 """Parse command line arguments and return as a Struct."""
170 self._create_parser()
156 self._create_parser()
171 self._parse_args(args)
157 self._parse_args(args)
172 self._convert_to_struct()
158 self._convert_to_struct()
173 return self.config
159 return self.config
174
160
175 def _create_parser(self):
161 def _create_parser(self):
176 self.parser = argparse.ArgumentParser(*self.args, **self.kw)
162 self.parser = argparse.ArgumentParser(*self.args, **self.kw)
177 self._add_arguments()
163 self._add_arguments()
164 self._add_other_arguments()
165
166 def _add_other_arguments():
167 pass
178
168
179 def _add_arguments(self):
169 def _add_arguments(self):
180 for argument in self.arguments:
170 for argument in self.arguments:
181 if not argument[1].has_key('default'):
171 if not argument[1].has_key('default'):
182 argument[1]['default'] = NoDefault
172 argument[1]['default'] = NoDefault
183 self.parser.add_argument(*argument[0],**argument[1])
173 self.parser.add_argument(*argument[0],**argument[1])
184
174
185 def _parse_args(self, args=None):
175 def _parse_args(self, args=None):
186 """self.parser->self.parsed_data"""
176 """self.parser->self.parsed_data"""
187 if args is None:
177 if args is None:
188 self.parsed_data = self.parser.parse_args()
178 self.parsed_data = self.parser.parse_args()
189 else:
179 else:
190 self.parsed_data = self.parser.parse_args(args)
180 self.parsed_data = self.parser.parse_args(args)
191
181
192 def _convert_to_struct(self):
182 def _convert_to_struct(self):
193 """self.parsed_data->self.config"""
183 """self.parsed_data->self.config"""
194 self.config = Struct()
184 self.config = Struct()
195 for k, v in vars(self.parsed_data).items():
185 for k, v in vars(self.parsed_data).items():
196 if v is not NoDefault:
186 if v is not NoDefault:
197 setattr(self.config, k, v)
187 setattr(self.config, k, v)
198
188
189 class IPythonArgParseConfigLoader(ArgParseConfigLoader):
190
191 def _add_other_arguments(self):
192 self.parser.add_argument('--ipythondir',dest='IPYTHONDIR',type=str,
193 help='set to override default location of IPYTHONDIR',
194 default=NoDefault)
195 self.parser.add_argument('-p','--p',dest='PROFILE_NAME',type=str,
196 help='the string name of the ipython profile to be used',
197 default=None)
198 self.parser.add_argument('--debug',dest="DEBUG",action='store_true',
199 help='debug the application startup process',
200 default=NoDefault)
@@ -1,161 +1,231 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 An application for IPython
4 An application for IPython
5
5
6 Authors:
6 Authors:
7
7
8 * Brian Granger
8 * Brian Granger
9 * Fernando Perez
9 * Fernando Perez
10
10
11 Notes
11 Notes
12 -----
12 -----
13
14 The following directories are relevant in the startup of an app:
15
16 * The ipythondir. This has a default, but can be set by IPYTHONDIR or at
17 the command line.
18 * The current working directory.
19 * Another runtime directory. With some applications (engine, controller) we
20 need the ability to have different cluster configs. Each of these needs
21 to have its own config, security dir and log dir. We could simply treat
22 these as regular ipython dirs.
23
24 There are number of ways in which these directories are used:
25
26 * For config files.
27 * For other assets and resources needed to run. These include
28 plugins, magics, furls files.
29 * For writing various things created at runtime like logs, furl files, etc.
30
31 Questions:
32
33
34 * Can we limit ourselves to 1 config file or do we want to have a sequence
35 of them like IPYTHONDIR->RUNTIMEDIR->CWD? [1]
36 * Do we need a debug mode that has custom exception handling and can drop
37 into pdb upno startup? N
38 * Do we need to use an OutputTrap to capture output and then present it
39 to a user if startup fails? N
40 * Do we want the location of the config file(s) to be independent of the
41 ipython/runtime dir or coupled to it. In other words, can the user select
42 a config file that is outside their runtime/ipython dir. One model is
43 that we could have a very strict model of IPYTHONDIR=runtimed dir=
44 dir used for all config.
45 * Do we install default config files or not? N
46
47 * attempt needs to either clash or to die
48 """
13 """
49
14
50 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
51 # Copyright (C) 2008-2009 The IPython Development Team
16 # Copyright (C) 2008-2009 The IPython Development Team
52 #
17 #
53 # 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
54 # the file COPYING, distributed as part of this software.
19 # the file COPYING, distributed as part of this software.
55 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
56
21
57 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
58 # Imports
23 # Imports
59 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
60
25
26 import os
61 import sys
27 import sys
28 import traceback
29
62 from copy import deepcopy
30 from copy import deepcopy
63 from IPython.utils.ipstruct import Struct
31 from IPython.utils.ipstruct import Struct
32 from IPython.utils.genutils import get_ipython_dir, filefind
33 from IPython.config.loader import (
34 IPythonArgParseConfigLoader,
35 PyFileConfigLoader
36 )
64
37
65 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
66 # Classes and functions
39 # Classes and functions
67 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
68
41
69
42
70 class ApplicationError(Exception):
43 class ApplicationError(Exception):
71 pass
44 pass
72
45
73
46
74 class Application(object):
47 class Application(object):
48 """Load a config, construct an app and run it.
49 """
75
50
76 runtime_dirs = []
51 config_file_name = 'ipython_config.py'
77 default_config = Struct()
52 name = 'ipython'
78 runtime_dir = ''
53 debug = False
79 config_file = ''
80 name = ''
81
54
82 def __init__(self):
55 def __init__(self):
83 pass
56 pass
84
57
85 def start(self):
58 def start(self):
86 """Start the application."""
59 """Start the application."""
87 self.attempt(self.create_command_line_config)
60 self.attempt(self.create_default_config)
88 self.attempt(self.find_runtime_dirs)
61 self.attempt(self.pre_load_command_line_config)
89 self.attempt(self.create_runtime_dirs)
62 self.attempt(self.load_command_line_config, action='exit')
90 self.attempt(self.find_config_files)
63 self.attempt(self.post_load_command_line_config)
91 self.attempt(self.create_file_configs)
64 self.attempt(self.find_ipythondir)
65 self.attempt(self.find_config_file_name)
66 self.attempt(self.find_config_file_paths)
67 self.attempt(self.pre_load_file_config)
68 self.attempt(self.load_file_config)
69 self.attempt(self.post_load_file_config)
92 self.attempt(self.merge_configs)
70 self.attempt(self.merge_configs)
71 self.attempt(self.pre_construct)
93 self.attempt(self.construct)
72 self.attempt(self.construct)
94 self.attempt(self.start_logging)
73 self.attempt(self.post_construct)
95 self.attempt(self.start_app)
74 self.attempt(self.start_app)
96
75
97 #-------------------------------------------------------------------------
76 #-------------------------------------------------------------------------
98 # Various stages of Application creation
77 # Various stages of Application creation
99 #-------------------------------------------------------------------------
78 #-------------------------------------------------------------------------
100
79
80 def create_default_config(self):
81 """Create defaults that can't be set elsewhere."""
82 self.default_config = Struct()
83 self.default_config.IPYTHONDIR = get_ipython_dir()
84
101 def create_command_line_config(self):
85 def create_command_line_config(self):
102 """Read the command line args and return its config object."""
86 """Create and return a command line config loader."""
103 self.command_line_config = Struct()
87 return IPythonArgParseConfigLoader(description=self.name)
88
89 def pre_load_command_line_config(self):
90 """Do actions just before loading the command line config."""
91 pass
104
92
105 def find_runtime_dirs(self):
93 def load_command_line_config(self):
106 """Find the runtime directory for this application.
94 """Load the command line config.
107
95
108 This should set self.runtime_dir.
96 This method also sets ``self.debug``.
109 """
97 """
110 pass
111
98
112 def create_runtime_dirs(self):
99 loader = self.create_command_line_config()
113 """Create the runtime dirs if they don't exist."""
100 self.command_line_config = loader.load_config()
101 try:
102 self.debug = self.command_line_config.DEBUG
103 except AttributeError:
104 pass # use class default
105 self.log("Default config loaded:", self.default_config)
106 self.log("Command line config loaded:", self.command_line_config)
107
108 def post_load_command_line_config(self):
109 """Do actions just after loading the command line config."""
114 pass
110 pass
115
111
116 def find_config_files(self):
112 def find_ipythondir(self):
117 """Find the config file for this application."""
113 """Set the IPython directory.
114
115 This sets ``self.ipythondir``, but the actual value that is passed
116 to the application is kept in either ``self.default_config`` or
117 ``self.command_line_config``. This also added ``self.ipythondir`` to
118 ``sys.path`` so config files there can be references by other config
119 files.
120 """
121
122 try:
123 self.ipythondir = self.command_line_config.IPYTHONDIR
124 except AttributeError:
125 self.ipythondir = self.default_config.IPYTHONDIR
126 sys.path.append(os.path.abspath(self.ipythondir))
127 self.log("IPYTHONDIR set to: %s" % self.ipythondir)
128
129 def find_config_file_name(self):
130 """Find the config file name for this application.
131
132 If a profile has been set at the command line, this will resolve
133 it. The search paths for the config file are set in
134 :meth:`find_config_file_paths` and then passed to the config file
135 loader where they are resolved to an absolute path.
136 """
137
138 if self.command_line_config.PROFILE_NAME is not None:
139 self.profile_name = self.command_line_config.PROFILE_NAME
140 name_parts = self.config_file_name.split('.')
141 name_parts.insert(1, '_' + self.profile_name + '.')
142 self.config_file_name = ''.join(name_parts)
143
144 def find_config_file_paths(self):
145 """Set the search paths for resolving the config file."""
146 self.config_file_paths = (os.getcwd(), self.ipythondir)
147
148 def pre_load_file_config(self):
149 """Do actions before the config file is loaded."""
118 pass
150 pass
119
151
120 def create_file_configs(self):
152 def load_file_config(self):
121 self.file_configs = [Struct()]
153 """Load the config file.
154
155 This tries to load the config file from disk. If successful, the
156 ``CONFIG_FILE`` config variable is set to the resolved config file
157 location. If not successful, an empty config is used.
158 """
159 loader = PyFileConfigLoader(self.config_file_name,
160 self.config_file_paths)
161 try:
162 self.file_config = loader.load_config()
163 self.file_config.CONFIG_FILE = loader.full_filename
164 except IOError:
165 self.log("Config file not found, skipping: %s" % \
166 self.config_file_name)
167 self.file_config = Struct()
168 else:
169 self.log("Config file loaded: %s" % loader.full_filename)
170
171 def post_load_file_config(self):
172 """Do actions after the config file is loaded."""
173 pass
122
174
123 def merge_configs(self):
175 def merge_configs(self):
176 """Merge the default, command line and file config objects."""
124 config = Struct()
177 config = Struct()
125 all_configs = self.file_configs + self.command_line_config
178 config.update(self.default_config)
126 for c in all_configs:
179 config.update(self.command_line_config)
127 config.update(c)
180 config.update(self.file_config)
128 self.master_config = config
181 self.master_config = config
182 self.log("Master config created:", self.master_config)
129
183
130 def construct(self, config):
184 def pre_construct(self):
131 """Construct the main components that make up this app."""
185 """Do actions after the config has been built, but before construct."""
132 pass
186 pass
133
187
134 def start_logging(self):
188 def construct(self):
135 """Start logging, if needed, at the last possible moment."""
189 """Construct the main components that make up this app."""
190 self.log("Constructing components for application...")
191
192 def post_construct(self):
193 """Do actions after construct, but before starting the app."""
136 pass
194 pass
137
195
138 def start_app(self):
196 def start_app(self):
139 """Actually start the app."""
197 """Actually start the app."""
140 pass
198 self.log("Starting application...")
141
199
142 #-------------------------------------------------------------------------
200 #-------------------------------------------------------------------------
143 # Utility methods
201 # Utility methods
144 #-------------------------------------------------------------------------
202 #-------------------------------------------------------------------------
145
203
146 def abort(self):
204 def abort(self):
147 """Abort the starting of the application."""
205 """Abort the starting of the application."""
148 print "Aborting application: ", self.name
206 print "Aborting application: ", self.name
149 sys.exit(1)
207 sys.exit(1)
150
208
151 def attempt(self, func):
209 def exit(self):
210 print "Exiting application: ", self.name
211 sys.exit(1)
212
213 def attempt(self, func, action='abort'):
152 try:
214 try:
153 func()
215 func()
154 except:
216 except:
155 self.handle_error()
217 if action == 'abort':
156 self.abort()
218 self.print_traceback()
157
219 self.abort()
158 def handle_error(self):
220 elif action == 'exit':
159 print "I am dying!"
221 self.exit()
160
222
161 No newline at end of file
223 def print_traceback(self):
224 print "Error in appliction startup: ", self.name
225 print
226 traceback.print_exc()
227
228 def log(self, *args):
229 if self.debug:
230 for arg in args:
231 print "[%s] %s" % (self.name, arg) No newline at end of file
@@ -1,225 +1,225 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 A lightweight component system for IPython.
4 A lightweight component system for IPython.
5
5
6 Authors:
6 Authors:
7
7
8 * Brian Granger
8 * Brian Granger
9 * Fernando Perez
9 * Fernando Perez
10 """
10 """
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2009 The IPython Development Team
13 # Copyright (C) 2008-2009 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 from copy import deepcopy
23 from copy import deepcopy
24 from weakref import WeakValueDictionary
24 from weakref import WeakValueDictionary
25
25
26 from IPython.utils.ipstruct import Struct
26 from IPython.utils.ipstruct import Struct
27 from IPython.utils.traitlets import (
27 from IPython.utils.traitlets import (
28 HasTraitlets, TraitletError, MetaHasTraitlets, Instance, This
28 HasTraitlets, TraitletError, MetaHasTraitlets, Instance, This
29 )
29 )
30
30
31
31
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33 # Helper classes for Components
33 # Helper classes for Components
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35
35
36
36
37 class ComponentError(Exception):
37 class ComponentError(Exception):
38 pass
38 pass
39
39
40 class MetaComponentTracker(type):
40 class MetaComponentTracker(type):
41 """A metaclass that tracks instances of Components and its subclasses."""
41 """A metaclass that tracks instances of Components and its subclasses."""
42
42
43 def __init__(cls, name, bases, d):
43 def __init__(cls, name, bases, d):
44 super(MetaComponentTracker, cls).__init__(name, bases, d)
44 super(MetaComponentTracker, cls).__init__(name, bases, d)
45 cls.__instance_refs = WeakValueDictionary()
45 cls.__instance_refs = WeakValueDictionary()
46 cls.__numcreated = 0
46 cls.__numcreated = 0
47
47
48 def __call__(cls, *args, **kw):
48 def __call__(cls, *args, **kw):
49 """Called when *class* is called (instantiated)!!!
49 """Called when *class* is called (instantiated)!!!
50
50
51 When a Component or subclass is instantiated, this is called and
51 When a Component or subclass is instantiated, this is called and
52 the instance is saved in a WeakValueDictionary for tracking.
52 the instance is saved in a WeakValueDictionary for tracking.
53 """
53 """
54
54
55 instance = super(MetaComponentTracker, cls).__call__(*args, **kw)
55 instance = super(MetaComponentTracker, cls).__call__(*args, **kw)
56 for c in cls.__mro__:
56 for c in cls.__mro__:
57 if issubclass(cls, c) and issubclass(c, Component):
57 if issubclass(cls, c) and issubclass(c, Component):
58 c.__numcreated += 1
58 c.__numcreated += 1
59 c.__instance_refs[c.__numcreated] = instance
59 c.__instance_refs[c.__numcreated] = instance
60 return instance
60 return instance
61
61
62 def get_instances(cls, name=None, klass=None, root=None):
62 def get_instances(cls, name=None, klass=None, root=None):
63 """Get all instances of cls and its subclasses.
63 """Get all instances of cls and its subclasses.
64
64
65 Parameters
65 Parameters
66 ----------
66 ----------
67 name : str
67 name : str
68 Limit to components with this name.
68 Limit to components with this name.
69 klass : class
69 klass : class
70 Limit to components having isinstance(component, klass)
70 Limit to components having isinstance(component, klass)
71 root : Component or subclass
71 root : Component or subclass
72 Limit to components having this root.
72 Limit to components having this root.
73 """
73 """
74 instances = cls.__instance_refs.values()
74 instances = cls.__instance_refs.values()
75 if name is not None:
75 if name is not None:
76 instances = [i for i in instances if i.name == name]
76 instances = [i for i in instances if i.name == name]
77 if klass is not None:
77 if klass is not None:
78 instances = [i for i in instances if isinstance(i, klass)]
78 instances = [i for i in instances if isinstance(i, klass)]
79 if root is not None:
79 if root is not None:
80 instances = [i for i in instances if i.root == root]
80 instances = [i for i in instances if i.root == root]
81 return instances
81 return instances
82
82
83 def get_instances_by_condition(cls, call, name=None, klass=None, root=None):
83 def get_instances_by_condition(cls, call, name=None, klass=None, root=None):
84 """Get all instances of cls, i such that call(i)==True.
84 """Get all instances of cls, i such that call(i)==True.
85
85
86 This also takes the ``name``, ``klass`` and ``root`` arguments of
86 This also takes the ``name``, ``klass`` and ``root`` arguments of
87 :meth:`get_instance`
87 :meth:`get_instance`
88 """
88 """
89 return [i for i in cls.get_instances(name,klass,root) if call(i)]
89 return [i for i in cls.get_instances(name,klass,root) if call(i)]
90
90
91
91
92 class ComponentNameGenerator(object):
92 class ComponentNameGenerator(object):
93 """A Singleton to generate unique component names."""
93 """A Singleton to generate unique component names."""
94
94
95 def __init__(self, prefix):
95 def __init__(self, prefix):
96 self.prefix = prefix
96 self.prefix = prefix
97 self.i = 0
97 self.i = 0
98
98
99 def __call__(self):
99 def __call__(self):
100 count = self.i
100 count = self.i
101 self.i += 1
101 self.i += 1
102 return "%s%s" % (self.prefix, count)
102 return "%s%s" % (self.prefix, count)
103
103
104
104
105 ComponentNameGenerator = ComponentNameGenerator('ipython.component')
105 ComponentNameGenerator = ComponentNameGenerator('ipython.component')
106
106
107
107
108 class MetaComponent(MetaHasTraitlets, MetaComponentTracker):
108 class MetaComponent(MetaHasTraitlets, MetaComponentTracker):
109 pass
109 pass
110
110
111
111
112 #-----------------------------------------------------------------------------
112 #-----------------------------------------------------------------------------
113 # Component implementation
113 # Component implementation
114 #-----------------------------------------------------------------------------
114 #-----------------------------------------------------------------------------
115
115
116
116
117 class Component(HasTraitlets):
117 class Component(HasTraitlets):
118
118
119 __metaclass__ = MetaComponent
119 __metaclass__ = MetaComponent
120
120
121 # Traitlets are fun!
121 # Traitlets are fun!
122 config = Instance(Struct,(),{})
122 config = Instance(Struct,(),{})
123 parent = This()
123 parent = This()
124 root = This()
124 root = This()
125
125
126 def __init__(self, parent, name=None, config=None):
126 def __init__(self, parent, name=None, config=None):
127 """Create a component given a parent and possibly and name and config.
127 """Create a component given a parent and possibly and name and config.
128
128
129 Parameters
129 Parameters
130 ----------
130 ----------
131 parent : Component subclass
131 parent : Component subclass
132 The parent in the component graph. The parent is used
132 The parent in the component graph. The parent is used
133 to get the root of the component graph.
133 to get the root of the component graph.
134 name : str
134 name : str
135 The unique name of the component. If empty, then a unique
135 The unique name of the component. If empty, then a unique
136 one will be autogenerated.
136 one will be autogenerated.
137 config : Struct
137 config : Struct
138 If this is empty, self.config = parent.config, otherwise
138 If this is empty, self.config = parent.config, otherwise
139 self.config = config and root.config is ignored. This argument
139 self.config = config and root.config is ignored. This argument
140 should only be used to *override* the automatic inheritance of
140 should only be used to *override* the automatic inheritance of
141 parent.config. If a caller wants to modify parent.config
141 parent.config. If a caller wants to modify parent.config
142 (not override), the caller should make a copy and change
142 (not override), the caller should make a copy and change
143 attributes and then pass the copy to this argument.
143 attributes and then pass the copy to this argument.
144
144
145 Notes
145 Notes
146 -----
146 -----
147 Subclasses of Component must call the :meth:`__init__` method of
147 Subclasses of Component must call the :meth:`__init__` method of
148 :class:`Component` *before* doing anything else and using
148 :class:`Component` *before* doing anything else and using
149 :func:`super`::
149 :func:`super`::
150
150
151 class MyComponent(Component):
151 class MyComponent(Component):
152 def __init__(self, parent, name=None, config=None):
152 def __init__(self, parent, name=None, config=None):
153 super(MyComponent, self).__init__(parent, name, config)
153 super(MyComponent, self).__init__(parent, name, config)
154 # Then any other code you need to finish initialization.
154 # Then any other code you need to finish initialization.
155
155
156 This ensures that the :attr:`parent`, :attr:`name` and :attr:`config`
156 This ensures that the :attr:`parent`, :attr:`name` and :attr:`config`
157 attributes are handled properly.
157 attributes are handled properly.
158 """
158 """
159 super(Component, self).__init__()
159 super(Component, self).__init__()
160 self._children = []
160 self._children = []
161 if name is None:
161 if name is None:
162 self.name = ComponentNameGenerator()
162 self.name = ComponentNameGenerator()
163 else:
163 else:
164 self.name = name
164 self.name = name
165 self.root = self # This is the default, it is set when parent is set
165 self.root = self # This is the default, it is set when parent is set
166 self.parent = parent
166 self.parent = parent
167 if config is not None:
167 if config is not None:
168 self.config = deepcopy(config)
168 self.config = deepcopy(config)
169 else:
169 else:
170 if self.parent is not None:
170 if self.parent is not None:
171 self.config = deepcopy(self.parent.config)
171 self.config = deepcopy(self.parent.config)
172
172
173 #-------------------------------------------------------------------------
173 #-------------------------------------------------------------------------
174 # Static traitlet notifiations
174 # Static traitlet notifiations
175 #-------------------------------------------------------------------------
175 #-------------------------------------------------------------------------
176
176
177 def _parent_changed(self, name, old, new):
177 def _parent_changed(self, name, old, new):
178 if old is not None:
178 if old is not None:
179 old._remove_child(self)
179 old._remove_child(self)
180 if new is not None:
180 if new is not None:
181 new._add_child(self)
181 new._add_child(self)
182
182
183 if new is None:
183 if new is None:
184 self.root = self
184 self.root = self
185 else:
185 else:
186 self.root = new.root
186 self.root = new.root
187
187
188 def _root_changed(self, name, old, new):
188 def _root_changed(self, name, old, new):
189 if self.parent is None:
189 if self.parent is None:
190 if not (new is self):
190 if not (new is self):
191 raise ComponentError("Root not self, but parent is None.")
191 raise ComponentError("Root not self, but parent is None.")
192 else:
192 else:
193 if not self.parent.root is new:
193 if not self.parent.root is new:
194 raise ComponentError("Error in setting the root attribute: "
194 raise ComponentError("Error in setting the root attribute: "
195 "root != parent.root")
195 "root != parent.root")
196
196
197 def _config_changed(self, name, old, new):
197 def _config_changed(self, name, old, new):
198 # Get all traitlets with a config_key metadata entry
198 # Get all traitlets with a config_key metadata entry
199 traitlets = self.traitlets(config_key=lambda v: True)
199 traitlets = self.traitlets('config_key')
200 for k, v in traitlets.items():
200 for k, v in traitlets.items():
201 try:
201 try:
202 config_value = new[v.get_metadata('config_key')]
202 config_value = new[v.get_metadata('config_key')]
203 except KeyError:
203 except KeyError:
204 pass
204 pass
205 else:
205 else:
206 setattr(self, k, config_value)
206 setattr(self, k, config_value)
207
207
208 @property
208 @property
209 def children(self):
209 def children(self):
210 """A list of all my child components."""
210 """A list of all my child components."""
211 return self._children
211 return self._children
212
212
213 def _remove_child(self, child):
213 def _remove_child(self, child):
214 """A private method for removing children componenets."""
214 """A private method for removing children componenets."""
215 if child in self._children:
215 if child in self._children:
216 index = self._children.index(child)
216 index = self._children.index(child)
217 del self._children[index]
217 del self._children[index]
218
218
219 def _add_child(self, child):
219 def _add_child(self, child):
220 """A private method for adding children componenets."""
220 """A private method for adding children componenets."""
221 if child not in self._children:
221 if child not in self._children:
222 self._children.append(child)
222 self._children.append(child)
223
223
224 def __repr__(self):
224 def __repr__(self):
225 return "<Component('%s')>" % self.name
225 return "<Component('%s')>" % self.name
@@ -1,790 +1,792 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 IPython -- An enhanced Interactive Python
3 IPython -- An enhanced Interactive Python
4
4
5 Requires Python 2.1 or better.
5 Requires Python 2.1 or better.
6
6
7 This file contains the main make_IPython() starter function.
7 This file contains the main make_IPython() starter function.
8 """
8 """
9
9
10 #*****************************************************************************
10 #*****************************************************************************
11 # Copyright (C) 2008-2009 The IPython Development Team
11 # Copyright (C) 2008-2009 The IPython Development Team
12 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
12 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #*****************************************************************************
16 #*****************************************************************************
17
17
18 try:
18 try:
19 credits._Printer__data = """
19 credits._Printer__data = """
20 Python: %s
20 Python: %s
21
21
22 IPython: The IPython Development Team.
22 IPython: The IPython Development Team.
23 See http://ipython.scipy.org for more information.""" \
23 See http://ipython.scipy.org for more information.""" \
24 % credits._Printer__data
24 % credits._Printer__data
25
25
26 copyright._Printer__data += """
26 copyright._Printer__data += """
27
27
28 Copyright (c) 2008-2009 The IPython Development Team.
28 Copyright (c) 2008-2009 The IPython Development Team.
29 Copyright (c) 2001-2007 Fernando Perez, Janko Hauser, Nathan Gray.
29 Copyright (c) 2001-2007 Fernando Perez, Janko Hauser, Nathan Gray.
30 All Rights Reserved."""
30 All Rights Reserved."""
31 except NameError:
31 except NameError:
32 # Can happen if ipython was started with 'python -S', so that site.py is
32 # Can happen if ipython was started with 'python -S', so that site.py is
33 # not loaded
33 # not loaded
34 pass
34 pass
35
35
36 #****************************************************************************
36 #****************************************************************************
37 # Required modules
37 # Required modules
38
38
39 # From the standard library
39 # From the standard library
40 import __main__
40 import __main__
41 import __builtin__
41 import __builtin__
42 import os
42 import os
43 import sys
43 import sys
44 from pprint import pprint
44 from pprint import pprint
45 import warnings
45 import warnings
46
46
47 # Our own
47 # Our own
48 from IPython.utils import DPyGetOpt
48 from IPython.utils import DPyGetOpt
49 from IPython.core import release
49 from IPython.core import release
50 from IPython.utils.ipstruct import Struct
50 from IPython.utils.ipstruct import Struct
51 from IPython.core.outputtrap import OutputTrap
51 from IPython.core.outputtrap import OutputTrap
52 from IPython.config.configloader import ConfigLoader
52 from IPython.config.configloader import ConfigLoader
53 from IPython.core.iplib import InteractiveShell
53 from IPython.core.iplib import InteractiveShell
54 from IPython.core.usage import cmd_line_usage, interactive_usage
54 from IPython.core.usage import cmd_line_usage, interactive_usage
55 from IPython.utils.genutils import *
55 from IPython.utils.genutils import *
56
56
57
57
58 def force_import(modname,force_reload=False):
58 def force_import(modname,force_reload=False):
59 if modname in sys.modules and force_reload:
59 if modname in sys.modules and force_reload:
60 info("reloading: %s" % modname)
60 info("reloading: %s" % modname)
61 reload(sys.modules[modname])
61 reload(sys.modules[modname])
62 else:
62 else:
63 __import__(modname)
63 __import__(modname)
64
64
65
65
66 def threaded_shell_warning():
66 def threaded_shell_warning():
67 msg = """
67 msg = """
68
68
69 The IPython threaded shells and their associated command line
69 The IPython threaded shells and their associated command line
70 arguments (pylab/wthread/gthread/qthread/q4thread) have been
70 arguments (pylab/wthread/gthread/qthread/q4thread) have been
71 deprecated. See the %gui magic for information on the new interface.
71 deprecated. See the %gui magic for information on the new interface.
72 """
72 """
73 warnings.warn(msg, category=DeprecationWarning, stacklevel=1)
73 warnings.warn(msg, category=DeprecationWarning, stacklevel=1)
74
74
75
75
76 #-----------------------------------------------------------------------------
76 #-----------------------------------------------------------------------------
77 def make_IPython(argv=None,user_ns=None,user_global_ns=None,debug=1,
77 def make_IPython(argv=None,user_ns=None,user_global_ns=None,debug=1,
78 rc_override=None,shell_class=InteractiveShell,
78 rc_override=None,shell_class=InteractiveShell,
79 embedded=False,**kw):
79 embedded=False,**kw):
80 """This is a dump of IPython into a single function.
80 """This is a dump of IPython into a single function.
81
81
82 Later it will have to be broken up in a sensible manner.
82 Later it will have to be broken up in a sensible manner.
83
83
84 Arguments:
84 Arguments:
85
85
86 - argv: a list similar to sys.argv[1:]. It should NOT contain the desired
86 - argv: a list similar to sys.argv[1:]. It should NOT contain the desired
87 script name, b/c DPyGetOpt strips the first argument only for the real
87 script name, b/c DPyGetOpt strips the first argument only for the real
88 sys.argv.
88 sys.argv.
89
89
90 - user_ns: a dict to be used as the user's namespace."""
90 - user_ns: a dict to be used as the user's namespace."""
91
91
92 #----------------------------------------------------------------------
92 #----------------------------------------------------------------------
93 # Defaults and initialization
93 # Defaults and initialization
94
94
95 # For developer debugging, deactivates crash handler and uses pdb.
95 # For developer debugging, deactivates crash handler and uses pdb.
96 DEVDEBUG = False
96 DEVDEBUG = True
97
97
98 if argv is None:
98 if argv is None:
99 argv = sys.argv
99 argv = sys.argv
100
100
101 # __IP is the main global that lives throughout and represents the whole
101 # __IP is the main global that lives throughout and represents the whole
102 # application. If the user redefines it, all bets are off as to what
102 # application. If the user redefines it, all bets are off as to what
103 # happens.
103 # happens.
104
104
105 # __IP is the name of he global which the caller will have accessible as
105 # __IP is the name of he global which the caller will have accessible as
106 # __IP.name. We set its name via the first parameter passed to
106 # __IP.name. We set its name via the first parameter passed to
107 # InteractiveShell:
107 # InteractiveShell:
108
108
109 IP = shell_class('__IP',user_ns=user_ns,user_global_ns=user_global_ns,
109 IP = shell_class('__IP',user_ns=user_ns,user_global_ns=user_global_ns,
110 embedded=embedded,**kw)
110 embedded=embedded,**kw)
111
111
112 # Put 'help' in the user namespace
112 # Put 'help' in the user namespace
113 try:
113 try:
114 from site import _Helper
114 from site import _Helper
115 IP.user_ns['help'] = _Helper()
115 IP.user_ns['help'] = _Helper()
116 except ImportError:
116 except ImportError:
117 warn('help() not available - check site.py')
117 warn('help() not available - check site.py')
118
118
119 if DEVDEBUG:
119 if DEVDEBUG:
120 # For developer debugging only (global flag)
120 # For developer debugging only (global flag)
121 from IPython.core import ultratb
121 from IPython.core import ultratb
122 sys.excepthook = ultratb.VerboseTB(call_pdb=1)
122 sys.excepthook = ultratb.VerboseTB(call_pdb=1)
123
123
124 IP.BANNER_PARTS = ['Python %s\n'
124 IP.BANNER_PARTS = ['Python %s\n'
125 'Type "copyright", "credits" or "license" '
125 'Type "copyright", "credits" or "license" '
126 'for more information.\n'
126 'for more information.\n'
127 % (sys.version.split('\n')[0],),
127 % (sys.version.split('\n')[0],),
128 "IPython %s -- An enhanced Interactive Python."
128 "IPython %s -- An enhanced Interactive Python."
129 % (release.version,),
129 % (release.version,),
130 """\
130 """\
131 ? -> Introduction and overview of IPython's features.
131 ? -> Introduction and overview of IPython's features.
132 %quickref -> Quick reference.
132 %quickref -> Quick reference.
133 help -> Python's own help system.
133 help -> Python's own help system.
134 object? -> Details about 'object'. ?object also works, ?? prints more.
134 object? -> Details about 'object'. ?object also works, ?? prints more.
135 """ ]
135 """ ]
136
136
137 IP.usage = interactive_usage
137 IP.usage = interactive_usage
138
138
139 # Platform-dependent suffix.
139 # Platform-dependent suffix.
140 if os.name == 'posix':
140 if os.name == 'posix':
141 rc_suffix = ''
141 rc_suffix = ''
142 else:
142 else:
143 rc_suffix = '.ini'
143 rc_suffix = '.ini'
144
144
145 # default directory for configuration
145 # default directory for configuration
146 ipythondir_def = get_ipython_dir()
146 ipythondir_def = get_ipython_dir()
147
147
148 sys.path.insert(0, '') # add . to sys.path. Fix from Prabhu Ramachandran
148 sys.path.insert(0, '') # add . to sys.path. Fix from Prabhu Ramachandran
149
149
150 # we need the directory where IPython itself is installed
150 # we need the directory where IPython itself is installed
151 import IPython
151 import IPython
152 IPython_dir = os.path.dirname(IPython.__file__)
152 IPython_dir = os.path.dirname(IPython.__file__)
153 del IPython
153 del IPython
154
154
155 #-------------------------------------------------------------------------
155 #-------------------------------------------------------------------------
156 # Command line handling
156 # Command line handling
157
157
158 # Valid command line options (uses DPyGetOpt syntax, like Perl's
158 # Valid command line options (uses DPyGetOpt syntax, like Perl's
159 # GetOpt::Long)
159 # GetOpt::Long)
160
160
161 # Any key not listed here gets deleted even if in the file (like session
161 # Any key not listed here gets deleted even if in the file (like session
162 # or profile). That's deliberate, to maintain the rc namespace clean.
162 # or profile). That's deliberate, to maintain the rc namespace clean.
163
163
164 # Each set of options appears twice: under _conv only the names are
164 # Each set of options appears twice: under _conv only the names are
165 # listed, indicating which type they must be converted to when reading the
165 # listed, indicating which type they must be converted to when reading the
166 # ipythonrc file. And under DPyGetOpt they are listed with the regular
166 # ipythonrc file. And under DPyGetOpt they are listed with the regular
167 # DPyGetOpt syntax (=s,=i,:f,etc).
167 # DPyGetOpt syntax (=s,=i,:f,etc).
168
168
169 # Make sure there's a space before each end of line (they get auto-joined!)
169 # Make sure there's a space before each end of line (they get auto-joined!)
170 cmdline_opts = ('autocall=i autoindent! automagic! banner! cache_size|cs=i '
170 cmdline_opts = ('autocall=i autoindent! automagic! banner! cache_size|cs=i '
171 'c=s classic|cl color_info! colors=s confirm_exit! '
171 'c=s classic|cl color_info! colors=s confirm_exit! '
172 'debug! deep_reload! editor=s log|l messages! nosep '
172 'debug! deep_reload! editor=s log|l messages! nosep '
173 'object_info_string_level=i pdb! '
173 'object_info_string_level=i pdb! '
174 'pprint! prompt_in1|pi1=s prompt_in2|pi2=s prompt_out|po=s '
174 'pprint! prompt_in1|pi1=s prompt_in2|pi2=s prompt_out|po=s '
175 'pydb! '
175 'pydb! '
176 'pylab_import_all! '
176 'pylab_import_all! '
177 'quick screen_length|sl=i prompts_pad_left=i '
177 'quick screen_length|sl=i prompts_pad_left=i '
178 'logfile|lf=s logplay|lp=s profile|p=s '
178 'logfile|lf=s logplay|lp=s profile|p=s '
179 'readline! readline_merge_completions! '
179 'readline! readline_merge_completions! '
180 'readline_omit__names! '
180 'readline_omit__names! '
181 'rcfile=s separate_in|si=s separate_out|so=s '
181 'rcfile=s separate_in|si=s separate_out|so=s '
182 'separate_out2|so2=s xmode=s wildcards_case_sensitive! '
182 'separate_out2|so2=s xmode=s wildcards_case_sensitive! '
183 'magic_docstrings system_verbose! '
183 'magic_docstrings system_verbose! '
184 'multi_line_specials! '
184 'multi_line_specials! '
185 'term_title! wxversion=s '
185 'term_title! wxversion=s '
186 'autoedit_syntax!')
186 'autoedit_syntax!')
187
187
188 # Options that can *only* appear at the cmd line (not in rcfiles).
188 # Options that can *only* appear at the cmd line (not in rcfiles).
189
189
190 cmdline_only = ('help interact|i ipythondir=s Version upgrade '
190 cmdline_only = ('help interact|i ipythondir=s Version upgrade '
191 'gthread! qthread! q4thread! wthread! tkthread! pylab! tk! '
191 'gthread! qthread! q4thread! wthread! tkthread! pylab! tk! '
192 # 'twisted!' # disabled for now.
192 # 'twisted!' # disabled for now.
193 )
193 )
194
194
195 # Build the actual name list to be used by DPyGetOpt
195 # Build the actual name list to be used by DPyGetOpt
196 opts_names = qw(cmdline_opts) + qw(cmdline_only)
196 opts_names = qw(cmdline_opts) + qw(cmdline_only)
197
197
198 # Set sensible command line defaults.
198 # Set sensible command line defaults.
199 # This should have everything from cmdline_opts and cmdline_only
199 # This should have everything from cmdline_opts and cmdline_only
200 opts_def = Struct(autocall = 1,
200 opts_def = Struct(autocall = 1,
201 autoedit_syntax = 0,
201 autoedit_syntax = 0,
202 autoindent = 0,
202 autoindent = 0,
203 automagic = 1,
203 automagic = 1,
204 autoexec = [],
204 autoexec = [],
205 banner = 1,
205 banner = 1,
206 c = '',
206 c = '',
207 cache_size = 1000,
207 cache_size = 1000,
208 classic = 0,
208 classic = 0,
209 color_info = 0,
209 color_info = 0,
210 colors = 'NoColor',
210 colors = 'NoColor',
211 confirm_exit = 1,
211 confirm_exit = 1,
212 debug = 0,
212 debug = 0,
213 deep_reload = 0,
213 deep_reload = 0,
214 editor = '0',
214 editor = '0',
215 gthread = 0,
215 gthread = 0,
216 help = 0,
216 help = 0,
217 interact = 0,
217 interact = 0,
218 ipythondir = ipythondir_def,
218 ipythondir = ipythondir_def,
219 log = 0,
219 log = 0,
220 logfile = '',
220 logfile = '',
221 logplay = '',
221 logplay = '',
222 messages = 1,
222 messages = 1,
223 multi_line_specials = 1,
223 multi_line_specials = 1,
224 nosep = 0,
224 nosep = 0,
225 object_info_string_level = 0,
225 object_info_string_level = 0,
226 pdb = 0,
226 pdb = 0,
227 pprint = 0,
227 pprint = 0,
228 profile = '',
228 profile = '',
229 prompt_in1 = 'In [\\#]: ',
229 prompt_in1 = 'In [\\#]: ',
230 prompt_in2 = ' .\\D.: ',
230 prompt_in2 = ' .\\D.: ',
231 prompt_out = 'Out[\\#]: ',
231 prompt_out = 'Out[\\#]: ',
232 prompts_pad_left = 1,
232 prompts_pad_left = 1,
233 pydb = 0,
233 pydb = 0,
234 pylab = 0,
234 pylab = 0,
235 pylab_import_all = 1,
235 pylab_import_all = 1,
236 q4thread = 0,
236 q4thread = 0,
237 qthread = 0,
237 qthread = 0,
238 quick = 0,
238 quick = 0,
239 quiet = 0,
239 quiet = 0,
240 rcfile = 'ipythonrc' + rc_suffix,
240 rcfile = 'ipythonrc' + rc_suffix,
241 readline = 1,
241 readline = 1,
242 readline_merge_completions = 1,
242 readline_merge_completions = 1,
243 readline_omit__names = 0,
243 readline_omit__names = 0,
244 screen_length = 0,
244 screen_length = 0,
245 separate_in = '\n',
245 separate_in = '\n',
246 separate_out = '\n',
246 separate_out = '\n',
247 separate_out2 = '',
247 separate_out2 = '',
248 system_header = 'IPython system call: ',
248 system_header = 'IPython system call: ',
249 system_verbose = 0,
249 system_verbose = 0,
250 term_title = 1,
250 term_title = 1,
251 tk = 0,
251 tk = 0,
252 #twisted= 0, # disabled for now
252 #twisted= 0, # disabled for now
253 upgrade = 0,
253 upgrade = 0,
254 Version = 0,
254 Version = 0,
255 wildcards_case_sensitive = 1,
255 wildcards_case_sensitive = 1,
256 wthread = 0,
256 wthread = 0,
257 wxversion = '0',
257 wxversion = '0',
258 xmode = 'Context',
258 xmode = 'Context',
259 magic_docstrings = 0, # undocumented, for doc generation
259 magic_docstrings = 0, # undocumented, for doc generation
260 )
260 )
261
261
262 # Things that will *only* appear in rcfiles (not at the command line).
262 # Things that will *only* appear in rcfiles (not at the command line).
263 # Make sure there's a space before each end of line (they get auto-joined!)
263 # Make sure there's a space before each end of line (they get auto-joined!)
264 rcfile_opts = { qwflat: 'include import_mod import_all execfile ',
264 rcfile_opts = { qwflat: 'include import_mod import_all execfile ',
265 qw_lol: 'import_some ',
265 qw_lol: 'import_some ',
266 # for things with embedded whitespace:
266 # for things with embedded whitespace:
267 list_strings:'execute alias readline_parse_and_bind ',
267 list_strings:'execute alias readline_parse_and_bind ',
268 # Regular strings need no conversion:
268 # Regular strings need no conversion:
269 None:'readline_remove_delims ',
269 None:'readline_remove_delims ',
270 }
270 }
271 # Default values for these
271 # Default values for these
272 rc_def = Struct(include = [],
272 rc_def = Struct(include = [],
273 import_mod = [],
273 import_mod = [],
274 import_all = [],
274 import_all = [],
275 import_some = [[]],
275 import_some = [[]],
276 execute = [],
276 execute = [],
277 execfile = [],
277 execfile = [],
278 alias = [],
278 alias = [],
279 readline_parse_and_bind = [],
279 readline_parse_and_bind = [],
280 readline_remove_delims = '',
280 readline_remove_delims = '',
281 )
281 )
282
282
283 # Build the type conversion dictionary from the above tables:
283 # Build the type conversion dictionary from the above tables:
284 typeconv = rcfile_opts.copy()
284 typeconv = rcfile_opts.copy()
285 typeconv.update(optstr2types(cmdline_opts))
285 typeconv.update(optstr2types(cmdline_opts))
286
286
287 # FIXME: the None key appears in both, put that back together by hand. Ugly!
287 # FIXME: the None key appears in both, put that back together by hand. Ugly!
288 typeconv[None] += ' ' + rcfile_opts[None]
288 typeconv[None] += ' ' + rcfile_opts[None]
289
289
290 # Remove quotes at ends of all strings (used to protect spaces)
290 # Remove quotes at ends of all strings (used to protect spaces)
291 typeconv[unquote_ends] = typeconv[None]
291 typeconv[unquote_ends] = typeconv[None]
292 del typeconv[None]
292 del typeconv[None]
293
293
294 # Build the list we'll use to make all config decisions with defaults:
294 # Build the list we'll use to make all config decisions with defaults:
295 opts_all = opts_def.copy()
295 opts_all = opts_def.copy()
296 opts_all.update(rc_def)
296 opts_all.update(rc_def)
297
297
298 # Build conflict resolver for recursive loading of config files:
298 # Build conflict resolver for recursive loading of config files:
299 # - preserve means the outermost file maintains the value, it is not
299 # - preserve means the outermost file maintains the value, it is not
300 # overwritten if an included file has the same key.
300 # overwritten if an included file has the same key.
301 # - add_flip applies + to the two values, so it better make sense to add
301 # - add_flip applies + to the two values, so it better make sense to add
302 # those types of keys. But it flips them first so that things loaded
302 # those types of keys. But it flips them first so that things loaded
303 # deeper in the inclusion chain have lower precedence.
303 # deeper in the inclusion chain have lower precedence.
304 conflict = {'preserve': ' '.join([ typeconv[int],
304 conflict = {'preserve': ' '.join([ typeconv[int],
305 typeconv[unquote_ends] ]),
305 typeconv[unquote_ends] ]),
306 'add_flip': ' '.join([ typeconv[qwflat],
306 'add_flip': ' '.join([ typeconv[qwflat],
307 typeconv[qw_lol],
307 typeconv[qw_lol],
308 typeconv[list_strings] ])
308 typeconv[list_strings] ])
309 }
309 }
310
310
311 # Now actually process the command line
311 # Now actually process the command line
312 getopt = DPyGetOpt.DPyGetOpt()
312 getopt = DPyGetOpt.DPyGetOpt()
313 getopt.setIgnoreCase(0)
313 getopt.setIgnoreCase(0)
314
314
315 getopt.parseConfiguration(opts_names)
315 getopt.parseConfiguration(opts_names)
316
316
317 try:
317 try:
318 getopt.processArguments(argv)
318 getopt.processArguments(argv)
319 except DPyGetOpt.ArgumentError, exc:
319 except DPyGetOpt.ArgumentError, exc:
320 print cmd_line_usage
320 print cmd_line_usage
321 warn('\nError in Arguments: "%s"' % exc)
321 warn('\nError in Arguments: "%s"' % exc)
322 sys.exit(1)
322 sys.exit(1)
323
323
324 # convert the options dict to a struct for much lighter syntax later
324 # convert the options dict to a struct for much lighter syntax later
325 opts = Struct(getopt.optionValues)
325 opts = Struct(getopt.optionValues)
326 args = getopt.freeValues
326 args = getopt.freeValues
327
327
328 # this is the struct (which has default values at this point) with which
328 # this is the struct (which has default values at this point) with which
329 # we make all decisions:
329 # we make all decisions:
330 opts_all.update(opts)
330 opts_all.update(opts)
331
331
332 # Options that force an immediate exit
332 # Options that force an immediate exit
333 if opts_all.help:
333 if opts_all.help:
334 page(cmd_line_usage)
334 page(cmd_line_usage)
335 sys.exit()
335 sys.exit()
336
336
337 if opts_all.Version:
337 if opts_all.Version:
338 print release.version
338 print release.version
339 sys.exit()
339 sys.exit()
340
340
341 if opts_all.magic_docstrings:
341 if opts_all.magic_docstrings:
342 IP.magic_magic('-latex')
342 IP.magic_magic('-latex')
343 sys.exit()
343 sys.exit()
344
344
345 # Display the deprecation warnings about threaded shells
345 # Display the deprecation warnings about threaded shells
346 if opts_all.pylab == 1: threaded_shell_warning()
346 if opts_all.pylab == 1: threaded_shell_warning()
347 if opts_all.wthread == 1: threaded_shell_warning()
347 if opts_all.wthread == 1: threaded_shell_warning()
348 if opts_all.qthread == 1: threaded_shell_warning()
348 if opts_all.qthread == 1: threaded_shell_warning()
349 if opts_all.q4thread == 1: threaded_shell_warning()
349 if opts_all.q4thread == 1: threaded_shell_warning()
350 if opts_all.gthread == 1: threaded_shell_warning()
350 if opts_all.gthread == 1: threaded_shell_warning()
351
351
352 # add personal ipythondir to sys.path so that users can put things in
352 # add personal ipythondir to sys.path so that users can put things in
353 # there for customization
353 # there for customization
354 sys.path.append(os.path.abspath(opts_all.ipythondir))
354 sys.path.append(os.path.abspath(opts_all.ipythondir))
355
355
356 # Create user config directory if it doesn't exist. This must be done
356 # Create user config directory if it doesn't exist. This must be done
357 # *after* getting the cmd line options.
357 # *after* getting the cmd line options.
358 if not os.path.isdir(opts_all.ipythondir):
358 if not os.path.isdir(opts_all.ipythondir):
359 IP.user_setup(opts_all.ipythondir,rc_suffix,'install')
359 IP.user_setup(opts_all.ipythondir,rc_suffix,'install')
360
360
361 # upgrade user config files while preserving a copy of the originals
361 # upgrade user config files while preserving a copy of the originals
362 if opts_all.upgrade:
362 if opts_all.upgrade:
363 IP.user_setup(opts_all.ipythondir,rc_suffix,'upgrade')
363 IP.user_setup(opts_all.ipythondir,rc_suffix,'upgrade')
364
364
365 # check mutually exclusive options in the *original* command line
365 # check mutually exclusive options in the *original* command line
366 mutex_opts(opts,[qw('log logfile'),qw('rcfile profile'),
366 mutex_opts(opts,[qw('log logfile'),qw('rcfile profile'),
367 qw('classic profile'),qw('classic rcfile')])
367 qw('classic profile'),qw('classic rcfile')])
368
368
369 #---------------------------------------------------------------------------
369 #---------------------------------------------------------------------------
370 # Log replay
370 # Log replay
371
371
372 # if -logplay, we need to 'become' the other session. That basically means
372 # if -logplay, we need to 'become' the other session. That basically means
373 # replacing the current command line environment with that of the old
373 # replacing the current command line environment with that of the old
374 # session and moving on.
374 # session and moving on.
375
375
376 # this is needed so that later we know we're in session reload mode, as
376 # this is needed so that later we know we're in session reload mode, as
377 # opts_all will get overwritten:
377 # opts_all will get overwritten:
378 load_logplay = 0
378 load_logplay = 0
379
379
380 if opts_all.logplay:
380 if opts_all.logplay:
381 load_logplay = opts_all.logplay
381 load_logplay = opts_all.logplay
382 opts_debug_save = opts_all.debug
382 opts_debug_save = opts_all.debug
383 try:
383 try:
384 logplay = open(opts_all.logplay)
384 logplay = open(opts_all.logplay)
385 except IOError:
385 except IOError:
386 if opts_all.debug: IP.InteractiveTB()
386 if opts_all.debug: IP.InteractiveTB()
387 warn('Could not open logplay file '+`opts_all.logplay`)
387 warn('Could not open logplay file '+`opts_all.logplay`)
388 # restore state as if nothing had happened and move on, but make
388 # restore state as if nothing had happened and move on, but make
389 # sure that later we don't try to actually load the session file
389 # sure that later we don't try to actually load the session file
390 logplay = None
390 logplay = None
391 load_logplay = 0
391 load_logplay = 0
392 del opts_all.logplay
392 del opts_all.logplay
393 else:
393 else:
394 try:
394 try:
395 logplay.readline()
395 logplay.readline()
396 logplay.readline();
396 logplay.readline();
397 # this reloads that session's command line
397 # this reloads that session's command line
398 cmd = logplay.readline()[6:]
398 cmd = logplay.readline()[6:]
399 exec cmd
399 exec cmd
400 # restore the true debug flag given so that the process of
400 # restore the true debug flag given so that the process of
401 # session loading itself can be monitored.
401 # session loading itself can be monitored.
402 opts.debug = opts_debug_save
402 opts.debug = opts_debug_save
403 # save the logplay flag so later we don't overwrite the log
403 # save the logplay flag so later we don't overwrite the log
404 opts.logplay = load_logplay
404 opts.logplay = load_logplay
405 # now we must update our own structure with defaults
405 # now we must update our own structure with defaults
406 opts_all.update(opts)
406 opts_all.update(opts)
407 # now load args
407 # now load args
408 cmd = logplay.readline()[6:]
408 cmd = logplay.readline()[6:]
409 exec cmd
409 exec cmd
410 logplay.close()
410 logplay.close()
411 except:
411 except:
412 logplay.close()
412 logplay.close()
413 if opts_all.debug: IP.InteractiveTB()
413 if opts_all.debug: IP.InteractiveTB()
414 warn("Logplay file lacking full configuration information.\n"
414 warn("Logplay file lacking full configuration information.\n"
415 "I'll try to read it, but some things may not work.")
415 "I'll try to read it, but some things may not work.")
416
416
417 #-------------------------------------------------------------------------
417 #-------------------------------------------------------------------------
418 # set up output traps: catch all output from files, being run, modules
418 # set up output traps: catch all output from files, being run, modules
419 # loaded, etc. Then give it to the user in a clean form at the end.
419 # loaded, etc. Then give it to the user in a clean form at the end.
420
420
421 msg_out = 'Output messages. '
421 msg_out = 'Output messages. '
422 msg_err = 'Error messages. '
422 msg_err = 'Error messages. '
423 msg_sep = '\n'
423 msg_sep = '\n'
424 msg = Struct(config = OutputTrap('Configuration Loader',msg_out,
424 msg = Struct(config = OutputTrap('Configuration Loader',msg_out,
425 msg_err,msg_sep,debug,
425 msg_err,msg_sep,debug,
426 quiet_out=1),
426 quiet_out=1),
427 user_exec = OutputTrap('User File Execution',msg_out,
427 user_exec = OutputTrap('User File Execution',msg_out,
428 msg_err,msg_sep,debug),
428 msg_err,msg_sep,debug),
429 logplay = OutputTrap('Log Loader',msg_out,
429 logplay = OutputTrap('Log Loader',msg_out,
430 msg_err,msg_sep,debug),
430 msg_err,msg_sep,debug),
431 summary = ''
431 summary = ''
432 )
432 )
433
433
434 #-------------------------------------------------------------------------
434 #-------------------------------------------------------------------------
435 # Process user ipythonrc-type configuration files
435 # Process user ipythonrc-type configuration files
436
436
437 # turn on output trapping and log to msg.config
437 # turn on output trapping and log to msg.config
438 # remember that with debug on, trapping is actually disabled
438 # remember that with debug on, trapping is actually disabled
439 msg.config.trap_all()
439 msg.config.trap_all()
440
440
441 # look for rcfile in current or default directory
441 # look for rcfile in current or default directory
442 try:
442 try:
443 opts_all.rcfile = filefind(opts_all.rcfile,opts_all.ipythondir)
443 opts_all.rcfile = filefind(opts_all.rcfile,opts_all.ipythondir)
444 except IOError:
444 except IOError:
445 if opts_all.debug: IP.InteractiveTB()
445 if opts_all.debug: IP.InteractiveTB()
446 warn('Configuration file %s not found. Ignoring request.'
446 warn('Configuration file %s not found. Ignoring request.'
447 % (opts_all.rcfile) )
447 % (opts_all.rcfile) )
448
448
449 print opts_all.rcfile, opts_all.ipythondir
450
449 # 'profiles' are a shorthand notation for config filenames
451 # 'profiles' are a shorthand notation for config filenames
450 profile_handled_by_legacy = False
452 profile_handled_by_legacy = False
451 if opts_all.profile:
453 if opts_all.profile:
452
454
453 try:
455 try:
454 opts_all.rcfile = filefind('ipythonrc-' + opts_all.profile
456 opts_all.rcfile = filefind('ipythonrc-' + opts_all.profile
455 + rc_suffix,
457 + rc_suffix,
456 opts_all.ipythondir)
458 opts_all.ipythondir)
457 profile_handled_by_legacy = True
459 profile_handled_by_legacy = True
458 except IOError:
460 except IOError:
459 if opts_all.debug: IP.InteractiveTB()
461 if opts_all.debug: IP.InteractiveTB()
460 opts.profile = '' # remove profile from options if invalid
462 opts.profile = '' # remove profile from options if invalid
461 # We won't warn anymore, primary method is ipy_profile_PROFNAME
463 # We won't warn anymore, primary method is ipy_profile_PROFNAME
462 # which does trigger a warning.
464 # which does trigger a warning.
463
465
464 # load the config file
466 # load the config file
465 rcfiledata = None
467 rcfiledata = None
466 if opts_all.quick:
468 if opts_all.quick:
467 print 'Launching IPython in quick mode. No config file read.'
469 print 'Launching IPython in quick mode. No config file read.'
468 elif opts_all.rcfile:
470 elif opts_all.rcfile:
469 try:
471 try:
470 cfg_loader = ConfigLoader(conflict)
472 cfg_loader = ConfigLoader(conflict)
471 rcfiledata = cfg_loader.load(opts_all.rcfile,typeconv,
473 rcfiledata = cfg_loader.load(opts_all.rcfile,typeconv,
472 'include',opts_all.ipythondir,
474 'include',opts_all.ipythondir,
473 purge = 1,
475 purge = 1,
474 unique = conflict['preserve'])
476 unique = conflict['preserve'])
475 except:
477 except:
476 IP.InteractiveTB()
478 IP.InteractiveTB()
477 warn('Problems loading configuration file '+
479 warn('Problems loading configuration file '+
478 `opts_all.rcfile`+
480 `opts_all.rcfile`+
479 '\nStarting with default -bare bones- configuration.')
481 '\nStarting with default -bare bones- configuration.')
480 else:
482 else:
481 warn('No valid configuration file found in either currrent directory\n'+
483 warn('No valid configuration file found in either currrent directory\n'+
482 'or in the IPython config. directory: '+`opts_all.ipythondir`+
484 'or in the IPython config. directory: '+`opts_all.ipythondir`+
483 '\nProceeding with internal defaults.')
485 '\nProceeding with internal defaults.')
484
486
485 #------------------------------------------------------------------------
487 #------------------------------------------------------------------------
486 # Set exception handlers in mode requested by user.
488 # Set exception handlers in mode requested by user.
487 otrap = OutputTrap(trap_out=1) # trap messages from magic_xmode
489 otrap = OutputTrap(trap_out=1) # trap messages from magic_xmode
488 IP.magic_xmode(opts_all.xmode)
490 IP.magic_xmode(opts_all.xmode)
489 otrap.release_out()
491 otrap.release_out()
490
492
491 #------------------------------------------------------------------------
493 #------------------------------------------------------------------------
492 # Execute user config
494 # Execute user config
493
495
494 # Create a valid config structure with the right precedence order:
496 # Create a valid config structure with the right precedence order:
495 # defaults < rcfile < command line. This needs to be in the instance, so
497 # defaults < rcfile < command line. This needs to be in the instance, so
496 # that method calls below that rely on it find it.
498 # that method calls below that rely on it find it.
497 IP.rc = rc_def.copy()
499 IP.rc = rc_def.copy()
498
500
499 # Work with a local alias inside this routine to avoid unnecessary
501 # Work with a local alias inside this routine to avoid unnecessary
500 # attribute lookups.
502 # attribute lookups.
501 IP_rc = IP.rc
503 IP_rc = IP.rc
502
504
503 IP_rc.update(opts_def)
505 IP_rc.update(opts_def)
504 if rcfiledata:
506 if rcfiledata:
505 IP_rc.update(rcfiledata)
507 IP_rc.update(rcfiledata)
506 IP_rc.update(opts)
508 IP_rc.update(opts)
507 if rc_override is not None:
509 if rc_override is not None:
508 IP_rc.update(rc_override)
510 IP_rc.update(rc_override)
509
511
510 # Store the original cmd line for reference:
512 # Store the original cmd line for reference:
511 IP_rc.opts = opts
513 IP_rc.opts = opts
512 IP_rc.args = args
514 IP_rc.args = args
513
515
514 # create a *runtime* Struct like rc for holding parameters which may be
516 # create a *runtime* Struct like rc for holding parameters which may be
515 # created and/or modified by runtime user extensions.
517 # created and/or modified by runtime user extensions.
516 IP.runtime_rc = Struct()
518 IP.runtime_rc = Struct()
517
519
518 # from this point on, all config should be handled through IP_rc,
520 # from this point on, all config should be handled through IP_rc,
519 # opts* shouldn't be used anymore.
521 # opts* shouldn't be used anymore.
520
522
521
523
522 # update IP_rc with some special things that need manual
524 # update IP_rc with some special things that need manual
523 # tweaks. Basically options which affect other options. I guess this
525 # tweaks. Basically options which affect other options. I guess this
524 # should just be written so that options are fully orthogonal and we
526 # should just be written so that options are fully orthogonal and we
525 # wouldn't worry about this stuff!
527 # wouldn't worry about this stuff!
526
528
527 if IP_rc.classic:
529 if IP_rc.classic:
528 IP_rc.quick = 1
530 IP_rc.quick = 1
529 IP_rc.cache_size = 0
531 IP_rc.cache_size = 0
530 IP_rc.pprint = 0
532 IP_rc.pprint = 0
531 IP_rc.prompt_in1 = '>>> '
533 IP_rc.prompt_in1 = '>>> '
532 IP_rc.prompt_in2 = '... '
534 IP_rc.prompt_in2 = '... '
533 IP_rc.prompt_out = ''
535 IP_rc.prompt_out = ''
534 IP_rc.separate_in = IP_rc.separate_out = IP_rc.separate_out2 = '0'
536 IP_rc.separate_in = IP_rc.separate_out = IP_rc.separate_out2 = '0'
535 IP_rc.colors = 'NoColor'
537 IP_rc.colors = 'NoColor'
536 IP_rc.xmode = 'Plain'
538 IP_rc.xmode = 'Plain'
537
539
538 IP.pre_config_initialization()
540 IP.pre_config_initialization()
539 # configure readline
541 # configure readline
540
542
541 # update exception handlers with rc file status
543 # update exception handlers with rc file status
542 otrap.trap_out() # I don't want these messages ever.
544 otrap.trap_out() # I don't want these messages ever.
543 IP.magic_xmode(IP_rc.xmode)
545 IP.magic_xmode(IP_rc.xmode)
544 otrap.release_out()
546 otrap.release_out()
545
547
546 # activate logging if requested and not reloading a log
548 # activate logging if requested and not reloading a log
547 if IP_rc.logplay:
549 if IP_rc.logplay:
548 IP.magic_logstart(IP_rc.logplay + ' append')
550 IP.magic_logstart(IP_rc.logplay + ' append')
549 elif IP_rc.logfile:
551 elif IP_rc.logfile:
550 IP.magic_logstart(IP_rc.logfile)
552 IP.magic_logstart(IP_rc.logfile)
551 elif IP_rc.log:
553 elif IP_rc.log:
552 IP.magic_logstart()
554 IP.magic_logstart()
553
555
554 # find user editor so that it we don't have to look it up constantly
556 # find user editor so that it we don't have to look it up constantly
555 if IP_rc.editor.strip()=='0':
557 if IP_rc.editor.strip()=='0':
556 try:
558 try:
557 ed = os.environ['EDITOR']
559 ed = os.environ['EDITOR']
558 except KeyError:
560 except KeyError:
559 if os.name == 'posix':
561 if os.name == 'posix':
560 ed = 'vi' # the only one guaranteed to be there!
562 ed = 'vi' # the only one guaranteed to be there!
561 else:
563 else:
562 ed = 'notepad' # same in Windows!
564 ed = 'notepad' # same in Windows!
563 IP_rc.editor = ed
565 IP_rc.editor = ed
564
566
565 # Keep track of whether this is an embedded instance or not (useful for
567 # Keep track of whether this is an embedded instance or not (useful for
566 # post-mortems).
568 # post-mortems).
567 IP_rc.embedded = IP.embedded
569 IP_rc.embedded = IP.embedded
568
570
569 # Recursive reload
571 # Recursive reload
570 try:
572 try:
571 from IPython.lib import deepreload
573 from IPython.lib import deepreload
572 if IP_rc.deep_reload:
574 if IP_rc.deep_reload:
573 __builtin__.reload = deepreload.reload
575 __builtin__.reload = deepreload.reload
574 else:
576 else:
575 __builtin__.dreload = deepreload.reload
577 __builtin__.dreload = deepreload.reload
576 del deepreload
578 del deepreload
577 except ImportError:
579 except ImportError:
578 pass
580 pass
579
581
580 # Save the current state of our namespace so that the interactive shell
582 # Save the current state of our namespace so that the interactive shell
581 # can later know which variables have been created by us from config files
583 # can later know which variables have been created by us from config files
582 # and loading. This way, loading a file (in any way) is treated just like
584 # and loading. This way, loading a file (in any way) is treated just like
583 # defining things on the command line, and %who works as expected.
585 # defining things on the command line, and %who works as expected.
584
586
585 # DON'T do anything that affects the namespace beyond this point!
587 # DON'T do anything that affects the namespace beyond this point!
586 IP.internal_ns.update(__main__.__dict__)
588 IP.internal_ns.update(__main__.__dict__)
587
589
588 #IP.internal_ns.update(locals()) # so our stuff doesn't show up in %who
590 #IP.internal_ns.update(locals()) # so our stuff doesn't show up in %who
589
591
590 # Now run through the different sections of the users's config
592 # Now run through the different sections of the users's config
591 if IP_rc.debug:
593 if IP_rc.debug:
592 print 'Trying to execute the following configuration structure:'
594 print 'Trying to execute the following configuration structure:'
593 print '(Things listed first are deeper in the inclusion tree and get'
595 print '(Things listed first are deeper in the inclusion tree and get'
594 print 'loaded first).\n'
596 print 'loaded first).\n'
595 pprint(IP_rc.__dict__)
597 pprint(IP_rc.__dict__)
596
598
597 for mod in IP_rc.import_mod:
599 for mod in IP_rc.import_mod:
598 try:
600 try:
599 exec 'import '+mod in IP.user_ns
601 exec 'import '+mod in IP.user_ns
600 except :
602 except :
601 IP.InteractiveTB()
603 IP.InteractiveTB()
602 import_fail_info(mod)
604 import_fail_info(mod)
603
605
604 for mod_fn in IP_rc.import_some:
606 for mod_fn in IP_rc.import_some:
605 if not mod_fn == []:
607 if not mod_fn == []:
606 mod,fn = mod_fn[0],','.join(mod_fn[1:])
608 mod,fn = mod_fn[0],','.join(mod_fn[1:])
607 try:
609 try:
608 exec 'from '+mod+' import '+fn in IP.user_ns
610 exec 'from '+mod+' import '+fn in IP.user_ns
609 except :
611 except :
610 IP.InteractiveTB()
612 IP.InteractiveTB()
611 import_fail_info(mod,fn)
613 import_fail_info(mod,fn)
612
614
613 for mod in IP_rc.import_all:
615 for mod in IP_rc.import_all:
614 try:
616 try:
615 exec 'from '+mod+' import *' in IP.user_ns
617 exec 'from '+mod+' import *' in IP.user_ns
616 except :
618 except :
617 IP.InteractiveTB()
619 IP.InteractiveTB()
618 import_fail_info(mod)
620 import_fail_info(mod)
619
621
620 for code in IP_rc.execute:
622 for code in IP_rc.execute:
621 try:
623 try:
622 exec code in IP.user_ns
624 exec code in IP.user_ns
623 except:
625 except:
624 IP.InteractiveTB()
626 IP.InteractiveTB()
625 warn('Failure executing code: ' + `code`)
627 warn('Failure executing code: ' + `code`)
626
628
627 # Execute the files the user wants in ipythonrc
629 # Execute the files the user wants in ipythonrc
628 for file in IP_rc.execfile:
630 for file in IP_rc.execfile:
629 try:
631 try:
630 file = filefind(file,sys.path+[IPython_dir])
632 file = filefind(file,sys.path+[IPython_dir])
631 except IOError:
633 except IOError:
632 warn(itpl('File $file not found. Skipping it.'))
634 warn(itpl('File $file not found. Skipping it.'))
633 else:
635 else:
634 IP.safe_execfile(os.path.expanduser(file),IP.user_ns)
636 IP.safe_execfile(os.path.expanduser(file),IP.user_ns)
635
637
636 # finally, try importing ipy_*_conf for final configuration
638 # finally, try importing ipy_*_conf for final configuration
637 try:
639 try:
638 import ipy_system_conf
640 import ipy_system_conf
639 except ImportError:
641 except ImportError:
640 if opts_all.debug: IP.InteractiveTB()
642 if opts_all.debug: IP.InteractiveTB()
641 warn("Could not import 'ipy_system_conf'")
643 warn("Could not import 'ipy_system_conf'")
642 except:
644 except:
643 IP.InteractiveTB()
645 IP.InteractiveTB()
644 import_fail_info('ipy_system_conf')
646 import_fail_info('ipy_system_conf')
645
647
646 # only import prof module if ipythonrc-PROF was not found
648 # only import prof module if ipythonrc-PROF was not found
647 if opts_all.profile and not profile_handled_by_legacy:
649 if opts_all.profile and not profile_handled_by_legacy:
648 profmodname = 'ipy_profile_' + opts_all.profile
650 profmodname = 'ipy_profile_' + opts_all.profile
649 try:
651 try:
650 force_import(profmodname)
652 force_import(profmodname)
651 except:
653 except:
652 IP.InteractiveTB()
654 IP.InteractiveTB()
653 print "Error importing",profmodname,\
655 print "Error importing",profmodname,\
654 "- perhaps you should run %upgrade?"
656 "- perhaps you should run %upgrade?"
655 import_fail_info(profmodname)
657 import_fail_info(profmodname)
656 else:
658 else:
657 opts.profile = opts_all.profile
659 opts.profile = opts_all.profile
658 else:
660 else:
659 force_import('ipy_profile_none')
661 force_import('ipy_profile_none')
660 # XXX - this is wrong: ipy_user_conf should not be loaded unconditionally,
662 # XXX - this is wrong: ipy_user_conf should not be loaded unconditionally,
661 # since the user could have specified a config file path by hand.
663 # since the user could have specified a config file path by hand.
662 try:
664 try:
663 force_import('ipy_user_conf')
665 force_import('ipy_user_conf')
664 except:
666 except:
665 conf = opts_all.ipythondir + "/ipy_user_conf.py"
667 conf = opts_all.ipythondir + "/ipy_user_conf.py"
666 IP.InteractiveTB()
668 IP.InteractiveTB()
667 if not os.path.isfile(conf):
669 if not os.path.isfile(conf):
668 warn(conf + ' does not exist, please run %upgrade!')
670 warn(conf + ' does not exist, please run %upgrade!')
669
671
670 import_fail_info("ipy_user_conf")
672 import_fail_info("ipy_user_conf")
671
673
672 # Define the history file for saving commands in between sessions
674 # Define the history file for saving commands in between sessions
673 try:
675 try:
674 histfname = 'history-%s' % opts.profile
676 histfname = 'history-%s' % opts.profile
675 except AttributeError:
677 except AttributeError:
676 histfname = 'history'
678 histfname = 'history'
677 IP.histfile = os.path.join(opts_all.ipythondir,histfname)
679 IP.histfile = os.path.join(opts_all.ipythondir,histfname)
678
680
679 # finally, push the argv to options again to ensure highest priority
681 # finally, push the argv to options again to ensure highest priority
680 IP_rc.update(opts)
682 IP_rc.update(opts)
681
683
682 # release stdout and stderr and save config log into a global summary
684 # release stdout and stderr and save config log into a global summary
683 msg.config.release_all()
685 msg.config.release_all()
684 if IP_rc.messages:
686 if IP_rc.messages:
685 msg.summary += msg.config.summary_all()
687 msg.summary += msg.config.summary_all()
686
688
687 #------------------------------------------------------------------------
689 #------------------------------------------------------------------------
688 # Setup interactive session
690 # Setup interactive session
689
691
690 # Now we should be fully configured. We can then execute files or load
692 # Now we should be fully configured. We can then execute files or load
691 # things only needed for interactive use. Then we'll open the shell.
693 # things only needed for interactive use. Then we'll open the shell.
692
694
693 # Take a snapshot of the user namespace before opening the shell. That way
695 # Take a snapshot of the user namespace before opening the shell. That way
694 # we'll be able to identify which things were interactively defined and
696 # we'll be able to identify which things were interactively defined and
695 # which were defined through config files.
697 # which were defined through config files.
696 IP.user_config_ns.update(IP.user_ns)
698 IP.user_config_ns.update(IP.user_ns)
697
699
698 # Force reading a file as if it were a session log. Slower but safer.
700 # Force reading a file as if it were a session log. Slower but safer.
699 if load_logplay:
701 if load_logplay:
700 print 'Replaying log...'
702 print 'Replaying log...'
701 try:
703 try:
702 if IP_rc.debug:
704 if IP_rc.debug:
703 logplay_quiet = 0
705 logplay_quiet = 0
704 else:
706 else:
705 logplay_quiet = 1
707 logplay_quiet = 1
706
708
707 msg.logplay.trap_all()
709 msg.logplay.trap_all()
708 IP.safe_execfile(load_logplay,IP.user_ns,
710 IP.safe_execfile(load_logplay,IP.user_ns,
709 islog = 1, quiet = logplay_quiet)
711 islog = 1, quiet = logplay_quiet)
710 msg.logplay.release_all()
712 msg.logplay.release_all()
711 if IP_rc.messages:
713 if IP_rc.messages:
712 msg.summary += msg.logplay.summary_all()
714 msg.summary += msg.logplay.summary_all()
713 except:
715 except:
714 warn('Problems replaying logfile %s.' % load_logplay)
716 warn('Problems replaying logfile %s.' % load_logplay)
715 IP.InteractiveTB()
717 IP.InteractiveTB()
716
718
717 # Load remaining files in command line
719 # Load remaining files in command line
718 msg.user_exec.trap_all()
720 msg.user_exec.trap_all()
719
721
720 # Do NOT execute files named in the command line as scripts to be loaded
722 # Do NOT execute files named in the command line as scripts to be loaded
721 # by embedded instances. Doing so has the potential for an infinite
723 # by embedded instances. Doing so has the potential for an infinite
722 # recursion if there are exceptions thrown in the process.
724 # recursion if there are exceptions thrown in the process.
723
725
724 # XXX FIXME: the execution of user files should be moved out to after
726 # XXX FIXME: the execution of user files should be moved out to after
725 # ipython is fully initialized, just as if they were run via %run at the
727 # ipython is fully initialized, just as if they were run via %run at the
726 # ipython prompt. This would also give them the benefit of ipython's
728 # ipython prompt. This would also give them the benefit of ipython's
727 # nice tracebacks.
729 # nice tracebacks.
728
730
729 if (not embedded and IP_rc.args and
731 if (not embedded and IP_rc.args and
730 not IP_rc.args[0].lower().endswith('.ipy')):
732 not IP_rc.args[0].lower().endswith('.ipy')):
731 name_save = IP.user_ns['__name__']
733 name_save = IP.user_ns['__name__']
732 IP.user_ns['__name__'] = '__main__'
734 IP.user_ns['__name__'] = '__main__'
733 # Set our own excepthook in case the user code tries to call it
735 # Set our own excepthook in case the user code tries to call it
734 # directly. This prevents triggering the IPython crash handler.
736 # directly. This prevents triggering the IPython crash handler.
735 old_excepthook,sys.excepthook = sys.excepthook, IP.excepthook
737 old_excepthook,sys.excepthook = sys.excepthook, IP.excepthook
736
738
737 save_argv = sys.argv[1:] # save it for later restoring
739 save_argv = sys.argv[1:] # save it for later restoring
738
740
739 sys.argv = args
741 sys.argv = args
740
742
741 try:
743 try:
742 IP.safe_execfile(args[0], IP.user_ns)
744 IP.safe_execfile(args[0], IP.user_ns)
743 finally:
745 finally:
744 # Reset our crash handler in place
746 # Reset our crash handler in place
745 sys.excepthook = old_excepthook
747 sys.excepthook = old_excepthook
746 sys.argv[:] = save_argv
748 sys.argv[:] = save_argv
747 IP.user_ns['__name__'] = name_save
749 IP.user_ns['__name__'] = name_save
748
750
749 msg.user_exec.release_all()
751 msg.user_exec.release_all()
750
752
751 if IP_rc.messages:
753 if IP_rc.messages:
752 msg.summary += msg.user_exec.summary_all()
754 msg.summary += msg.user_exec.summary_all()
753
755
754 # since we can't specify a null string on the cmd line, 0 is the equivalent:
756 # since we can't specify a null string on the cmd line, 0 is the equivalent:
755 if IP_rc.nosep:
757 if IP_rc.nosep:
756 IP_rc.separate_in = IP_rc.separate_out = IP_rc.separate_out2 = '0'
758 IP_rc.separate_in = IP_rc.separate_out = IP_rc.separate_out2 = '0'
757 if IP_rc.separate_in == '0': IP_rc.separate_in = ''
759 if IP_rc.separate_in == '0': IP_rc.separate_in = ''
758 if IP_rc.separate_out == '0': IP_rc.separate_out = ''
760 if IP_rc.separate_out == '0': IP_rc.separate_out = ''
759 if IP_rc.separate_out2 == '0': IP_rc.separate_out2 = ''
761 if IP_rc.separate_out2 == '0': IP_rc.separate_out2 = ''
760 IP_rc.separate_in = IP_rc.separate_in.replace('\\n','\n')
762 IP_rc.separate_in = IP_rc.separate_in.replace('\\n','\n')
761 IP_rc.separate_out = IP_rc.separate_out.replace('\\n','\n')
763 IP_rc.separate_out = IP_rc.separate_out.replace('\\n','\n')
762 IP_rc.separate_out2 = IP_rc.separate_out2.replace('\\n','\n')
764 IP_rc.separate_out2 = IP_rc.separate_out2.replace('\\n','\n')
763
765
764 # Determine how many lines at the bottom of the screen are needed for
766 # Determine how many lines at the bottom of the screen are needed for
765 # showing prompts, so we can know wheter long strings are to be printed or
767 # showing prompts, so we can know wheter long strings are to be printed or
766 # paged:
768 # paged:
767 num_lines_bot = IP_rc.separate_in.count('\n')+1
769 num_lines_bot = IP_rc.separate_in.count('\n')+1
768 IP_rc.screen_length = IP_rc.screen_length - num_lines_bot
770 IP_rc.screen_length = IP_rc.screen_length - num_lines_bot
769
771
770 # configure startup banner
772 # configure startup banner
771 if IP_rc.c: # regular python doesn't print the banner with -c
773 if IP_rc.c: # regular python doesn't print the banner with -c
772 IP_rc.banner = 0
774 IP_rc.banner = 0
773 if IP_rc.banner:
775 if IP_rc.banner:
774 BANN_P = IP.BANNER_PARTS
776 BANN_P = IP.BANNER_PARTS
775 else:
777 else:
776 BANN_P = []
778 BANN_P = []
777
779
778 if IP_rc.profile: BANN_P.append('IPython profile: %s\n' % IP_rc.profile)
780 if IP_rc.profile: BANN_P.append('IPython profile: %s\n' % IP_rc.profile)
779
781
780 # add message log (possibly empty)
782 # add message log (possibly empty)
781 if msg.summary: BANN_P.append(msg.summary)
783 if msg.summary: BANN_P.append(msg.summary)
782 # Final banner is a string
784 # Final banner is a string
783 IP.BANNER = '\n'.join(BANN_P)
785 IP.BANNER = '\n'.join(BANN_P)
784
786
785 # Finalize the IPython instance. This assumes the rc structure is fully
787 # Finalize the IPython instance. This assumes the rc structure is fully
786 # in place.
788 # in place.
787 IP.post_config_initialization()
789 IP.post_config_initialization()
788
790
789 return IP
791 return IP
790 #************************ end of file <ipmaker.py> **************************
792 #************************ end of file <ipmaker.py> **************************
@@ -1,2261 +1,2284 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """General purpose utilities.
2 """General purpose utilities.
3
3
4 This is a grab-bag of stuff I find useful in most programs I write. Some of
4 This is a grab-bag of stuff I find useful in most programs I write. Some of
5 these things are also convenient when working at the command line.
5 these things are also convenient when working at the command line.
6 """
6 """
7
7
8 #*****************************************************************************
8 #*****************************************************************************
9 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
9 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #*****************************************************************************
13 #*****************************************************************************
14
14
15 #****************************************************************************
15 #****************************************************************************
16 # required modules from the Python standard library
16 # required modules from the Python standard library
17 import __main__
17 import __main__
18 import commands
18 import commands
19 try:
19 try:
20 import doctest
20 import doctest
21 except ImportError:
21 except ImportError:
22 pass
22 pass
23 import os
23 import os
24 import platform
24 import platform
25 import re
25 import re
26 import shlex
26 import shlex
27 import shutil
27 import shutil
28 import subprocess
28 import subprocess
29 import sys
29 import sys
30 import tempfile
30 import tempfile
31 import time
31 import time
32 import types
32 import types
33 import warnings
33 import warnings
34
34
35 # Curses and termios are Unix-only modules
35 # Curses and termios are Unix-only modules
36 try:
36 try:
37 import curses
37 import curses
38 # We need termios as well, so if its import happens to raise, we bail on
38 # We need termios as well, so if its import happens to raise, we bail on
39 # using curses altogether.
39 # using curses altogether.
40 import termios
40 import termios
41 except ImportError:
41 except ImportError:
42 USE_CURSES = False
42 USE_CURSES = False
43 else:
43 else:
44 # Curses on Solaris may not be complete, so we can't use it there
44 # Curses on Solaris may not be complete, so we can't use it there
45 USE_CURSES = hasattr(curses,'initscr')
45 USE_CURSES = hasattr(curses,'initscr')
46
46
47 # Other IPython utilities
47 # Other IPython utilities
48 import IPython
48 import IPython
49 from IPython.external.Itpl import Itpl,itpl,printpl
49 from IPython.external.Itpl import Itpl,itpl,printpl
50 from IPython.utils import platutils
50 from IPython.utils import platutils
51 from IPython.utils import DPyGetOpt
51 from IPython.utils import DPyGetOpt
52 from IPython.utils.generics import result_display
52 from IPython.utils.generics import result_display
53 from IPython.core import ipapi
53 from IPython.core import ipapi
54 from IPython.external.path import path
54 from IPython.external.path import path
55 if os.name == "nt":
55 if os.name == "nt":
56 from IPython.utils.winconsole import get_console_size
56 from IPython.utils.winconsole import get_console_size
57
57
58 try:
58 try:
59 set
59 set
60 except:
60 except:
61 from sets import Set as set
61 from sets import Set as set
62
62
63
63
64 #****************************************************************************
64 #****************************************************************************
65 # Exceptions
65 # Exceptions
66 class Error(Exception):
66 class Error(Exception):
67 """Base class for exceptions in this module."""
67 """Base class for exceptions in this module."""
68 pass
68 pass
69
69
70 #----------------------------------------------------------------------------
70 #----------------------------------------------------------------------------
71 class IOStream:
71 class IOStream:
72 def __init__(self,stream,fallback):
72 def __init__(self,stream,fallback):
73 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
73 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
74 stream = fallback
74 stream = fallback
75 self.stream = stream
75 self.stream = stream
76 self._swrite = stream.write
76 self._swrite = stream.write
77 self.flush = stream.flush
77 self.flush = stream.flush
78
78
79 def write(self,data):
79 def write(self,data):
80 try:
80 try:
81 self._swrite(data)
81 self._swrite(data)
82 except:
82 except:
83 try:
83 try:
84 # print handles some unicode issues which may trip a plain
84 # print handles some unicode issues which may trip a plain
85 # write() call. Attempt to emulate write() by using a
85 # write() call. Attempt to emulate write() by using a
86 # trailing comma
86 # trailing comma
87 print >> self.stream, data,
87 print >> self.stream, data,
88 except:
88 except:
89 # if we get here, something is seriously broken.
89 # if we get here, something is seriously broken.
90 print >> sys.stderr, \
90 print >> sys.stderr, \
91 'ERROR - failed to write data to stream:', self.stream
91 'ERROR - failed to write data to stream:', self.stream
92
92
93 def close(self):
93 def close(self):
94 pass
94 pass
95
95
96
96
97 class IOTerm:
97 class IOTerm:
98 """ Term holds the file or file-like objects for handling I/O operations.
98 """ Term holds the file or file-like objects for handling I/O operations.
99
99
100 These are normally just sys.stdin, sys.stdout and sys.stderr but for
100 These are normally just sys.stdin, sys.stdout and sys.stderr but for
101 Windows they can can replaced to allow editing the strings before they are
101 Windows they can can replaced to allow editing the strings before they are
102 displayed."""
102 displayed."""
103
103
104 # In the future, having IPython channel all its I/O operations through
104 # In the future, having IPython channel all its I/O operations through
105 # this class will make it easier to embed it into other environments which
105 # this class will make it easier to embed it into other environments which
106 # are not a normal terminal (such as a GUI-based shell)
106 # are not a normal terminal (such as a GUI-based shell)
107 def __init__(self,cin=None,cout=None,cerr=None):
107 def __init__(self,cin=None,cout=None,cerr=None):
108 self.cin = IOStream(cin,sys.stdin)
108 self.cin = IOStream(cin,sys.stdin)
109 self.cout = IOStream(cout,sys.stdout)
109 self.cout = IOStream(cout,sys.stdout)
110 self.cerr = IOStream(cerr,sys.stderr)
110 self.cerr = IOStream(cerr,sys.stderr)
111
111
112 # Global variable to be used for all I/O
112 # Global variable to be used for all I/O
113 Term = IOTerm()
113 Term = IOTerm()
114
114
115 import IPython.utils.rlineimpl as readline
115 import IPython.utils.rlineimpl as readline
116 # Remake Term to use the readline i/o facilities
116 # Remake Term to use the readline i/o facilities
117 if sys.platform == 'win32' and readline.have_readline:
117 if sys.platform == 'win32' and readline.have_readline:
118
118
119 Term = IOTerm(cout=readline._outputfile,cerr=readline._outputfile)
119 Term = IOTerm(cout=readline._outputfile,cerr=readline._outputfile)
120
120
121
121
122 #****************************************************************************
122 #****************************************************************************
123 # Generic warning/error printer, used by everything else
123 # Generic warning/error printer, used by everything else
124 def warn(msg,level=2,exit_val=1):
124 def warn(msg,level=2,exit_val=1):
125 """Standard warning printer. Gives formatting consistency.
125 """Standard warning printer. Gives formatting consistency.
126
126
127 Output is sent to Term.cerr (sys.stderr by default).
127 Output is sent to Term.cerr (sys.stderr by default).
128
128
129 Options:
129 Options:
130
130
131 -level(2): allows finer control:
131 -level(2): allows finer control:
132 0 -> Do nothing, dummy function.
132 0 -> Do nothing, dummy function.
133 1 -> Print message.
133 1 -> Print message.
134 2 -> Print 'WARNING:' + message. (Default level).
134 2 -> Print 'WARNING:' + message. (Default level).
135 3 -> Print 'ERROR:' + message.
135 3 -> Print 'ERROR:' + message.
136 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
136 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
137
137
138 -exit_val (1): exit value returned by sys.exit() for a level 4
138 -exit_val (1): exit value returned by sys.exit() for a level 4
139 warning. Ignored for all other levels."""
139 warning. Ignored for all other levels."""
140
140
141 if level>0:
141 if level>0:
142 header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
142 header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
143 print >> Term.cerr, '%s%s' % (header[level],msg)
143 print >> Term.cerr, '%s%s' % (header[level],msg)
144 if level == 4:
144 if level == 4:
145 print >> Term.cerr,'Exiting.\n'
145 print >> Term.cerr,'Exiting.\n'
146 sys.exit(exit_val)
146 sys.exit(exit_val)
147
147
148 def info(msg):
148 def info(msg):
149 """Equivalent to warn(msg,level=1)."""
149 """Equivalent to warn(msg,level=1)."""
150
150
151 warn(msg,level=1)
151 warn(msg,level=1)
152
152
153 def error(msg):
153 def error(msg):
154 """Equivalent to warn(msg,level=3)."""
154 """Equivalent to warn(msg,level=3)."""
155
155
156 warn(msg,level=3)
156 warn(msg,level=3)
157
157
158 def fatal(msg,exit_val=1):
158 def fatal(msg,exit_val=1):
159 """Equivalent to warn(msg,exit_val=exit_val,level=4)."""
159 """Equivalent to warn(msg,exit_val=exit_val,level=4)."""
160
160
161 warn(msg,exit_val=exit_val,level=4)
161 warn(msg,exit_val=exit_val,level=4)
162
162
163 #---------------------------------------------------------------------------
163 #---------------------------------------------------------------------------
164 # Debugging routines
164 # Debugging routines
165 #
165 #
166 def debugx(expr,pre_msg=''):
166 def debugx(expr,pre_msg=''):
167 """Print the value of an expression from the caller's frame.
167 """Print the value of an expression from the caller's frame.
168
168
169 Takes an expression, evaluates it in the caller's frame and prints both
169 Takes an expression, evaluates it in the caller's frame and prints both
170 the given expression and the resulting value (as well as a debug mark
170 the given expression and the resulting value (as well as a debug mark
171 indicating the name of the calling function. The input must be of a form
171 indicating the name of the calling function. The input must be of a form
172 suitable for eval().
172 suitable for eval().
173
173
174 An optional message can be passed, which will be prepended to the printed
174 An optional message can be passed, which will be prepended to the printed
175 expr->value pair."""
175 expr->value pair."""
176
176
177 cf = sys._getframe(1)
177 cf = sys._getframe(1)
178 print '[DBG:%s] %s%s -> %r' % (cf.f_code.co_name,pre_msg,expr,
178 print '[DBG:%s] %s%s -> %r' % (cf.f_code.co_name,pre_msg,expr,
179 eval(expr,cf.f_globals,cf.f_locals))
179 eval(expr,cf.f_globals,cf.f_locals))
180
180
181 # deactivate it by uncommenting the following line, which makes it a no-op
181 # deactivate it by uncommenting the following line, which makes it a no-op
182 #def debugx(expr,pre_msg=''): pass
182 #def debugx(expr,pre_msg=''): pass
183
183
184 #----------------------------------------------------------------------------
184 #----------------------------------------------------------------------------
185 StringTypes = types.StringTypes
185 StringTypes = types.StringTypes
186
186
187 # Basic timing functionality
187 # Basic timing functionality
188
188
189 # If possible (Unix), use the resource module instead of time.clock()
189 # If possible (Unix), use the resource module instead of time.clock()
190 try:
190 try:
191 import resource
191 import resource
192 def clocku():
192 def clocku():
193 """clocku() -> floating point number
193 """clocku() -> floating point number
194
194
195 Return the *USER* CPU time in seconds since the start of the process.
195 Return the *USER* CPU time in seconds since the start of the process.
196 This is done via a call to resource.getrusage, so it avoids the
196 This is done via a call to resource.getrusage, so it avoids the
197 wraparound problems in time.clock()."""
197 wraparound problems in time.clock()."""
198
198
199 return resource.getrusage(resource.RUSAGE_SELF)[0]
199 return resource.getrusage(resource.RUSAGE_SELF)[0]
200
200
201 def clocks():
201 def clocks():
202 """clocks() -> floating point number
202 """clocks() -> floating point number
203
203
204 Return the *SYSTEM* CPU time in seconds since the start of the process.
204 Return the *SYSTEM* CPU time in seconds since the start of the process.
205 This is done via a call to resource.getrusage, so it avoids the
205 This is done via a call to resource.getrusage, so it avoids the
206 wraparound problems in time.clock()."""
206 wraparound problems in time.clock()."""
207
207
208 return resource.getrusage(resource.RUSAGE_SELF)[1]
208 return resource.getrusage(resource.RUSAGE_SELF)[1]
209
209
210 def clock():
210 def clock():
211 """clock() -> floating point number
211 """clock() -> floating point number
212
212
213 Return the *TOTAL USER+SYSTEM* CPU time in seconds since the start of
213 Return the *TOTAL USER+SYSTEM* CPU time in seconds since the start of
214 the process. This is done via a call to resource.getrusage, so it
214 the process. This is done via a call to resource.getrusage, so it
215 avoids the wraparound problems in time.clock()."""
215 avoids the wraparound problems in time.clock()."""
216
216
217 u,s = resource.getrusage(resource.RUSAGE_SELF)[:2]
217 u,s = resource.getrusage(resource.RUSAGE_SELF)[:2]
218 return u+s
218 return u+s
219
219
220 def clock2():
220 def clock2():
221 """clock2() -> (t_user,t_system)
221 """clock2() -> (t_user,t_system)
222
222
223 Similar to clock(), but return a tuple of user/system times."""
223 Similar to clock(), but return a tuple of user/system times."""
224 return resource.getrusage(resource.RUSAGE_SELF)[:2]
224 return resource.getrusage(resource.RUSAGE_SELF)[:2]
225
225
226 except ImportError:
226 except ImportError:
227 # There is no distinction of user/system time under windows, so we just use
227 # There is no distinction of user/system time under windows, so we just use
228 # time.clock() for everything...
228 # time.clock() for everything...
229 clocku = clocks = clock = time.clock
229 clocku = clocks = clock = time.clock
230 def clock2():
230 def clock2():
231 """Under windows, system CPU time can't be measured.
231 """Under windows, system CPU time can't be measured.
232
232
233 This just returns clock() and zero."""
233 This just returns clock() and zero."""
234 return time.clock(),0.0
234 return time.clock(),0.0
235
235
236 def timings_out(reps,func,*args,**kw):
236 def timings_out(reps,func,*args,**kw):
237 """timings_out(reps,func,*args,**kw) -> (t_total,t_per_call,output)
237 """timings_out(reps,func,*args,**kw) -> (t_total,t_per_call,output)
238
238
239 Execute a function reps times, return a tuple with the elapsed total
239 Execute a function reps times, return a tuple with the elapsed total
240 CPU time in seconds, the time per call and the function's output.
240 CPU time in seconds, the time per call and the function's output.
241
241
242 Under Unix, the return value is the sum of user+system time consumed by
242 Under Unix, the return value is the sum of user+system time consumed by
243 the process, computed via the resource module. This prevents problems
243 the process, computed via the resource module. This prevents problems
244 related to the wraparound effect which the time.clock() function has.
244 related to the wraparound effect which the time.clock() function has.
245
245
246 Under Windows the return value is in wall clock seconds. See the
246 Under Windows the return value is in wall clock seconds. See the
247 documentation for the time module for more details."""
247 documentation for the time module for more details."""
248
248
249 reps = int(reps)
249 reps = int(reps)
250 assert reps >=1, 'reps must be >= 1'
250 assert reps >=1, 'reps must be >= 1'
251 if reps==1:
251 if reps==1:
252 start = clock()
252 start = clock()
253 out = func(*args,**kw)
253 out = func(*args,**kw)
254 tot_time = clock()-start
254 tot_time = clock()-start
255 else:
255 else:
256 rng = xrange(reps-1) # the last time is executed separately to store output
256 rng = xrange(reps-1) # the last time is executed separately to store output
257 start = clock()
257 start = clock()
258 for dummy in rng: func(*args,**kw)
258 for dummy in rng: func(*args,**kw)
259 out = func(*args,**kw) # one last time
259 out = func(*args,**kw) # one last time
260 tot_time = clock()-start
260 tot_time = clock()-start
261 av_time = tot_time / reps
261 av_time = tot_time / reps
262 return tot_time,av_time,out
262 return tot_time,av_time,out
263
263
264 def timings(reps,func,*args,**kw):
264 def timings(reps,func,*args,**kw):
265 """timings(reps,func,*args,**kw) -> (t_total,t_per_call)
265 """timings(reps,func,*args,**kw) -> (t_total,t_per_call)
266
266
267 Execute a function reps times, return a tuple with the elapsed total CPU
267 Execute a function reps times, return a tuple with the elapsed total CPU
268 time in seconds and the time per call. These are just the first two values
268 time in seconds and the time per call. These are just the first two values
269 in timings_out()."""
269 in timings_out()."""
270
270
271 return timings_out(reps,func,*args,**kw)[0:2]
271 return timings_out(reps,func,*args,**kw)[0:2]
272
272
273 def timing(func,*args,**kw):
273 def timing(func,*args,**kw):
274 """timing(func,*args,**kw) -> t_total
274 """timing(func,*args,**kw) -> t_total
275
275
276 Execute a function once, return the elapsed total CPU time in
276 Execute a function once, return the elapsed total CPU time in
277 seconds. This is just the first value in timings_out()."""
277 seconds. This is just the first value in timings_out()."""
278
278
279 return timings_out(1,func,*args,**kw)[0]
279 return timings_out(1,func,*args,**kw)[0]
280
280
281 #****************************************************************************
281 #****************************************************************************
282 # file and system
282 # file and system
283
283
284 def arg_split(s,posix=False):
284 def arg_split(s,posix=False):
285 """Split a command line's arguments in a shell-like manner.
285 """Split a command line's arguments in a shell-like manner.
286
286
287 This is a modified version of the standard library's shlex.split()
287 This is a modified version of the standard library's shlex.split()
288 function, but with a default of posix=False for splitting, so that quotes
288 function, but with a default of posix=False for splitting, so that quotes
289 in inputs are respected."""
289 in inputs are respected."""
290
290
291 # XXX - there may be unicode-related problems here!!! I'm not sure that
291 # XXX - there may be unicode-related problems here!!! I'm not sure that
292 # shlex is truly unicode-safe, so it might be necessary to do
292 # shlex is truly unicode-safe, so it might be necessary to do
293 #
293 #
294 # s = s.encode(sys.stdin.encoding)
294 # s = s.encode(sys.stdin.encoding)
295 #
295 #
296 # first, to ensure that shlex gets a normal string. Input from anyone who
296 # first, to ensure that shlex gets a normal string. Input from anyone who
297 # knows more about unicode and shlex than I would be good to have here...
297 # knows more about unicode and shlex than I would be good to have here...
298 lex = shlex.shlex(s, posix=posix)
298 lex = shlex.shlex(s, posix=posix)
299 lex.whitespace_split = True
299 lex.whitespace_split = True
300 return list(lex)
300 return list(lex)
301
301
302 def system(cmd,verbose=0,debug=0,header=''):
302 def system(cmd,verbose=0,debug=0,header=''):
303 """Execute a system command, return its exit status.
303 """Execute a system command, return its exit status.
304
304
305 Options:
305 Options:
306
306
307 - verbose (0): print the command to be executed.
307 - verbose (0): print the command to be executed.
308
308
309 - debug (0): only print, do not actually execute.
309 - debug (0): only print, do not actually execute.
310
310
311 - header (''): Header to print on screen prior to the executed command (it
311 - header (''): Header to print on screen prior to the executed command (it
312 is only prepended to the command, no newlines are added).
312 is only prepended to the command, no newlines are added).
313
313
314 Note: a stateful version of this function is available through the
314 Note: a stateful version of this function is available through the
315 SystemExec class."""
315 SystemExec class."""
316
316
317 stat = 0
317 stat = 0
318 if verbose or debug: print header+cmd
318 if verbose or debug: print header+cmd
319 sys.stdout.flush()
319 sys.stdout.flush()
320 if not debug: stat = os.system(cmd)
320 if not debug: stat = os.system(cmd)
321 return stat
321 return stat
322
322
323 def abbrev_cwd():
323 def abbrev_cwd():
324 """ Return abbreviated version of cwd, e.g. d:mydir """
324 """ Return abbreviated version of cwd, e.g. d:mydir """
325 cwd = os.getcwd().replace('\\','/')
325 cwd = os.getcwd().replace('\\','/')
326 drivepart = ''
326 drivepart = ''
327 tail = cwd
327 tail = cwd
328 if sys.platform == 'win32':
328 if sys.platform == 'win32':
329 if len(cwd) < 4:
329 if len(cwd) < 4:
330 return cwd
330 return cwd
331 drivepart,tail = os.path.splitdrive(cwd)
331 drivepart,tail = os.path.splitdrive(cwd)
332
332
333
333
334 parts = tail.split('/')
334 parts = tail.split('/')
335 if len(parts) > 2:
335 if len(parts) > 2:
336 tail = '/'.join(parts[-2:])
336 tail = '/'.join(parts[-2:])
337
337
338 return (drivepart + (
338 return (drivepart + (
339 cwd == '/' and '/' or tail))
339 cwd == '/' and '/' or tail))
340
340
341
341
342 # This function is used by ipython in a lot of places to make system calls.
342 # This function is used by ipython in a lot of places to make system calls.
343 # We need it to be slightly different under win32, due to the vagaries of
343 # We need it to be slightly different under win32, due to the vagaries of
344 # 'network shares'. A win32 override is below.
344 # 'network shares'. A win32 override is below.
345
345
346 def shell(cmd,verbose=0,debug=0,header=''):
346 def shell(cmd,verbose=0,debug=0,header=''):
347 """Execute a command in the system shell, always return None.
347 """Execute a command in the system shell, always return None.
348
348
349 Options:
349 Options:
350
350
351 - verbose (0): print the command to be executed.
351 - verbose (0): print the command to be executed.
352
352
353 - debug (0): only print, do not actually execute.
353 - debug (0): only print, do not actually execute.
354
354
355 - header (''): Header to print on screen prior to the executed command (it
355 - header (''): Header to print on screen prior to the executed command (it
356 is only prepended to the command, no newlines are added).
356 is only prepended to the command, no newlines are added).
357
357
358 Note: this is similar to genutils.system(), but it returns None so it can
358 Note: this is similar to genutils.system(), but it returns None so it can
359 be conveniently used in interactive loops without getting the return value
359 be conveniently used in interactive loops without getting the return value
360 (typically 0) printed many times."""
360 (typically 0) printed many times."""
361
361
362 stat = 0
362 stat = 0
363 if verbose or debug: print header+cmd
363 if verbose or debug: print header+cmd
364 # flush stdout so we don't mangle python's buffering
364 # flush stdout so we don't mangle python's buffering
365 sys.stdout.flush()
365 sys.stdout.flush()
366
366
367 if not debug:
367 if not debug:
368 platutils.set_term_title("IPy " + cmd)
368 platutils.set_term_title("IPy " + cmd)
369 os.system(cmd)
369 os.system(cmd)
370 platutils.set_term_title("IPy " + abbrev_cwd())
370 platutils.set_term_title("IPy " + abbrev_cwd())
371
371
372 # override shell() for win32 to deal with network shares
372 # override shell() for win32 to deal with network shares
373 if os.name in ('nt','dos'):
373 if os.name in ('nt','dos'):
374
374
375 shell_ori = shell
375 shell_ori = shell
376
376
377 def shell(cmd,verbose=0,debug=0,header=''):
377 def shell(cmd,verbose=0,debug=0,header=''):
378 if os.getcwd().startswith(r"\\"):
378 if os.getcwd().startswith(r"\\"):
379 path = os.getcwd()
379 path = os.getcwd()
380 # change to c drive (cannot be on UNC-share when issuing os.system,
380 # change to c drive (cannot be on UNC-share when issuing os.system,
381 # as cmd.exe cannot handle UNC addresses)
381 # as cmd.exe cannot handle UNC addresses)
382 os.chdir("c:")
382 os.chdir("c:")
383 # issue pushd to the UNC-share and then run the command
383 # issue pushd to the UNC-share and then run the command
384 try:
384 try:
385 shell_ori('"pushd %s&&"'%path+cmd,verbose,debug,header)
385 shell_ori('"pushd %s&&"'%path+cmd,verbose,debug,header)
386 finally:
386 finally:
387 os.chdir(path)
387 os.chdir(path)
388 else:
388 else:
389 shell_ori(cmd,verbose,debug,header)
389 shell_ori(cmd,verbose,debug,header)
390
390
391 shell.__doc__ = shell_ori.__doc__
391 shell.__doc__ = shell_ori.__doc__
392
392
393 def getoutput(cmd,verbose=0,debug=0,header='',split=0):
393 def getoutput(cmd,verbose=0,debug=0,header='',split=0):
394 """Dummy substitute for perl's backquotes.
394 """Dummy substitute for perl's backquotes.
395
395
396 Executes a command and returns the output.
396 Executes a command and returns the output.
397
397
398 Accepts the same arguments as system(), plus:
398 Accepts the same arguments as system(), plus:
399
399
400 - split(0): if true, the output is returned as a list split on newlines.
400 - split(0): if true, the output is returned as a list split on newlines.
401
401
402 Note: a stateful version of this function is available through the
402 Note: a stateful version of this function is available through the
403 SystemExec class.
403 SystemExec class.
404
404
405 This is pretty much deprecated and rarely used,
405 This is pretty much deprecated and rarely used,
406 genutils.getoutputerror may be what you need.
406 genutils.getoutputerror may be what you need.
407
407
408 """
408 """
409
409
410 if verbose or debug: print header+cmd
410 if verbose or debug: print header+cmd
411 if not debug:
411 if not debug:
412 output = os.popen(cmd).read()
412 output = os.popen(cmd).read()
413 # stipping last \n is here for backwards compat.
413 # stipping last \n is here for backwards compat.
414 if output.endswith('\n'):
414 if output.endswith('\n'):
415 output = output[:-1]
415 output = output[:-1]
416 if split:
416 if split:
417 return output.split('\n')
417 return output.split('\n')
418 else:
418 else:
419 return output
419 return output
420
420
421 def getoutputerror(cmd,verbose=0,debug=0,header='',split=0):
421 def getoutputerror(cmd,verbose=0,debug=0,header='',split=0):
422 """Return (standard output,standard error) of executing cmd in a shell.
422 """Return (standard output,standard error) of executing cmd in a shell.
423
423
424 Accepts the same arguments as system(), plus:
424 Accepts the same arguments as system(), plus:
425
425
426 - split(0): if true, each of stdout/err is returned as a list split on
426 - split(0): if true, each of stdout/err is returned as a list split on
427 newlines.
427 newlines.
428
428
429 Note: a stateful version of this function is available through the
429 Note: a stateful version of this function is available through the
430 SystemExec class."""
430 SystemExec class."""
431
431
432 if verbose or debug: print header+cmd
432 if verbose or debug: print header+cmd
433 if not cmd:
433 if not cmd:
434 if split:
434 if split:
435 return [],[]
435 return [],[]
436 else:
436 else:
437 return '',''
437 return '',''
438 if not debug:
438 if not debug:
439 pin,pout,perr = os.popen3(cmd)
439 pin,pout,perr = os.popen3(cmd)
440 tout = pout.read().rstrip()
440 tout = pout.read().rstrip()
441 terr = perr.read().rstrip()
441 terr = perr.read().rstrip()
442 pin.close()
442 pin.close()
443 pout.close()
443 pout.close()
444 perr.close()
444 perr.close()
445 if split:
445 if split:
446 return tout.split('\n'),terr.split('\n')
446 return tout.split('\n'),terr.split('\n')
447 else:
447 else:
448 return tout,terr
448 return tout,terr
449
449
450 # for compatibility with older naming conventions
450 # for compatibility with older naming conventions
451 xsys = system
451 xsys = system
452 bq = getoutput
452 bq = getoutput
453
453
454 class SystemExec:
454 class SystemExec:
455 """Access the system and getoutput functions through a stateful interface.
455 """Access the system and getoutput functions through a stateful interface.
456
456
457 Note: here we refer to the system and getoutput functions from this
457 Note: here we refer to the system and getoutput functions from this
458 library, not the ones from the standard python library.
458 library, not the ones from the standard python library.
459
459
460 This class offers the system and getoutput functions as methods, but the
460 This class offers the system and getoutput functions as methods, but the
461 verbose, debug and header parameters can be set for the instance (at
461 verbose, debug and header parameters can be set for the instance (at
462 creation time or later) so that they don't need to be specified on each
462 creation time or later) so that they don't need to be specified on each
463 call.
463 call.
464
464
465 For efficiency reasons, there's no way to override the parameters on a
465 For efficiency reasons, there's no way to override the parameters on a
466 per-call basis other than by setting instance attributes. If you need
466 per-call basis other than by setting instance attributes. If you need
467 local overrides, it's best to directly call system() or getoutput().
467 local overrides, it's best to directly call system() or getoutput().
468
468
469 The following names are provided as alternate options:
469 The following names are provided as alternate options:
470 - xsys: alias to system
470 - xsys: alias to system
471 - bq: alias to getoutput
471 - bq: alias to getoutput
472
472
473 An instance can then be created as:
473 An instance can then be created as:
474 >>> sysexec = SystemExec(verbose=1,debug=0,header='Calling: ')
474 >>> sysexec = SystemExec(verbose=1,debug=0,header='Calling: ')
475 """
475 """
476
476
477 def __init__(self,verbose=0,debug=0,header='',split=0):
477 def __init__(self,verbose=0,debug=0,header='',split=0):
478 """Specify the instance's values for verbose, debug and header."""
478 """Specify the instance's values for verbose, debug and header."""
479 setattr_list(self,'verbose debug header split')
479 setattr_list(self,'verbose debug header split')
480
480
481 def system(self,cmd):
481 def system(self,cmd):
482 """Stateful interface to system(), with the same keyword parameters."""
482 """Stateful interface to system(), with the same keyword parameters."""
483
483
484 system(cmd,self.verbose,self.debug,self.header)
484 system(cmd,self.verbose,self.debug,self.header)
485
485
486 def shell(self,cmd):
486 def shell(self,cmd):
487 """Stateful interface to shell(), with the same keyword parameters."""
487 """Stateful interface to shell(), with the same keyword parameters."""
488
488
489 shell(cmd,self.verbose,self.debug,self.header)
489 shell(cmd,self.verbose,self.debug,self.header)
490
490
491 xsys = system # alias
491 xsys = system # alias
492
492
493 def getoutput(self,cmd):
493 def getoutput(self,cmd):
494 """Stateful interface to getoutput()."""
494 """Stateful interface to getoutput()."""
495
495
496 return getoutput(cmd,self.verbose,self.debug,self.header,self.split)
496 return getoutput(cmd,self.verbose,self.debug,self.header,self.split)
497
497
498 def getoutputerror(self,cmd):
498 def getoutputerror(self,cmd):
499 """Stateful interface to getoutputerror()."""
499 """Stateful interface to getoutputerror()."""
500
500
501 return getoutputerror(cmd,self.verbose,self.debug,self.header,self.split)
501 return getoutputerror(cmd,self.verbose,self.debug,self.header,self.split)
502
502
503 bq = getoutput # alias
503 bq = getoutput # alias
504
504
505 #-----------------------------------------------------------------------------
505 #-----------------------------------------------------------------------------
506 def mutex_opts(dict,ex_op):
506 def mutex_opts(dict,ex_op):
507 """Check for presence of mutually exclusive keys in a dict.
507 """Check for presence of mutually exclusive keys in a dict.
508
508
509 Call: mutex_opts(dict,[[op1a,op1b],[op2a,op2b]...]"""
509 Call: mutex_opts(dict,[[op1a,op1b],[op2a,op2b]...]"""
510 for op1,op2 in ex_op:
510 for op1,op2 in ex_op:
511 if op1 in dict and op2 in dict:
511 if op1 in dict and op2 in dict:
512 raise ValueError,'\n*** ERROR in Arguments *** '\
512 raise ValueError,'\n*** ERROR in Arguments *** '\
513 'Options '+op1+' and '+op2+' are mutually exclusive.'
513 'Options '+op1+' and '+op2+' are mutually exclusive.'
514
514
515 #-----------------------------------------------------------------------------
515 #-----------------------------------------------------------------------------
516 def get_py_filename(name):
516 def get_py_filename(name):
517 """Return a valid python filename in the current directory.
517 """Return a valid python filename in the current directory.
518
518
519 If the given name is not a file, it adds '.py' and searches again.
519 If the given name is not a file, it adds '.py' and searches again.
520 Raises IOError with an informative message if the file isn't found."""
520 Raises IOError with an informative message if the file isn't found."""
521
521
522 name = os.path.expanduser(name)
522 name = os.path.expanduser(name)
523 if not os.path.isfile(name) and not name.endswith('.py'):
523 if not os.path.isfile(name) and not name.endswith('.py'):
524 name += '.py'
524 name += '.py'
525 if os.path.isfile(name):
525 if os.path.isfile(name):
526 return name
526 return name
527 else:
527 else:
528 raise IOError,'File `%s` not found.' % name
528 raise IOError,'File `%s` not found.' % name
529
529
530 #-----------------------------------------------------------------------------
530 #-----------------------------------------------------------------------------
531 def filefind(fname,alt_dirs = None):
532 """Return the given filename either in the current directory, if it
533 exists, or in a specified list of directories.
534
531
535 ~ expansion is done on all file and directory names.
536
532
537 Upon an unsuccessful search, raise an IOError exception."""
533 def filefind(filename, path_dirs=None):
534 """Find a file by looking through a sequence of paths.
538
535
539 if alt_dirs is None:
536 This iterates through a sequence of paths looking for a file and returns
540 try:
537 the full, absolute path of the first occurence of the file. If no set of
541 alt_dirs = get_home_dir()
538 path dirs is given, the filename is tested as is, after running through
542 except HomeDirError:
539 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
543 alt_dirs = os.getcwd()
540
544 search = [fname] + list_strings(alt_dirs)
541 filefind('myfile.txt')
545 search = map(os.path.expanduser,search)
542
546 #print 'search list for',fname,'list:',search # dbg
543 will find the file in the current working dir, but::
547 fname = search[0]
544
548 if os.path.isfile(fname):
545 filefind('~/myfile.txt')
549 return fname
546
550 for direc in search[1:]:
547 Will find the file in the users home directory. This function does not
551 testname = os.path.join(direc,fname)
548 automatically try any paths, such as the cwd or the user's home directory.
552 #print 'testname',testname # dbg
549
550 Parameters
551 ----------
552 filename : str
553 The filename to look for.
554 path_dirs : str, None or sequence of str
555 The sequence of paths to look for the file in. If None, the filename
556 need to be absolute or be in the cwd. If a string, the string is
557 put into a sequence and the searched. If a sequence, walk through
558 each element and join with ``filename``, calling :func:`expandvars`
559 and :func:`expanduser` before testing for existence.
560
561 Returns
562 -------
563 Raises :exc:`IOError` or returns absolute path to file.
564 """
565 if path_dirs is None:
566 path_dirs = ("",)
567 elif isinstance(path_dirs, basestring):
568 path_dirs = (path_dirs,)
569 for path in path_dirs:
570 if path == '.': path = os.getcwd()
571 testname = os.path.expandvars(
572 os.path.expanduser(
573 os.path.join(path, filename)))
553 if os.path.isfile(testname):
574 if os.path.isfile(testname):
554 return testname
575 return os.path.abspath(testname)
555 raise IOError,'File' + `fname` + \
576 raise IOError("File does not exist in any "
556 ' not found in current or supplied directories:' + `alt_dirs`
577 "of the search paths: %r, %r" % \
578 (filename, path_dirs))
579
557
580
558 #----------------------------------------------------------------------------
581 #----------------------------------------------------------------------------
559 def file_read(filename):
582 def file_read(filename):
560 """Read a file and close it. Returns the file source."""
583 """Read a file and close it. Returns the file source."""
561 fobj = open(filename,'r');
584 fobj = open(filename,'r');
562 source = fobj.read();
585 source = fobj.read();
563 fobj.close()
586 fobj.close()
564 return source
587 return source
565
588
566 def file_readlines(filename):
589 def file_readlines(filename):
567 """Read a file and close it. Returns the file source using readlines()."""
590 """Read a file and close it. Returns the file source using readlines()."""
568 fobj = open(filename,'r');
591 fobj = open(filename,'r');
569 lines = fobj.readlines();
592 lines = fobj.readlines();
570 fobj.close()
593 fobj.close()
571 return lines
594 return lines
572
595
573 #----------------------------------------------------------------------------
596 #----------------------------------------------------------------------------
574 def target_outdated(target,deps):
597 def target_outdated(target,deps):
575 """Determine whether a target is out of date.
598 """Determine whether a target is out of date.
576
599
577 target_outdated(target,deps) -> 1/0
600 target_outdated(target,deps) -> 1/0
578
601
579 deps: list of filenames which MUST exist.
602 deps: list of filenames which MUST exist.
580 target: single filename which may or may not exist.
603 target: single filename which may or may not exist.
581
604
582 If target doesn't exist or is older than any file listed in deps, return
605 If target doesn't exist or is older than any file listed in deps, return
583 true, otherwise return false.
606 true, otherwise return false.
584 """
607 """
585 try:
608 try:
586 target_time = os.path.getmtime(target)
609 target_time = os.path.getmtime(target)
587 except os.error:
610 except os.error:
588 return 1
611 return 1
589 for dep in deps:
612 for dep in deps:
590 dep_time = os.path.getmtime(dep)
613 dep_time = os.path.getmtime(dep)
591 if dep_time > target_time:
614 if dep_time > target_time:
592 #print "For target",target,"Dep failed:",dep # dbg
615 #print "For target",target,"Dep failed:",dep # dbg
593 #print "times (dep,tar):",dep_time,target_time # dbg
616 #print "times (dep,tar):",dep_time,target_time # dbg
594 return 1
617 return 1
595 return 0
618 return 0
596
619
597 #-----------------------------------------------------------------------------
620 #-----------------------------------------------------------------------------
598 def target_update(target,deps,cmd):
621 def target_update(target,deps,cmd):
599 """Update a target with a given command given a list of dependencies.
622 """Update a target with a given command given a list of dependencies.
600
623
601 target_update(target,deps,cmd) -> runs cmd if target is outdated.
624 target_update(target,deps,cmd) -> runs cmd if target is outdated.
602
625
603 This is just a wrapper around target_outdated() which calls the given
626 This is just a wrapper around target_outdated() which calls the given
604 command if target is outdated."""
627 command if target is outdated."""
605
628
606 if target_outdated(target,deps):
629 if target_outdated(target,deps):
607 xsys(cmd)
630 xsys(cmd)
608
631
609 #----------------------------------------------------------------------------
632 #----------------------------------------------------------------------------
610 def unquote_ends(istr):
633 def unquote_ends(istr):
611 """Remove a single pair of quotes from the endpoints of a string."""
634 """Remove a single pair of quotes from the endpoints of a string."""
612
635
613 if not istr:
636 if not istr:
614 return istr
637 return istr
615 if (istr[0]=="'" and istr[-1]=="'") or \
638 if (istr[0]=="'" and istr[-1]=="'") or \
616 (istr[0]=='"' and istr[-1]=='"'):
639 (istr[0]=='"' and istr[-1]=='"'):
617 return istr[1:-1]
640 return istr[1:-1]
618 else:
641 else:
619 return istr
642 return istr
620
643
621 #----------------------------------------------------------------------------
644 #----------------------------------------------------------------------------
622 def process_cmdline(argv,names=[],defaults={},usage=''):
645 def process_cmdline(argv,names=[],defaults={},usage=''):
623 """ Process command-line options and arguments.
646 """ Process command-line options and arguments.
624
647
625 Arguments:
648 Arguments:
626
649
627 - argv: list of arguments, typically sys.argv.
650 - argv: list of arguments, typically sys.argv.
628
651
629 - names: list of option names. See DPyGetOpt docs for details on options
652 - names: list of option names. See DPyGetOpt docs for details on options
630 syntax.
653 syntax.
631
654
632 - defaults: dict of default values.
655 - defaults: dict of default values.
633
656
634 - usage: optional usage notice to print if a wrong argument is passed.
657 - usage: optional usage notice to print if a wrong argument is passed.
635
658
636 Return a dict of options and a list of free arguments."""
659 Return a dict of options and a list of free arguments."""
637
660
638 getopt = DPyGetOpt.DPyGetOpt()
661 getopt = DPyGetOpt.DPyGetOpt()
639 getopt.setIgnoreCase(0)
662 getopt.setIgnoreCase(0)
640 getopt.parseConfiguration(names)
663 getopt.parseConfiguration(names)
641
664
642 try:
665 try:
643 getopt.processArguments(argv)
666 getopt.processArguments(argv)
644 except DPyGetOpt.ArgumentError, exc:
667 except DPyGetOpt.ArgumentError, exc:
645 print usage
668 print usage
646 warn('"%s"' % exc,level=4)
669 warn('"%s"' % exc,level=4)
647
670
648 defaults.update(getopt.optionValues)
671 defaults.update(getopt.optionValues)
649 args = getopt.freeValues
672 args = getopt.freeValues
650
673
651 return defaults,args
674 return defaults,args
652
675
653 #----------------------------------------------------------------------------
676 #----------------------------------------------------------------------------
654 def optstr2types(ostr):
677 def optstr2types(ostr):
655 """Convert a string of option names to a dict of type mappings.
678 """Convert a string of option names to a dict of type mappings.
656
679
657 optstr2types(str) -> {None:'string_opts',int:'int_opts',float:'float_opts'}
680 optstr2types(str) -> {None:'string_opts',int:'int_opts',float:'float_opts'}
658
681
659 This is used to get the types of all the options in a string formatted
682 This is used to get the types of all the options in a string formatted
660 with the conventions of DPyGetOpt. The 'type' None is used for options
683 with the conventions of DPyGetOpt. The 'type' None is used for options
661 which are strings (they need no further conversion). This function's main
684 which are strings (they need no further conversion). This function's main
662 use is to get a typemap for use with read_dict().
685 use is to get a typemap for use with read_dict().
663 """
686 """
664
687
665 typeconv = {None:'',int:'',float:''}
688 typeconv = {None:'',int:'',float:''}
666 typemap = {'s':None,'i':int,'f':float}
689 typemap = {'s':None,'i':int,'f':float}
667 opt_re = re.compile(r'([\w]*)([^:=]*:?=?)([sif]?)')
690 opt_re = re.compile(r'([\w]*)([^:=]*:?=?)([sif]?)')
668
691
669 for w in ostr.split():
692 for w in ostr.split():
670 oname,alias,otype = opt_re.match(w).groups()
693 oname,alias,otype = opt_re.match(w).groups()
671 if otype == '' or alias == '!': # simple switches are integers too
694 if otype == '' or alias == '!': # simple switches are integers too
672 otype = 'i'
695 otype = 'i'
673 typeconv[typemap[otype]] += oname + ' '
696 typeconv[typemap[otype]] += oname + ' '
674 return typeconv
697 return typeconv
675
698
676 #----------------------------------------------------------------------------
699 #----------------------------------------------------------------------------
677 def read_dict(filename,type_conv=None,**opt):
700 def read_dict(filename,type_conv=None,**opt):
678 r"""Read a dictionary of key=value pairs from an input file, optionally
701 r"""Read a dictionary of key=value pairs from an input file, optionally
679 performing conversions on the resulting values.
702 performing conversions on the resulting values.
680
703
681 read_dict(filename,type_conv,**opt) -> dict
704 read_dict(filename,type_conv,**opt) -> dict
682
705
683 Only one value per line is accepted, the format should be
706 Only one value per line is accepted, the format should be
684 # optional comments are ignored
707 # optional comments are ignored
685 key value\n
708 key value\n
686
709
687 Args:
710 Args:
688
711
689 - type_conv: A dictionary specifying which keys need to be converted to
712 - type_conv: A dictionary specifying which keys need to be converted to
690 which types. By default all keys are read as strings. This dictionary
713 which types. By default all keys are read as strings. This dictionary
691 should have as its keys valid conversion functions for strings
714 should have as its keys valid conversion functions for strings
692 (int,long,float,complex, or your own). The value for each key
715 (int,long,float,complex, or your own). The value for each key
693 (converter) should be a whitespace separated string containing the names
716 (converter) should be a whitespace separated string containing the names
694 of all the entries in the file to be converted using that function. For
717 of all the entries in the file to be converted using that function. For
695 keys to be left alone, use None as the conversion function (only needed
718 keys to be left alone, use None as the conversion function (only needed
696 with purge=1, see below).
719 with purge=1, see below).
697
720
698 - opt: dictionary with extra options as below (default in parens)
721 - opt: dictionary with extra options as below (default in parens)
699
722
700 purge(0): if set to 1, all keys *not* listed in type_conv are purged out
723 purge(0): if set to 1, all keys *not* listed in type_conv are purged out
701 of the dictionary to be returned. If purge is going to be used, the
724 of the dictionary to be returned. If purge is going to be used, the
702 set of keys to be left as strings also has to be explicitly specified
725 set of keys to be left as strings also has to be explicitly specified
703 using the (non-existent) conversion function None.
726 using the (non-existent) conversion function None.
704
727
705 fs(None): field separator. This is the key/value separator to be used
728 fs(None): field separator. This is the key/value separator to be used
706 when parsing the file. The None default means any whitespace [behavior
729 when parsing the file. The None default means any whitespace [behavior
707 of string.split()].
730 of string.split()].
708
731
709 strip(0): if 1, strip string values of leading/trailinig whitespace.
732 strip(0): if 1, strip string values of leading/trailinig whitespace.
710
733
711 warn(1): warning level if requested keys are not found in file.
734 warn(1): warning level if requested keys are not found in file.
712 - 0: silently ignore.
735 - 0: silently ignore.
713 - 1: inform but proceed.
736 - 1: inform but proceed.
714 - 2: raise KeyError exception.
737 - 2: raise KeyError exception.
715
738
716 no_empty(0): if 1, remove keys with whitespace strings as a value.
739 no_empty(0): if 1, remove keys with whitespace strings as a value.
717
740
718 unique([]): list of keys (or space separated string) which can't be
741 unique([]): list of keys (or space separated string) which can't be
719 repeated. If one such key is found in the file, each new instance
742 repeated. If one such key is found in the file, each new instance
720 overwrites the previous one. For keys not listed here, the behavior is
743 overwrites the previous one. For keys not listed here, the behavior is
721 to make a list of all appearances.
744 to make a list of all appearances.
722
745
723 Example:
746 Example:
724
747
725 If the input file test.ini contains (we put it in a string to keep the test
748 If the input file test.ini contains (we put it in a string to keep the test
726 self-contained):
749 self-contained):
727
750
728 >>> test_ini = '''\
751 >>> test_ini = '''\
729 ... i 3
752 ... i 3
730 ... x 4.5
753 ... x 4.5
731 ... y 5.5
754 ... y 5.5
732 ... s hi ho'''
755 ... s hi ho'''
733
756
734 Then we can use it as follows:
757 Then we can use it as follows:
735 >>> type_conv={int:'i',float:'x',None:'s'}
758 >>> type_conv={int:'i',float:'x',None:'s'}
736
759
737 >>> d = read_dict(test_ini)
760 >>> d = read_dict(test_ini)
738
761
739 >>> sorted(d.items())
762 >>> sorted(d.items())
740 [('i', '3'), ('s', 'hi ho'), ('x', '4.5'), ('y', '5.5')]
763 [('i', '3'), ('s', 'hi ho'), ('x', '4.5'), ('y', '5.5')]
741
764
742 >>> d = read_dict(test_ini,type_conv)
765 >>> d = read_dict(test_ini,type_conv)
743
766
744 >>> sorted(d.items())
767 >>> sorted(d.items())
745 [('i', 3), ('s', 'hi ho'), ('x', 4.5), ('y', '5.5')]
768 [('i', 3), ('s', 'hi ho'), ('x', 4.5), ('y', '5.5')]
746
769
747 >>> d = read_dict(test_ini,type_conv,purge=True)
770 >>> d = read_dict(test_ini,type_conv,purge=True)
748
771
749 >>> sorted(d.items())
772 >>> sorted(d.items())
750 [('i', 3), ('s', 'hi ho'), ('x', 4.5)]
773 [('i', 3), ('s', 'hi ho'), ('x', 4.5)]
751 """
774 """
752
775
753 # starting config
776 # starting config
754 opt.setdefault('purge',0)
777 opt.setdefault('purge',0)
755 opt.setdefault('fs',None) # field sep defaults to any whitespace
778 opt.setdefault('fs',None) # field sep defaults to any whitespace
756 opt.setdefault('strip',0)
779 opt.setdefault('strip',0)
757 opt.setdefault('warn',1)
780 opt.setdefault('warn',1)
758 opt.setdefault('no_empty',0)
781 opt.setdefault('no_empty',0)
759 opt.setdefault('unique','')
782 opt.setdefault('unique','')
760 if type(opt['unique']) in StringTypes:
783 if type(opt['unique']) in StringTypes:
761 unique_keys = qw(opt['unique'])
784 unique_keys = qw(opt['unique'])
762 elif type(opt['unique']) in (types.TupleType,types.ListType):
785 elif type(opt['unique']) in (types.TupleType,types.ListType):
763 unique_keys = opt['unique']
786 unique_keys = opt['unique']
764 else:
787 else:
765 raise ValueError, 'Unique keys must be given as a string, List or Tuple'
788 raise ValueError, 'Unique keys must be given as a string, List or Tuple'
766
789
767 dict = {}
790 dict = {}
768
791
769 # first read in table of values as strings
792 # first read in table of values as strings
770 if '\n' in filename:
793 if '\n' in filename:
771 lines = filename.splitlines()
794 lines = filename.splitlines()
772 file = None
795 file = None
773 else:
796 else:
774 file = open(filename,'r')
797 file = open(filename,'r')
775 lines = file.readlines()
798 lines = file.readlines()
776 for line in lines:
799 for line in lines:
777 line = line.strip()
800 line = line.strip()
778 if len(line) and line[0]=='#': continue
801 if len(line) and line[0]=='#': continue
779 if len(line)>0:
802 if len(line)>0:
780 lsplit = line.split(opt['fs'],1)
803 lsplit = line.split(opt['fs'],1)
781 try:
804 try:
782 key,val = lsplit
805 key,val = lsplit
783 except ValueError:
806 except ValueError:
784 key,val = lsplit[0],''
807 key,val = lsplit[0],''
785 key = key.strip()
808 key = key.strip()
786 if opt['strip']: val = val.strip()
809 if opt['strip']: val = val.strip()
787 if val == "''" or val == '""': val = ''
810 if val == "''" or val == '""': val = ''
788 if opt['no_empty'] and (val=='' or val.isspace()):
811 if opt['no_empty'] and (val=='' or val.isspace()):
789 continue
812 continue
790 # if a key is found more than once in the file, build a list
813 # if a key is found more than once in the file, build a list
791 # unless it's in the 'unique' list. In that case, last found in file
814 # unless it's in the 'unique' list. In that case, last found in file
792 # takes precedence. User beware.
815 # takes precedence. User beware.
793 try:
816 try:
794 if dict[key] and key in unique_keys:
817 if dict[key] and key in unique_keys:
795 dict[key] = val
818 dict[key] = val
796 elif type(dict[key]) is types.ListType:
819 elif type(dict[key]) is types.ListType:
797 dict[key].append(val)
820 dict[key].append(val)
798 else:
821 else:
799 dict[key] = [dict[key],val]
822 dict[key] = [dict[key],val]
800 except KeyError:
823 except KeyError:
801 dict[key] = val
824 dict[key] = val
802 # purge if requested
825 # purge if requested
803 if opt['purge']:
826 if opt['purge']:
804 accepted_keys = qwflat(type_conv.values())
827 accepted_keys = qwflat(type_conv.values())
805 for key in dict.keys():
828 for key in dict.keys():
806 if key in accepted_keys: continue
829 if key in accepted_keys: continue
807 del(dict[key])
830 del(dict[key])
808 # now convert if requested
831 # now convert if requested
809 if type_conv==None: return dict
832 if type_conv==None: return dict
810 conversions = type_conv.keys()
833 conversions = type_conv.keys()
811 try: conversions.remove(None)
834 try: conversions.remove(None)
812 except: pass
835 except: pass
813 for convert in conversions:
836 for convert in conversions:
814 for val in qw(type_conv[convert]):
837 for val in qw(type_conv[convert]):
815 try:
838 try:
816 dict[val] = convert(dict[val])
839 dict[val] = convert(dict[val])
817 except KeyError,e:
840 except KeyError,e:
818 if opt['warn'] == 0:
841 if opt['warn'] == 0:
819 pass
842 pass
820 elif opt['warn'] == 1:
843 elif opt['warn'] == 1:
821 print >>sys.stderr, 'Warning: key',val,\
844 print >>sys.stderr, 'Warning: key',val,\
822 'not found in file',filename
845 'not found in file',filename
823 elif opt['warn'] == 2:
846 elif opt['warn'] == 2:
824 raise KeyError,e
847 raise KeyError,e
825 else:
848 else:
826 raise ValueError,'Warning level must be 0,1 or 2'
849 raise ValueError,'Warning level must be 0,1 or 2'
827
850
828 return dict
851 return dict
829
852
830 #----------------------------------------------------------------------------
853 #----------------------------------------------------------------------------
831 def flag_calls(func):
854 def flag_calls(func):
832 """Wrap a function to detect and flag when it gets called.
855 """Wrap a function to detect and flag when it gets called.
833
856
834 This is a decorator which takes a function and wraps it in a function with
857 This is a decorator which takes a function and wraps it in a function with
835 a 'called' attribute. wrapper.called is initialized to False.
858 a 'called' attribute. wrapper.called is initialized to False.
836
859
837 The wrapper.called attribute is set to False right before each call to the
860 The wrapper.called attribute is set to False right before each call to the
838 wrapped function, so if the call fails it remains False. After the call
861 wrapped function, so if the call fails it remains False. After the call
839 completes, wrapper.called is set to True and the output is returned.
862 completes, wrapper.called is set to True and the output is returned.
840
863
841 Testing for truth in wrapper.called allows you to determine if a call to
864 Testing for truth in wrapper.called allows you to determine if a call to
842 func() was attempted and succeeded."""
865 func() was attempted and succeeded."""
843
866
844 def wrapper(*args,**kw):
867 def wrapper(*args,**kw):
845 wrapper.called = False
868 wrapper.called = False
846 out = func(*args,**kw)
869 out = func(*args,**kw)
847 wrapper.called = True
870 wrapper.called = True
848 return out
871 return out
849
872
850 wrapper.called = False
873 wrapper.called = False
851 wrapper.__doc__ = func.__doc__
874 wrapper.__doc__ = func.__doc__
852 return wrapper
875 return wrapper
853
876
854 #----------------------------------------------------------------------------
877 #----------------------------------------------------------------------------
855 def dhook_wrap(func,*a,**k):
878 def dhook_wrap(func,*a,**k):
856 """Wrap a function call in a sys.displayhook controller.
879 """Wrap a function call in a sys.displayhook controller.
857
880
858 Returns a wrapper around func which calls func, with all its arguments and
881 Returns a wrapper around func which calls func, with all its arguments and
859 keywords unmodified, using the default sys.displayhook. Since IPython
882 keywords unmodified, using the default sys.displayhook. Since IPython
860 modifies sys.displayhook, it breaks the behavior of certain systems that
883 modifies sys.displayhook, it breaks the behavior of certain systems that
861 rely on the default behavior, notably doctest.
884 rely on the default behavior, notably doctest.
862 """
885 """
863
886
864 def f(*a,**k):
887 def f(*a,**k):
865
888
866 dhook_s = sys.displayhook
889 dhook_s = sys.displayhook
867 sys.displayhook = sys.__displayhook__
890 sys.displayhook = sys.__displayhook__
868 try:
891 try:
869 out = func(*a,**k)
892 out = func(*a,**k)
870 finally:
893 finally:
871 sys.displayhook = dhook_s
894 sys.displayhook = dhook_s
872
895
873 return out
896 return out
874
897
875 f.__doc__ = func.__doc__
898 f.__doc__ = func.__doc__
876 return f
899 return f
877
900
878 #----------------------------------------------------------------------------
901 #----------------------------------------------------------------------------
879 def doctest_reload():
902 def doctest_reload():
880 """Properly reload doctest to reuse it interactively.
903 """Properly reload doctest to reuse it interactively.
881
904
882 This routine:
905 This routine:
883
906
884 - imports doctest but does NOT reload it (see below).
907 - imports doctest but does NOT reload it (see below).
885
908
886 - resets its global 'master' attribute to None, so that multiple uses of
909 - resets its global 'master' attribute to None, so that multiple uses of
887 the module interactively don't produce cumulative reports.
910 the module interactively don't produce cumulative reports.
888
911
889 - Monkeypatches its core test runner method to protect it from IPython's
912 - Monkeypatches its core test runner method to protect it from IPython's
890 modified displayhook. Doctest expects the default displayhook behavior
913 modified displayhook. Doctest expects the default displayhook behavior
891 deep down, so our modification breaks it completely. For this reason, a
914 deep down, so our modification breaks it completely. For this reason, a
892 hard monkeypatch seems like a reasonable solution rather than asking
915 hard monkeypatch seems like a reasonable solution rather than asking
893 users to manually use a different doctest runner when under IPython.
916 users to manually use a different doctest runner when under IPython.
894
917
895 Notes
918 Notes
896 -----
919 -----
897
920
898 This function *used to* reload doctest, but this has been disabled because
921 This function *used to* reload doctest, but this has been disabled because
899 reloading doctest unconditionally can cause massive breakage of other
922 reloading doctest unconditionally can cause massive breakage of other
900 doctest-dependent modules already in memory, such as those for IPython's
923 doctest-dependent modules already in memory, such as those for IPython's
901 own testing system. The name wasn't changed to avoid breaking people's
924 own testing system. The name wasn't changed to avoid breaking people's
902 code, but the reload call isn't actually made anymore."""
925 code, but the reload call isn't actually made anymore."""
903
926
904 import doctest
927 import doctest
905 doctest.master = None
928 doctest.master = None
906 doctest.DocTestRunner.run = dhook_wrap(doctest.DocTestRunner.run)
929 doctest.DocTestRunner.run = dhook_wrap(doctest.DocTestRunner.run)
907
930
908 #----------------------------------------------------------------------------
931 #----------------------------------------------------------------------------
909 class HomeDirError(Error):
932 class HomeDirError(Error):
910 pass
933 pass
911
934
912 def get_home_dir():
935 def get_home_dir():
913 """Return the closest possible equivalent to a 'home' directory.
936 """Return the closest possible equivalent to a 'home' directory.
914
937
915 We first try $HOME. Absent that, on NT it's $HOMEDRIVE\$HOMEPATH.
938 We first try $HOME. Absent that, on NT it's $HOMEDRIVE\$HOMEPATH.
916
939
917 Currently only Posix and NT are implemented, a HomeDirError exception is
940 Currently only Posix and NT are implemented, a HomeDirError exception is
918 raised for all other OSes. """
941 raised for all other OSes. """
919
942
920 isdir = os.path.isdir
943 isdir = os.path.isdir
921 env = os.environ
944 env = os.environ
922
945
923 # first, check py2exe distribution root directory for _ipython.
946 # first, check py2exe distribution root directory for _ipython.
924 # This overrides all. Normally does not exist.
947 # This overrides all. Normally does not exist.
925
948
926 if hasattr(sys, "frozen"): #Is frozen by py2exe
949 if hasattr(sys, "frozen"): #Is frozen by py2exe
927 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
950 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
928 root, rest = IPython.__file__.lower().split('library.zip')
951 root, rest = IPython.__file__.lower().split('library.zip')
929 else:
952 else:
930 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
953 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
931 root=os.path.abspath(root).rstrip('\\')
954 root=os.path.abspath(root).rstrip('\\')
932 if isdir(os.path.join(root, '_ipython')):
955 if isdir(os.path.join(root, '_ipython')):
933 os.environ["IPYKITROOT"] = root
956 os.environ["IPYKITROOT"] = root
934 return root
957 return root
935 try:
958 try:
936 homedir = env['HOME']
959 homedir = env['HOME']
937 if not isdir(homedir):
960 if not isdir(homedir):
938 # in case a user stuck some string which does NOT resolve to a
961 # in case a user stuck some string which does NOT resolve to a
939 # valid path, it's as good as if we hadn't foud it
962 # valid path, it's as good as if we hadn't foud it
940 raise KeyError
963 raise KeyError
941 return homedir
964 return homedir
942 except KeyError:
965 except KeyError:
943 if os.name == 'posix':
966 if os.name == 'posix':
944 raise HomeDirError,'undefined $HOME, IPython can not proceed.'
967 raise HomeDirError,'undefined $HOME, IPython can not proceed.'
945 elif os.name == 'nt':
968 elif os.name == 'nt':
946 # For some strange reason, win9x returns 'nt' for os.name.
969 # For some strange reason, win9x returns 'nt' for os.name.
947 try:
970 try:
948 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
971 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
949 if not isdir(homedir):
972 if not isdir(homedir):
950 homedir = os.path.join(env['USERPROFILE'])
973 homedir = os.path.join(env['USERPROFILE'])
951 if not isdir(homedir):
974 if not isdir(homedir):
952 raise HomeDirError
975 raise HomeDirError
953 return homedir
976 return homedir
954 except KeyError:
977 except KeyError:
955 try:
978 try:
956 # Use the registry to get the 'My Documents' folder.
979 # Use the registry to get the 'My Documents' folder.
957 import _winreg as wreg
980 import _winreg as wreg
958 key = wreg.OpenKey(wreg.HKEY_CURRENT_USER,
981 key = wreg.OpenKey(wreg.HKEY_CURRENT_USER,
959 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
982 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
960 homedir = wreg.QueryValueEx(key,'Personal')[0]
983 homedir = wreg.QueryValueEx(key,'Personal')[0]
961 key.Close()
984 key.Close()
962 if not isdir(homedir):
985 if not isdir(homedir):
963 e = ('Invalid "Personal" folder registry key '
986 e = ('Invalid "Personal" folder registry key '
964 'typically "My Documents".\n'
987 'typically "My Documents".\n'
965 'Value: %s\n'
988 'Value: %s\n'
966 'This is not a valid directory on your system.' %
989 'This is not a valid directory on your system.' %
967 homedir)
990 homedir)
968 raise HomeDirError(e)
991 raise HomeDirError(e)
969 return homedir
992 return homedir
970 except HomeDirError:
993 except HomeDirError:
971 raise
994 raise
972 except:
995 except:
973 return 'C:\\'
996 return 'C:\\'
974 elif os.name == 'dos':
997 elif os.name == 'dos':
975 # Desperate, may do absurd things in classic MacOS. May work under DOS.
998 # Desperate, may do absurd things in classic MacOS. May work under DOS.
976 return 'C:\\'
999 return 'C:\\'
977 else:
1000 else:
978 raise HomeDirError,'support for your operating system not implemented.'
1001 raise HomeDirError,'support for your operating system not implemented.'
979
1002
980
1003
981 def get_ipython_dir():
1004 def get_ipython_dir():
982 """Get the IPython directory for this platform and user.
1005 """Get the IPython directory for this platform and user.
983
1006
984 This uses the logic in `get_home_dir` to find the home directory
1007 This uses the logic in `get_home_dir` to find the home directory
985 and the adds either .ipython or _ipython to the end of the path.
1008 and the adds either .ipython or _ipython to the end of the path.
986 """
1009 """
987 if os.name == 'posix':
1010 if os.name == 'posix':
988 ipdir_def = '.ipython'
1011 ipdir_def = '.ipython'
989 else:
1012 else:
990 ipdir_def = '_ipython'
1013 ipdir_def = '_ipython'
991 home_dir = get_home_dir()
1014 home_dir = get_home_dir()
992 ipdir = os.path.abspath(os.environ.get('IPYTHONDIR',
1015 ipdir = os.path.abspath(os.environ.get('IPYTHONDIR',
993 os.path.join(home_dir, ipdir_def)))
1016 os.path.join(home_dir, ipdir_def)))
994 return ipdir.decode(sys.getfilesystemencoding())
1017 return ipdir.decode(sys.getfilesystemencoding())
995
1018
996 def get_security_dir():
1019 def get_security_dir():
997 """Get the IPython security directory.
1020 """Get the IPython security directory.
998
1021
999 This directory is the default location for all security related files,
1022 This directory is the default location for all security related files,
1000 including SSL/TLS certificates and FURL files.
1023 including SSL/TLS certificates and FURL files.
1001
1024
1002 If the directory does not exist, it is created with 0700 permissions.
1025 If the directory does not exist, it is created with 0700 permissions.
1003 If it exists, permissions are set to 0700.
1026 If it exists, permissions are set to 0700.
1004 """
1027 """
1005 security_dir = os.path.join(get_ipython_dir(), 'security')
1028 security_dir = os.path.join(get_ipython_dir(), 'security')
1006 if not os.path.isdir(security_dir):
1029 if not os.path.isdir(security_dir):
1007 os.mkdir(security_dir, 0700)
1030 os.mkdir(security_dir, 0700)
1008 else:
1031 else:
1009 os.chmod(security_dir, 0700)
1032 os.chmod(security_dir, 0700)
1010 return security_dir
1033 return security_dir
1011
1034
1012 def get_log_dir():
1035 def get_log_dir():
1013 """Get the IPython log directory.
1036 """Get the IPython log directory.
1014
1037
1015 If the log directory does not exist, it is created.
1038 If the log directory does not exist, it is created.
1016 """
1039 """
1017 log_dir = os.path.join(get_ipython_dir(), 'log')
1040 log_dir = os.path.join(get_ipython_dir(), 'log')
1018 if not os.path.isdir(log_dir):
1041 if not os.path.isdir(log_dir):
1019 os.mkdir(log_dir, 0777)
1042 os.mkdir(log_dir, 0777)
1020 return log_dir
1043 return log_dir
1021
1044
1022 #****************************************************************************
1045 #****************************************************************************
1023 # strings and text
1046 # strings and text
1024
1047
1025 class LSString(str):
1048 class LSString(str):
1026 """String derivative with a special access attributes.
1049 """String derivative with a special access attributes.
1027
1050
1028 These are normal strings, but with the special attributes:
1051 These are normal strings, but with the special attributes:
1029
1052
1030 .l (or .list) : value as list (split on newlines).
1053 .l (or .list) : value as list (split on newlines).
1031 .n (or .nlstr): original value (the string itself).
1054 .n (or .nlstr): original value (the string itself).
1032 .s (or .spstr): value as whitespace-separated string.
1055 .s (or .spstr): value as whitespace-separated string.
1033 .p (or .paths): list of path objects
1056 .p (or .paths): list of path objects
1034
1057
1035 Any values which require transformations are computed only once and
1058 Any values which require transformations are computed only once and
1036 cached.
1059 cached.
1037
1060
1038 Such strings are very useful to efficiently interact with the shell, which
1061 Such strings are very useful to efficiently interact with the shell, which
1039 typically only understands whitespace-separated options for commands."""
1062 typically only understands whitespace-separated options for commands."""
1040
1063
1041 def get_list(self):
1064 def get_list(self):
1042 try:
1065 try:
1043 return self.__list
1066 return self.__list
1044 except AttributeError:
1067 except AttributeError:
1045 self.__list = self.split('\n')
1068 self.__list = self.split('\n')
1046 return self.__list
1069 return self.__list
1047
1070
1048 l = list = property(get_list)
1071 l = list = property(get_list)
1049
1072
1050 def get_spstr(self):
1073 def get_spstr(self):
1051 try:
1074 try:
1052 return self.__spstr
1075 return self.__spstr
1053 except AttributeError:
1076 except AttributeError:
1054 self.__spstr = self.replace('\n',' ')
1077 self.__spstr = self.replace('\n',' ')
1055 return self.__spstr
1078 return self.__spstr
1056
1079
1057 s = spstr = property(get_spstr)
1080 s = spstr = property(get_spstr)
1058
1081
1059 def get_nlstr(self):
1082 def get_nlstr(self):
1060 return self
1083 return self
1061
1084
1062 n = nlstr = property(get_nlstr)
1085 n = nlstr = property(get_nlstr)
1063
1086
1064 def get_paths(self):
1087 def get_paths(self):
1065 try:
1088 try:
1066 return self.__paths
1089 return self.__paths
1067 except AttributeError:
1090 except AttributeError:
1068 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
1091 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
1069 return self.__paths
1092 return self.__paths
1070
1093
1071 p = paths = property(get_paths)
1094 p = paths = property(get_paths)
1072
1095
1073 def print_lsstring(arg):
1096 def print_lsstring(arg):
1074 """ Prettier (non-repr-like) and more informative printer for LSString """
1097 """ Prettier (non-repr-like) and more informative printer for LSString """
1075 print "LSString (.p, .n, .l, .s available). Value:"
1098 print "LSString (.p, .n, .l, .s available). Value:"
1076 print arg
1099 print arg
1077
1100
1078 print_lsstring = result_display.when_type(LSString)(print_lsstring)
1101 print_lsstring = result_display.when_type(LSString)(print_lsstring)
1079
1102
1080 #----------------------------------------------------------------------------
1103 #----------------------------------------------------------------------------
1081 class SList(list):
1104 class SList(list):
1082 """List derivative with a special access attributes.
1105 """List derivative with a special access attributes.
1083
1106
1084 These are normal lists, but with the special attributes:
1107 These are normal lists, but with the special attributes:
1085
1108
1086 .l (or .list) : value as list (the list itself).
1109 .l (or .list) : value as list (the list itself).
1087 .n (or .nlstr): value as a string, joined on newlines.
1110 .n (or .nlstr): value as a string, joined on newlines.
1088 .s (or .spstr): value as a string, joined on spaces.
1111 .s (or .spstr): value as a string, joined on spaces.
1089 .p (or .paths): list of path objects
1112 .p (or .paths): list of path objects
1090
1113
1091 Any values which require transformations are computed only once and
1114 Any values which require transformations are computed only once and
1092 cached."""
1115 cached."""
1093
1116
1094 def get_list(self):
1117 def get_list(self):
1095 return self
1118 return self
1096
1119
1097 l = list = property(get_list)
1120 l = list = property(get_list)
1098
1121
1099 def get_spstr(self):
1122 def get_spstr(self):
1100 try:
1123 try:
1101 return self.__spstr
1124 return self.__spstr
1102 except AttributeError:
1125 except AttributeError:
1103 self.__spstr = ' '.join(self)
1126 self.__spstr = ' '.join(self)
1104 return self.__spstr
1127 return self.__spstr
1105
1128
1106 s = spstr = property(get_spstr)
1129 s = spstr = property(get_spstr)
1107
1130
1108 def get_nlstr(self):
1131 def get_nlstr(self):
1109 try:
1132 try:
1110 return self.__nlstr
1133 return self.__nlstr
1111 except AttributeError:
1134 except AttributeError:
1112 self.__nlstr = '\n'.join(self)
1135 self.__nlstr = '\n'.join(self)
1113 return self.__nlstr
1136 return self.__nlstr
1114
1137
1115 n = nlstr = property(get_nlstr)
1138 n = nlstr = property(get_nlstr)
1116
1139
1117 def get_paths(self):
1140 def get_paths(self):
1118 try:
1141 try:
1119 return self.__paths
1142 return self.__paths
1120 except AttributeError:
1143 except AttributeError:
1121 self.__paths = [path(p) for p in self if os.path.exists(p)]
1144 self.__paths = [path(p) for p in self if os.path.exists(p)]
1122 return self.__paths
1145 return self.__paths
1123
1146
1124 p = paths = property(get_paths)
1147 p = paths = property(get_paths)
1125
1148
1126 def grep(self, pattern, prune = False, field = None):
1149 def grep(self, pattern, prune = False, field = None):
1127 """ Return all strings matching 'pattern' (a regex or callable)
1150 """ Return all strings matching 'pattern' (a regex or callable)
1128
1151
1129 This is case-insensitive. If prune is true, return all items
1152 This is case-insensitive. If prune is true, return all items
1130 NOT matching the pattern.
1153 NOT matching the pattern.
1131
1154
1132 If field is specified, the match must occur in the specified
1155 If field is specified, the match must occur in the specified
1133 whitespace-separated field.
1156 whitespace-separated field.
1134
1157
1135 Examples::
1158 Examples::
1136
1159
1137 a.grep( lambda x: x.startswith('C') )
1160 a.grep( lambda x: x.startswith('C') )
1138 a.grep('Cha.*log', prune=1)
1161 a.grep('Cha.*log', prune=1)
1139 a.grep('chm', field=-1)
1162 a.grep('chm', field=-1)
1140 """
1163 """
1141
1164
1142 def match_target(s):
1165 def match_target(s):
1143 if field is None:
1166 if field is None:
1144 return s
1167 return s
1145 parts = s.split()
1168 parts = s.split()
1146 try:
1169 try:
1147 tgt = parts[field]
1170 tgt = parts[field]
1148 return tgt
1171 return tgt
1149 except IndexError:
1172 except IndexError:
1150 return ""
1173 return ""
1151
1174
1152 if isinstance(pattern, basestring):
1175 if isinstance(pattern, basestring):
1153 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
1176 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
1154 else:
1177 else:
1155 pred = pattern
1178 pred = pattern
1156 if not prune:
1179 if not prune:
1157 return SList([el for el in self if pred(match_target(el))])
1180 return SList([el for el in self if pred(match_target(el))])
1158 else:
1181 else:
1159 return SList([el for el in self if not pred(match_target(el))])
1182 return SList([el for el in self if not pred(match_target(el))])
1160 def fields(self, *fields):
1183 def fields(self, *fields):
1161 """ Collect whitespace-separated fields from string list
1184 """ Collect whitespace-separated fields from string list
1162
1185
1163 Allows quick awk-like usage of string lists.
1186 Allows quick awk-like usage of string lists.
1164
1187
1165 Example data (in var a, created by 'a = !ls -l')::
1188 Example data (in var a, created by 'a = !ls -l')::
1166 -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
1189 -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
1167 drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
1190 drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
1168
1191
1169 a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
1192 a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
1170 a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
1193 a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
1171 (note the joining by space).
1194 (note the joining by space).
1172 a.fields(-1) is ['ChangeLog', 'IPython']
1195 a.fields(-1) is ['ChangeLog', 'IPython']
1173
1196
1174 IndexErrors are ignored.
1197 IndexErrors are ignored.
1175
1198
1176 Without args, fields() just split()'s the strings.
1199 Without args, fields() just split()'s the strings.
1177 """
1200 """
1178 if len(fields) == 0:
1201 if len(fields) == 0:
1179 return [el.split() for el in self]
1202 return [el.split() for el in self]
1180
1203
1181 res = SList()
1204 res = SList()
1182 for el in [f.split() for f in self]:
1205 for el in [f.split() for f in self]:
1183 lineparts = []
1206 lineparts = []
1184
1207
1185 for fd in fields:
1208 for fd in fields:
1186 try:
1209 try:
1187 lineparts.append(el[fd])
1210 lineparts.append(el[fd])
1188 except IndexError:
1211 except IndexError:
1189 pass
1212 pass
1190 if lineparts:
1213 if lineparts:
1191 res.append(" ".join(lineparts))
1214 res.append(" ".join(lineparts))
1192
1215
1193 return res
1216 return res
1194 def sort(self,field= None, nums = False):
1217 def sort(self,field= None, nums = False):
1195 """ sort by specified fields (see fields())
1218 """ sort by specified fields (see fields())
1196
1219
1197 Example::
1220 Example::
1198 a.sort(1, nums = True)
1221 a.sort(1, nums = True)
1199
1222
1200 Sorts a by second field, in numerical order (so that 21 > 3)
1223 Sorts a by second field, in numerical order (so that 21 > 3)
1201
1224
1202 """
1225 """
1203
1226
1204 #decorate, sort, undecorate
1227 #decorate, sort, undecorate
1205 if field is not None:
1228 if field is not None:
1206 dsu = [[SList([line]).fields(field), line] for line in self]
1229 dsu = [[SList([line]).fields(field), line] for line in self]
1207 else:
1230 else:
1208 dsu = [[line, line] for line in self]
1231 dsu = [[line, line] for line in self]
1209 if nums:
1232 if nums:
1210 for i in range(len(dsu)):
1233 for i in range(len(dsu)):
1211 numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
1234 numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
1212 try:
1235 try:
1213 n = int(numstr)
1236 n = int(numstr)
1214 except ValueError:
1237 except ValueError:
1215 n = 0;
1238 n = 0;
1216 dsu[i][0] = n
1239 dsu[i][0] = n
1217
1240
1218
1241
1219 dsu.sort()
1242 dsu.sort()
1220 return SList([t[1] for t in dsu])
1243 return SList([t[1] for t in dsu])
1221
1244
1222 def print_slist(arg):
1245 def print_slist(arg):
1223 """ Prettier (non-repr-like) and more informative printer for SList """
1246 """ Prettier (non-repr-like) and more informative printer for SList """
1224 print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
1247 print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
1225 if hasattr(arg, 'hideonce') and arg.hideonce:
1248 if hasattr(arg, 'hideonce') and arg.hideonce:
1226 arg.hideonce = False
1249 arg.hideonce = False
1227 return
1250 return
1228
1251
1229 nlprint(arg)
1252 nlprint(arg)
1230
1253
1231 print_slist = result_display.when_type(SList)(print_slist)
1254 print_slist = result_display.when_type(SList)(print_slist)
1232
1255
1233
1256
1234
1257
1235 #----------------------------------------------------------------------------
1258 #----------------------------------------------------------------------------
1236 def esc_quotes(strng):
1259 def esc_quotes(strng):
1237 """Return the input string with single and double quotes escaped out"""
1260 """Return the input string with single and double quotes escaped out"""
1238
1261
1239 return strng.replace('"','\\"').replace("'","\\'")
1262 return strng.replace('"','\\"').replace("'","\\'")
1240
1263
1241 #----------------------------------------------------------------------------
1264 #----------------------------------------------------------------------------
1242 def make_quoted_expr(s):
1265 def make_quoted_expr(s):
1243 """Return string s in appropriate quotes, using raw string if possible.
1266 """Return string s in appropriate quotes, using raw string if possible.
1244
1267
1245 XXX - example removed because it caused encoding errors in documentation
1268 XXX - example removed because it caused encoding errors in documentation
1246 generation. We need a new example that doesn't contain invalid chars.
1269 generation. We need a new example that doesn't contain invalid chars.
1247
1270
1248 Note the use of raw string and padding at the end to allow trailing
1271 Note the use of raw string and padding at the end to allow trailing
1249 backslash.
1272 backslash.
1250 """
1273 """
1251
1274
1252 tail = ''
1275 tail = ''
1253 tailpadding = ''
1276 tailpadding = ''
1254 raw = ''
1277 raw = ''
1255 if "\\" in s:
1278 if "\\" in s:
1256 raw = 'r'
1279 raw = 'r'
1257 if s.endswith('\\'):
1280 if s.endswith('\\'):
1258 tail = '[:-1]'
1281 tail = '[:-1]'
1259 tailpadding = '_'
1282 tailpadding = '_'
1260 if '"' not in s:
1283 if '"' not in s:
1261 quote = '"'
1284 quote = '"'
1262 elif "'" not in s:
1285 elif "'" not in s:
1263 quote = "'"
1286 quote = "'"
1264 elif '"""' not in s and not s.endswith('"'):
1287 elif '"""' not in s and not s.endswith('"'):
1265 quote = '"""'
1288 quote = '"""'
1266 elif "'''" not in s and not s.endswith("'"):
1289 elif "'''" not in s and not s.endswith("'"):
1267 quote = "'''"
1290 quote = "'''"
1268 else:
1291 else:
1269 # give up, backslash-escaped string will do
1292 # give up, backslash-escaped string will do
1270 return '"%s"' % esc_quotes(s)
1293 return '"%s"' % esc_quotes(s)
1271 res = raw + quote + s + tailpadding + quote + tail
1294 res = raw + quote + s + tailpadding + quote + tail
1272 return res
1295 return res
1273
1296
1274
1297
1275 #----------------------------------------------------------------------------
1298 #----------------------------------------------------------------------------
1276 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
1299 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
1277 """Take multiple lines of input.
1300 """Take multiple lines of input.
1278
1301
1279 A list with each line of input as a separate element is returned when a
1302 A list with each line of input as a separate element is returned when a
1280 termination string is entered (defaults to a single '.'). Input can also
1303 termination string is entered (defaults to a single '.'). Input can also
1281 terminate via EOF (^D in Unix, ^Z-RET in Windows).
1304 terminate via EOF (^D in Unix, ^Z-RET in Windows).
1282
1305
1283 Lines of input which end in \\ are joined into single entries (and a
1306 Lines of input which end in \\ are joined into single entries (and a
1284 secondary continuation prompt is issued as long as the user terminates
1307 secondary continuation prompt is issued as long as the user terminates
1285 lines with \\). This allows entering very long strings which are still
1308 lines with \\). This allows entering very long strings which are still
1286 meant to be treated as single entities.
1309 meant to be treated as single entities.
1287 """
1310 """
1288
1311
1289 try:
1312 try:
1290 if header:
1313 if header:
1291 header += '\n'
1314 header += '\n'
1292 lines = [raw_input(header + ps1)]
1315 lines = [raw_input(header + ps1)]
1293 except EOFError:
1316 except EOFError:
1294 return []
1317 return []
1295 terminate = [terminate_str]
1318 terminate = [terminate_str]
1296 try:
1319 try:
1297 while lines[-1:] != terminate:
1320 while lines[-1:] != terminate:
1298 new_line = raw_input(ps1)
1321 new_line = raw_input(ps1)
1299 while new_line.endswith('\\'):
1322 while new_line.endswith('\\'):
1300 new_line = new_line[:-1] + raw_input(ps2)
1323 new_line = new_line[:-1] + raw_input(ps2)
1301 lines.append(new_line)
1324 lines.append(new_line)
1302
1325
1303 return lines[:-1] # don't return the termination command
1326 return lines[:-1] # don't return the termination command
1304 except EOFError:
1327 except EOFError:
1305 print
1328 print
1306 return lines
1329 return lines
1307
1330
1308 #----------------------------------------------------------------------------
1331 #----------------------------------------------------------------------------
1309 def raw_input_ext(prompt='', ps2='... '):
1332 def raw_input_ext(prompt='', ps2='... '):
1310 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
1333 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
1311
1334
1312 line = raw_input(prompt)
1335 line = raw_input(prompt)
1313 while line.endswith('\\'):
1336 while line.endswith('\\'):
1314 line = line[:-1] + raw_input(ps2)
1337 line = line[:-1] + raw_input(ps2)
1315 return line
1338 return line
1316
1339
1317 #----------------------------------------------------------------------------
1340 #----------------------------------------------------------------------------
1318 def ask_yes_no(prompt,default=None):
1341 def ask_yes_no(prompt,default=None):
1319 """Asks a question and returns a boolean (y/n) answer.
1342 """Asks a question and returns a boolean (y/n) answer.
1320
1343
1321 If default is given (one of 'y','n'), it is used if the user input is
1344 If default is given (one of 'y','n'), it is used if the user input is
1322 empty. Otherwise the question is repeated until an answer is given.
1345 empty. Otherwise the question is repeated until an answer is given.
1323
1346
1324 An EOF is treated as the default answer. If there is no default, an
1347 An EOF is treated as the default answer. If there is no default, an
1325 exception is raised to prevent infinite loops.
1348 exception is raised to prevent infinite loops.
1326
1349
1327 Valid answers are: y/yes/n/no (match is not case sensitive)."""
1350 Valid answers are: y/yes/n/no (match is not case sensitive)."""
1328
1351
1329 answers = {'y':True,'n':False,'yes':True,'no':False}
1352 answers = {'y':True,'n':False,'yes':True,'no':False}
1330 ans = None
1353 ans = None
1331 while ans not in answers.keys():
1354 while ans not in answers.keys():
1332 try:
1355 try:
1333 ans = raw_input(prompt+' ').lower()
1356 ans = raw_input(prompt+' ').lower()
1334 if not ans: # response was an empty string
1357 if not ans: # response was an empty string
1335 ans = default
1358 ans = default
1336 except KeyboardInterrupt:
1359 except KeyboardInterrupt:
1337 pass
1360 pass
1338 except EOFError:
1361 except EOFError:
1339 if default in answers.keys():
1362 if default in answers.keys():
1340 ans = default
1363 ans = default
1341 print
1364 print
1342 else:
1365 else:
1343 raise
1366 raise
1344
1367
1345 return answers[ans]
1368 return answers[ans]
1346
1369
1347 #----------------------------------------------------------------------------
1370 #----------------------------------------------------------------------------
1348 def marquee(txt='',width=78,mark='*'):
1371 def marquee(txt='',width=78,mark='*'):
1349 """Return the input string centered in a 'marquee'."""
1372 """Return the input string centered in a 'marquee'."""
1350 if not txt:
1373 if not txt:
1351 return (mark*width)[:width]
1374 return (mark*width)[:width]
1352 nmark = (width-len(txt)-2)/len(mark)/2
1375 nmark = (width-len(txt)-2)/len(mark)/2
1353 if nmark < 0: nmark =0
1376 if nmark < 0: nmark =0
1354 marks = mark*nmark
1377 marks = mark*nmark
1355 return '%s %s %s' % (marks,txt,marks)
1378 return '%s %s %s' % (marks,txt,marks)
1356
1379
1357 #----------------------------------------------------------------------------
1380 #----------------------------------------------------------------------------
1358 class EvalDict:
1381 class EvalDict:
1359 """
1382 """
1360 Emulate a dict which evaluates its contents in the caller's frame.
1383 Emulate a dict which evaluates its contents in the caller's frame.
1361
1384
1362 Usage:
1385 Usage:
1363 >>> number = 19
1386 >>> number = 19
1364
1387
1365 >>> text = "python"
1388 >>> text = "python"
1366
1389
1367 >>> print "%(text.capitalize())s %(number/9.0).1f rules!" % EvalDict()
1390 >>> print "%(text.capitalize())s %(number/9.0).1f rules!" % EvalDict()
1368 Python 2.1 rules!
1391 Python 2.1 rules!
1369 """
1392 """
1370
1393
1371 # This version is due to sismex01@hebmex.com on c.l.py, and is basically a
1394 # This version is due to sismex01@hebmex.com on c.l.py, and is basically a
1372 # modified (shorter) version of:
1395 # modified (shorter) version of:
1373 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66018 by
1396 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66018 by
1374 # Skip Montanaro (skip@pobox.com).
1397 # Skip Montanaro (skip@pobox.com).
1375
1398
1376 def __getitem__(self, name):
1399 def __getitem__(self, name):
1377 frame = sys._getframe(1)
1400 frame = sys._getframe(1)
1378 return eval(name, frame.f_globals, frame.f_locals)
1401 return eval(name, frame.f_globals, frame.f_locals)
1379
1402
1380 EvalString = EvalDict # for backwards compatibility
1403 EvalString = EvalDict # for backwards compatibility
1381 #----------------------------------------------------------------------------
1404 #----------------------------------------------------------------------------
1382 def qw(words,flat=0,sep=None,maxsplit=-1):
1405 def qw(words,flat=0,sep=None,maxsplit=-1):
1383 """Similar to Perl's qw() operator, but with some more options.
1406 """Similar to Perl's qw() operator, but with some more options.
1384
1407
1385 qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
1408 qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
1386
1409
1387 words can also be a list itself, and with flat=1, the output will be
1410 words can also be a list itself, and with flat=1, the output will be
1388 recursively flattened.
1411 recursively flattened.
1389
1412
1390 Examples:
1413 Examples:
1391
1414
1392 >>> qw('1 2')
1415 >>> qw('1 2')
1393 ['1', '2']
1416 ['1', '2']
1394
1417
1395 >>> qw(['a b','1 2',['m n','p q']])
1418 >>> qw(['a b','1 2',['m n','p q']])
1396 [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
1419 [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
1397
1420
1398 >>> qw(['a b','1 2',['m n','p q']],flat=1)
1421 >>> qw(['a b','1 2',['m n','p q']],flat=1)
1399 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
1422 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
1400 """
1423 """
1401
1424
1402 if type(words) in StringTypes:
1425 if type(words) in StringTypes:
1403 return [word.strip() for word in words.split(sep,maxsplit)
1426 return [word.strip() for word in words.split(sep,maxsplit)
1404 if word and not word.isspace() ]
1427 if word and not word.isspace() ]
1405 if flat:
1428 if flat:
1406 return flatten(map(qw,words,[1]*len(words)))
1429 return flatten(map(qw,words,[1]*len(words)))
1407 return map(qw,words)
1430 return map(qw,words)
1408
1431
1409 #----------------------------------------------------------------------------
1432 #----------------------------------------------------------------------------
1410 def qwflat(words,sep=None,maxsplit=-1):
1433 def qwflat(words,sep=None,maxsplit=-1):
1411 """Calls qw(words) in flat mode. It's just a convenient shorthand."""
1434 """Calls qw(words) in flat mode. It's just a convenient shorthand."""
1412 return qw(words,1,sep,maxsplit)
1435 return qw(words,1,sep,maxsplit)
1413
1436
1414 #----------------------------------------------------------------------------
1437 #----------------------------------------------------------------------------
1415 def qw_lol(indata):
1438 def qw_lol(indata):
1416 """qw_lol('a b') -> [['a','b']],
1439 """qw_lol('a b') -> [['a','b']],
1417 otherwise it's just a call to qw().
1440 otherwise it's just a call to qw().
1418
1441
1419 We need this to make sure the modules_some keys *always* end up as a
1442 We need this to make sure the modules_some keys *always* end up as a
1420 list of lists."""
1443 list of lists."""
1421
1444
1422 if type(indata) in StringTypes:
1445 if type(indata) in StringTypes:
1423 return [qw(indata)]
1446 return [qw(indata)]
1424 else:
1447 else:
1425 return qw(indata)
1448 return qw(indata)
1426
1449
1427 #----------------------------------------------------------------------------
1450 #----------------------------------------------------------------------------
1428 def grep(pat,list,case=1):
1451 def grep(pat,list,case=1):
1429 """Simple minded grep-like function.
1452 """Simple minded grep-like function.
1430 grep(pat,list) returns occurrences of pat in list, None on failure.
1453 grep(pat,list) returns occurrences of pat in list, None on failure.
1431
1454
1432 It only does simple string matching, with no support for regexps. Use the
1455 It only does simple string matching, with no support for regexps. Use the
1433 option case=0 for case-insensitive matching."""
1456 option case=0 for case-insensitive matching."""
1434
1457
1435 # This is pretty crude. At least it should implement copying only references
1458 # This is pretty crude. At least it should implement copying only references
1436 # to the original data in case it's big. Now it copies the data for output.
1459 # to the original data in case it's big. Now it copies the data for output.
1437 out=[]
1460 out=[]
1438 if case:
1461 if case:
1439 for term in list:
1462 for term in list:
1440 if term.find(pat)>-1: out.append(term)
1463 if term.find(pat)>-1: out.append(term)
1441 else:
1464 else:
1442 lpat=pat.lower()
1465 lpat=pat.lower()
1443 for term in list:
1466 for term in list:
1444 if term.lower().find(lpat)>-1: out.append(term)
1467 if term.lower().find(lpat)>-1: out.append(term)
1445
1468
1446 if len(out): return out
1469 if len(out): return out
1447 else: return None
1470 else: return None
1448
1471
1449 #----------------------------------------------------------------------------
1472 #----------------------------------------------------------------------------
1450 def dgrep(pat,*opts):
1473 def dgrep(pat,*opts):
1451 """Return grep() on dir()+dir(__builtins__).
1474 """Return grep() on dir()+dir(__builtins__).
1452
1475
1453 A very common use of grep() when working interactively."""
1476 A very common use of grep() when working interactively."""
1454
1477
1455 return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
1478 return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
1456
1479
1457 #----------------------------------------------------------------------------
1480 #----------------------------------------------------------------------------
1458 def idgrep(pat):
1481 def idgrep(pat):
1459 """Case-insensitive dgrep()"""
1482 """Case-insensitive dgrep()"""
1460
1483
1461 return dgrep(pat,0)
1484 return dgrep(pat,0)
1462
1485
1463 #----------------------------------------------------------------------------
1486 #----------------------------------------------------------------------------
1464 def igrep(pat,list):
1487 def igrep(pat,list):
1465 """Synonym for case-insensitive grep."""
1488 """Synonym for case-insensitive grep."""
1466
1489
1467 return grep(pat,list,case=0)
1490 return grep(pat,list,case=0)
1468
1491
1469 #----------------------------------------------------------------------------
1492 #----------------------------------------------------------------------------
1470 def indent(str,nspaces=4,ntabs=0):
1493 def indent(str,nspaces=4,ntabs=0):
1471 """Indent a string a given number of spaces or tabstops.
1494 """Indent a string a given number of spaces or tabstops.
1472
1495
1473 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
1496 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
1474 """
1497 """
1475 if str is None:
1498 if str is None:
1476 return
1499 return
1477 ind = '\t'*ntabs+' '*nspaces
1500 ind = '\t'*ntabs+' '*nspaces
1478 outstr = '%s%s' % (ind,str.replace(os.linesep,os.linesep+ind))
1501 outstr = '%s%s' % (ind,str.replace(os.linesep,os.linesep+ind))
1479 if outstr.endswith(os.linesep+ind):
1502 if outstr.endswith(os.linesep+ind):
1480 return outstr[:-len(ind)]
1503 return outstr[:-len(ind)]
1481 else:
1504 else:
1482 return outstr
1505 return outstr
1483
1506
1484 #-----------------------------------------------------------------------------
1507 #-----------------------------------------------------------------------------
1485 def native_line_ends(filename,backup=1):
1508 def native_line_ends(filename,backup=1):
1486 """Convert (in-place) a file to line-ends native to the current OS.
1509 """Convert (in-place) a file to line-ends native to the current OS.
1487
1510
1488 If the optional backup argument is given as false, no backup of the
1511 If the optional backup argument is given as false, no backup of the
1489 original file is left. """
1512 original file is left. """
1490
1513
1491 backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
1514 backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
1492
1515
1493 bak_filename = filename + backup_suffixes[os.name]
1516 bak_filename = filename + backup_suffixes[os.name]
1494
1517
1495 original = open(filename).read()
1518 original = open(filename).read()
1496 shutil.copy2(filename,bak_filename)
1519 shutil.copy2(filename,bak_filename)
1497 try:
1520 try:
1498 new = open(filename,'wb')
1521 new = open(filename,'wb')
1499 new.write(os.linesep.join(original.splitlines()))
1522 new.write(os.linesep.join(original.splitlines()))
1500 new.write(os.linesep) # ALWAYS put an eol at the end of the file
1523 new.write(os.linesep) # ALWAYS put an eol at the end of the file
1501 new.close()
1524 new.close()
1502 except:
1525 except:
1503 os.rename(bak_filename,filename)
1526 os.rename(bak_filename,filename)
1504 if not backup:
1527 if not backup:
1505 try:
1528 try:
1506 os.remove(bak_filename)
1529 os.remove(bak_filename)
1507 except:
1530 except:
1508 pass
1531 pass
1509
1532
1510 #----------------------------------------------------------------------------
1533 #----------------------------------------------------------------------------
1511 def get_pager_cmd(pager_cmd = None):
1534 def get_pager_cmd(pager_cmd = None):
1512 """Return a pager command.
1535 """Return a pager command.
1513
1536
1514 Makes some attempts at finding an OS-correct one."""
1537 Makes some attempts at finding an OS-correct one."""
1515
1538
1516 if os.name == 'posix':
1539 if os.name == 'posix':
1517 default_pager_cmd = 'less -r' # -r for color control sequences
1540 default_pager_cmd = 'less -r' # -r for color control sequences
1518 elif os.name in ['nt','dos']:
1541 elif os.name in ['nt','dos']:
1519 default_pager_cmd = 'type'
1542 default_pager_cmd = 'type'
1520
1543
1521 if pager_cmd is None:
1544 if pager_cmd is None:
1522 try:
1545 try:
1523 pager_cmd = os.environ['PAGER']
1546 pager_cmd = os.environ['PAGER']
1524 except:
1547 except:
1525 pager_cmd = default_pager_cmd
1548 pager_cmd = default_pager_cmd
1526 return pager_cmd
1549 return pager_cmd
1527
1550
1528 #-----------------------------------------------------------------------------
1551 #-----------------------------------------------------------------------------
1529 def get_pager_start(pager,start):
1552 def get_pager_start(pager,start):
1530 """Return the string for paging files with an offset.
1553 """Return the string for paging files with an offset.
1531
1554
1532 This is the '+N' argument which less and more (under Unix) accept.
1555 This is the '+N' argument which less and more (under Unix) accept.
1533 """
1556 """
1534
1557
1535 if pager in ['less','more']:
1558 if pager in ['less','more']:
1536 if start:
1559 if start:
1537 start_string = '+' + str(start)
1560 start_string = '+' + str(start)
1538 else:
1561 else:
1539 start_string = ''
1562 start_string = ''
1540 else:
1563 else:
1541 start_string = ''
1564 start_string = ''
1542 return start_string
1565 return start_string
1543
1566
1544 #----------------------------------------------------------------------------
1567 #----------------------------------------------------------------------------
1545 # (X)emacs on W32 doesn't like to be bypassed with msvcrt.getch()
1568 # (X)emacs on W32 doesn't like to be bypassed with msvcrt.getch()
1546 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
1569 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
1547 import msvcrt
1570 import msvcrt
1548 def page_more():
1571 def page_more():
1549 """ Smart pausing between pages
1572 """ Smart pausing between pages
1550
1573
1551 @return: True if need print more lines, False if quit
1574 @return: True if need print more lines, False if quit
1552 """
1575 """
1553 Term.cout.write('---Return to continue, q to quit--- ')
1576 Term.cout.write('---Return to continue, q to quit--- ')
1554 ans = msvcrt.getch()
1577 ans = msvcrt.getch()
1555 if ans in ("q", "Q"):
1578 if ans in ("q", "Q"):
1556 result = False
1579 result = False
1557 else:
1580 else:
1558 result = True
1581 result = True
1559 Term.cout.write("\b"*37 + " "*37 + "\b"*37)
1582 Term.cout.write("\b"*37 + " "*37 + "\b"*37)
1560 return result
1583 return result
1561 else:
1584 else:
1562 def page_more():
1585 def page_more():
1563 ans = raw_input('---Return to continue, q to quit--- ')
1586 ans = raw_input('---Return to continue, q to quit--- ')
1564 if ans.lower().startswith('q'):
1587 if ans.lower().startswith('q'):
1565 return False
1588 return False
1566 else:
1589 else:
1567 return True
1590 return True
1568
1591
1569 esc_re = re.compile(r"(\x1b[^m]+m)")
1592 esc_re = re.compile(r"(\x1b[^m]+m)")
1570
1593
1571 def page_dumb(strng,start=0,screen_lines=25):
1594 def page_dumb(strng,start=0,screen_lines=25):
1572 """Very dumb 'pager' in Python, for when nothing else works.
1595 """Very dumb 'pager' in Python, for when nothing else works.
1573
1596
1574 Only moves forward, same interface as page(), except for pager_cmd and
1597 Only moves forward, same interface as page(), except for pager_cmd and
1575 mode."""
1598 mode."""
1576
1599
1577 out_ln = strng.splitlines()[start:]
1600 out_ln = strng.splitlines()[start:]
1578 screens = chop(out_ln,screen_lines-1)
1601 screens = chop(out_ln,screen_lines-1)
1579 if len(screens) == 1:
1602 if len(screens) == 1:
1580 print >>Term.cout, os.linesep.join(screens[0])
1603 print >>Term.cout, os.linesep.join(screens[0])
1581 else:
1604 else:
1582 last_escape = ""
1605 last_escape = ""
1583 for scr in screens[0:-1]:
1606 for scr in screens[0:-1]:
1584 hunk = os.linesep.join(scr)
1607 hunk = os.linesep.join(scr)
1585 print >>Term.cout, last_escape + hunk
1608 print >>Term.cout, last_escape + hunk
1586 if not page_more():
1609 if not page_more():
1587 return
1610 return
1588 esc_list = esc_re.findall(hunk)
1611 esc_list = esc_re.findall(hunk)
1589 if len(esc_list) > 0:
1612 if len(esc_list) > 0:
1590 last_escape = esc_list[-1]
1613 last_escape = esc_list[-1]
1591 print >>Term.cout, last_escape + os.linesep.join(screens[-1])
1614 print >>Term.cout, last_escape + os.linesep.join(screens[-1])
1592
1615
1593 #----------------------------------------------------------------------------
1616 #----------------------------------------------------------------------------
1594 def page(strng,start=0,screen_lines=0,pager_cmd = None):
1617 def page(strng,start=0,screen_lines=0,pager_cmd = None):
1595 """Print a string, piping through a pager after a certain length.
1618 """Print a string, piping through a pager after a certain length.
1596
1619
1597 The screen_lines parameter specifies the number of *usable* lines of your
1620 The screen_lines parameter specifies the number of *usable* lines of your
1598 terminal screen (total lines minus lines you need to reserve to show other
1621 terminal screen (total lines minus lines you need to reserve to show other
1599 information).
1622 information).
1600
1623
1601 If you set screen_lines to a number <=0, page() will try to auto-determine
1624 If you set screen_lines to a number <=0, page() will try to auto-determine
1602 your screen size and will only use up to (screen_size+screen_lines) for
1625 your screen size and will only use up to (screen_size+screen_lines) for
1603 printing, paging after that. That is, if you want auto-detection but need
1626 printing, paging after that. That is, if you want auto-detection but need
1604 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
1627 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
1605 auto-detection without any lines reserved simply use screen_lines = 0.
1628 auto-detection without any lines reserved simply use screen_lines = 0.
1606
1629
1607 If a string won't fit in the allowed lines, it is sent through the
1630 If a string won't fit in the allowed lines, it is sent through the
1608 specified pager command. If none given, look for PAGER in the environment,
1631 specified pager command. If none given, look for PAGER in the environment,
1609 and ultimately default to less.
1632 and ultimately default to less.
1610
1633
1611 If no system pager works, the string is sent through a 'dumb pager'
1634 If no system pager works, the string is sent through a 'dumb pager'
1612 written in python, very simplistic.
1635 written in python, very simplistic.
1613 """
1636 """
1614
1637
1615 # Some routines may auto-compute start offsets incorrectly and pass a
1638 # Some routines may auto-compute start offsets incorrectly and pass a
1616 # negative value. Offset to 0 for robustness.
1639 # negative value. Offset to 0 for robustness.
1617 start = max(0,start)
1640 start = max(0,start)
1618
1641
1619 # first, try the hook
1642 # first, try the hook
1620 ip = ipapi.get()
1643 ip = ipapi.get()
1621 if ip:
1644 if ip:
1622 try:
1645 try:
1623 ip.IP.hooks.show_in_pager(strng)
1646 ip.IP.hooks.show_in_pager(strng)
1624 return
1647 return
1625 except ipapi.TryNext:
1648 except ipapi.TryNext:
1626 pass
1649 pass
1627
1650
1628 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
1651 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
1629 TERM = os.environ.get('TERM','dumb')
1652 TERM = os.environ.get('TERM','dumb')
1630 if TERM in ['dumb','emacs'] and os.name != 'nt':
1653 if TERM in ['dumb','emacs'] and os.name != 'nt':
1631 print strng
1654 print strng
1632 return
1655 return
1633 # chop off the topmost part of the string we don't want to see
1656 # chop off the topmost part of the string we don't want to see
1634 str_lines = strng.split(os.linesep)[start:]
1657 str_lines = strng.split(os.linesep)[start:]
1635 str_toprint = os.linesep.join(str_lines)
1658 str_toprint = os.linesep.join(str_lines)
1636 num_newlines = len(str_lines)
1659 num_newlines = len(str_lines)
1637 len_str = len(str_toprint)
1660 len_str = len(str_toprint)
1638
1661
1639 # Dumb heuristics to guesstimate number of on-screen lines the string
1662 # Dumb heuristics to guesstimate number of on-screen lines the string
1640 # takes. Very basic, but good enough for docstrings in reasonable
1663 # takes. Very basic, but good enough for docstrings in reasonable
1641 # terminals. If someone later feels like refining it, it's not hard.
1664 # terminals. If someone later feels like refining it, it's not hard.
1642 numlines = max(num_newlines,int(len_str/80)+1)
1665 numlines = max(num_newlines,int(len_str/80)+1)
1643
1666
1644 if os.name == "nt":
1667 if os.name == "nt":
1645 screen_lines_def = get_console_size(defaulty=25)[1]
1668 screen_lines_def = get_console_size(defaulty=25)[1]
1646 else:
1669 else:
1647 screen_lines_def = 25 # default value if we can't auto-determine
1670 screen_lines_def = 25 # default value if we can't auto-determine
1648
1671
1649 # auto-determine screen size
1672 # auto-determine screen size
1650 if screen_lines <= 0:
1673 if screen_lines <= 0:
1651 if TERM=='xterm':
1674 if TERM=='xterm':
1652 use_curses = USE_CURSES
1675 use_curses = USE_CURSES
1653 else:
1676 else:
1654 # curses causes problems on many terminals other than xterm.
1677 # curses causes problems on many terminals other than xterm.
1655 use_curses = False
1678 use_curses = False
1656 if use_curses:
1679 if use_curses:
1657 # There is a bug in curses, where *sometimes* it fails to properly
1680 # There is a bug in curses, where *sometimes* it fails to properly
1658 # initialize, and then after the endwin() call is made, the
1681 # initialize, and then after the endwin() call is made, the
1659 # terminal is left in an unusable state. Rather than trying to
1682 # terminal is left in an unusable state. Rather than trying to
1660 # check everytime for this (by requesting and comparing termios
1683 # check everytime for this (by requesting and comparing termios
1661 # flags each time), we just save the initial terminal state and
1684 # flags each time), we just save the initial terminal state and
1662 # unconditionally reset it every time. It's cheaper than making
1685 # unconditionally reset it every time. It's cheaper than making
1663 # the checks.
1686 # the checks.
1664 term_flags = termios.tcgetattr(sys.stdout)
1687 term_flags = termios.tcgetattr(sys.stdout)
1665 scr = curses.initscr()
1688 scr = curses.initscr()
1666 screen_lines_real,screen_cols = scr.getmaxyx()
1689 screen_lines_real,screen_cols = scr.getmaxyx()
1667 curses.endwin()
1690 curses.endwin()
1668 # Restore terminal state in case endwin() didn't.
1691 # Restore terminal state in case endwin() didn't.
1669 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
1692 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
1670 # Now we have what we needed: the screen size in rows/columns
1693 # Now we have what we needed: the screen size in rows/columns
1671 screen_lines += screen_lines_real
1694 screen_lines += screen_lines_real
1672 #print '***Screen size:',screen_lines_real,'lines x',\
1695 #print '***Screen size:',screen_lines_real,'lines x',\
1673 #screen_cols,'columns.' # dbg
1696 #screen_cols,'columns.' # dbg
1674 else:
1697 else:
1675 screen_lines += screen_lines_def
1698 screen_lines += screen_lines_def
1676
1699
1677 #print 'numlines',numlines,'screenlines',screen_lines # dbg
1700 #print 'numlines',numlines,'screenlines',screen_lines # dbg
1678 if numlines <= screen_lines :
1701 if numlines <= screen_lines :
1679 #print '*** normal print' # dbg
1702 #print '*** normal print' # dbg
1680 print >>Term.cout, str_toprint
1703 print >>Term.cout, str_toprint
1681 else:
1704 else:
1682 # Try to open pager and default to internal one if that fails.
1705 # Try to open pager and default to internal one if that fails.
1683 # All failure modes are tagged as 'retval=1', to match the return
1706 # All failure modes are tagged as 'retval=1', to match the return
1684 # value of a failed system command. If any intermediate attempt
1707 # value of a failed system command. If any intermediate attempt
1685 # sets retval to 1, at the end we resort to our own page_dumb() pager.
1708 # sets retval to 1, at the end we resort to our own page_dumb() pager.
1686 pager_cmd = get_pager_cmd(pager_cmd)
1709 pager_cmd = get_pager_cmd(pager_cmd)
1687 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
1710 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
1688 if os.name == 'nt':
1711 if os.name == 'nt':
1689 if pager_cmd.startswith('type'):
1712 if pager_cmd.startswith('type'):
1690 # The default WinXP 'type' command is failing on complex strings.
1713 # The default WinXP 'type' command is failing on complex strings.
1691 retval = 1
1714 retval = 1
1692 else:
1715 else:
1693 tmpname = tempfile.mktemp('.txt')
1716 tmpname = tempfile.mktemp('.txt')
1694 tmpfile = file(tmpname,'wt')
1717 tmpfile = file(tmpname,'wt')
1695 tmpfile.write(strng)
1718 tmpfile.write(strng)
1696 tmpfile.close()
1719 tmpfile.close()
1697 cmd = "%s < %s" % (pager_cmd,tmpname)
1720 cmd = "%s < %s" % (pager_cmd,tmpname)
1698 if os.system(cmd):
1721 if os.system(cmd):
1699 retval = 1
1722 retval = 1
1700 else:
1723 else:
1701 retval = None
1724 retval = None
1702 os.remove(tmpname)
1725 os.remove(tmpname)
1703 else:
1726 else:
1704 try:
1727 try:
1705 retval = None
1728 retval = None
1706 # if I use popen4, things hang. No idea why.
1729 # if I use popen4, things hang. No idea why.
1707 #pager,shell_out = os.popen4(pager_cmd)
1730 #pager,shell_out = os.popen4(pager_cmd)
1708 pager = os.popen(pager_cmd,'w')
1731 pager = os.popen(pager_cmd,'w')
1709 pager.write(strng)
1732 pager.write(strng)
1710 pager.close()
1733 pager.close()
1711 retval = pager.close() # success returns None
1734 retval = pager.close() # success returns None
1712 except IOError,msg: # broken pipe when user quits
1735 except IOError,msg: # broken pipe when user quits
1713 if msg.args == (32,'Broken pipe'):
1736 if msg.args == (32,'Broken pipe'):
1714 retval = None
1737 retval = None
1715 else:
1738 else:
1716 retval = 1
1739 retval = 1
1717 except OSError:
1740 except OSError:
1718 # Other strange problems, sometimes seen in Win2k/cygwin
1741 # Other strange problems, sometimes seen in Win2k/cygwin
1719 retval = 1
1742 retval = 1
1720 if retval is not None:
1743 if retval is not None:
1721 page_dumb(strng,screen_lines=screen_lines)
1744 page_dumb(strng,screen_lines=screen_lines)
1722
1745
1723 #----------------------------------------------------------------------------
1746 #----------------------------------------------------------------------------
1724 def page_file(fname,start = 0, pager_cmd = None):
1747 def page_file(fname,start = 0, pager_cmd = None):
1725 """Page a file, using an optional pager command and starting line.
1748 """Page a file, using an optional pager command and starting line.
1726 """
1749 """
1727
1750
1728 pager_cmd = get_pager_cmd(pager_cmd)
1751 pager_cmd = get_pager_cmd(pager_cmd)
1729 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
1752 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
1730
1753
1731 try:
1754 try:
1732 if os.environ['TERM'] in ['emacs','dumb']:
1755 if os.environ['TERM'] in ['emacs','dumb']:
1733 raise EnvironmentError
1756 raise EnvironmentError
1734 xsys(pager_cmd + ' ' + fname)
1757 xsys(pager_cmd + ' ' + fname)
1735 except:
1758 except:
1736 try:
1759 try:
1737 if start > 0:
1760 if start > 0:
1738 start -= 1
1761 start -= 1
1739 page(open(fname).read(),start)
1762 page(open(fname).read(),start)
1740 except:
1763 except:
1741 print 'Unable to show file',`fname`
1764 print 'Unable to show file',`fname`
1742
1765
1743
1766
1744 #----------------------------------------------------------------------------
1767 #----------------------------------------------------------------------------
1745 def snip_print(str,width = 75,print_full = 0,header = ''):
1768 def snip_print(str,width = 75,print_full = 0,header = ''):
1746 """Print a string snipping the midsection to fit in width.
1769 """Print a string snipping the midsection to fit in width.
1747
1770
1748 print_full: mode control:
1771 print_full: mode control:
1749 - 0: only snip long strings
1772 - 0: only snip long strings
1750 - 1: send to page() directly.
1773 - 1: send to page() directly.
1751 - 2: snip long strings and ask for full length viewing with page()
1774 - 2: snip long strings and ask for full length viewing with page()
1752 Return 1 if snipping was necessary, 0 otherwise."""
1775 Return 1 if snipping was necessary, 0 otherwise."""
1753
1776
1754 if print_full == 1:
1777 if print_full == 1:
1755 page(header+str)
1778 page(header+str)
1756 return 0
1779 return 0
1757
1780
1758 print header,
1781 print header,
1759 if len(str) < width:
1782 if len(str) < width:
1760 print str
1783 print str
1761 snip = 0
1784 snip = 0
1762 else:
1785 else:
1763 whalf = int((width -5)/2)
1786 whalf = int((width -5)/2)
1764 print str[:whalf] + ' <...> ' + str[-whalf:]
1787 print str[:whalf] + ' <...> ' + str[-whalf:]
1765 snip = 1
1788 snip = 1
1766 if snip and print_full == 2:
1789 if snip and print_full == 2:
1767 if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
1790 if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
1768 page(str)
1791 page(str)
1769 return snip
1792 return snip
1770
1793
1771 #****************************************************************************
1794 #****************************************************************************
1772 # lists, dicts and structures
1795 # lists, dicts and structures
1773
1796
1774 def belong(candidates,checklist):
1797 def belong(candidates,checklist):
1775 """Check whether a list of items appear in a given list of options.
1798 """Check whether a list of items appear in a given list of options.
1776
1799
1777 Returns a list of 1 and 0, one for each candidate given."""
1800 Returns a list of 1 and 0, one for each candidate given."""
1778
1801
1779 return [x in checklist for x in candidates]
1802 return [x in checklist for x in candidates]
1780
1803
1781 #----------------------------------------------------------------------------
1804 #----------------------------------------------------------------------------
1782 def uniq_stable(elems):
1805 def uniq_stable(elems):
1783 """uniq_stable(elems) -> list
1806 """uniq_stable(elems) -> list
1784
1807
1785 Return from an iterable, a list of all the unique elements in the input,
1808 Return from an iterable, a list of all the unique elements in the input,
1786 but maintaining the order in which they first appear.
1809 but maintaining the order in which they first appear.
1787
1810
1788 A naive solution to this problem which just makes a dictionary with the
1811 A naive solution to this problem which just makes a dictionary with the
1789 elements as keys fails to respect the stability condition, since
1812 elements as keys fails to respect the stability condition, since
1790 dictionaries are unsorted by nature.
1813 dictionaries are unsorted by nature.
1791
1814
1792 Note: All elements in the input must be valid dictionary keys for this
1815 Note: All elements in the input must be valid dictionary keys for this
1793 routine to work, as it internally uses a dictionary for efficiency
1816 routine to work, as it internally uses a dictionary for efficiency
1794 reasons."""
1817 reasons."""
1795
1818
1796 unique = []
1819 unique = []
1797 unique_dict = {}
1820 unique_dict = {}
1798 for nn in elems:
1821 for nn in elems:
1799 if nn not in unique_dict:
1822 if nn not in unique_dict:
1800 unique.append(nn)
1823 unique.append(nn)
1801 unique_dict[nn] = None
1824 unique_dict[nn] = None
1802 return unique
1825 return unique
1803
1826
1804 #----------------------------------------------------------------------------
1827 #----------------------------------------------------------------------------
1805 class NLprinter:
1828 class NLprinter:
1806 """Print an arbitrarily nested list, indicating index numbers.
1829 """Print an arbitrarily nested list, indicating index numbers.
1807
1830
1808 An instance of this class called nlprint is available and callable as a
1831 An instance of this class called nlprint is available and callable as a
1809 function.
1832 function.
1810
1833
1811 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
1834 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
1812 and using 'sep' to separate the index from the value. """
1835 and using 'sep' to separate the index from the value. """
1813
1836
1814 def __init__(self):
1837 def __init__(self):
1815 self.depth = 0
1838 self.depth = 0
1816
1839
1817 def __call__(self,lst,pos='',**kw):
1840 def __call__(self,lst,pos='',**kw):
1818 """Prints the nested list numbering levels."""
1841 """Prints the nested list numbering levels."""
1819 kw.setdefault('indent',' ')
1842 kw.setdefault('indent',' ')
1820 kw.setdefault('sep',': ')
1843 kw.setdefault('sep',': ')
1821 kw.setdefault('start',0)
1844 kw.setdefault('start',0)
1822 kw.setdefault('stop',len(lst))
1845 kw.setdefault('stop',len(lst))
1823 # we need to remove start and stop from kw so they don't propagate
1846 # we need to remove start and stop from kw so they don't propagate
1824 # into a recursive call for a nested list.
1847 # into a recursive call for a nested list.
1825 start = kw['start']; del kw['start']
1848 start = kw['start']; del kw['start']
1826 stop = kw['stop']; del kw['stop']
1849 stop = kw['stop']; del kw['stop']
1827 if self.depth == 0 and 'header' in kw.keys():
1850 if self.depth == 0 and 'header' in kw.keys():
1828 print kw['header']
1851 print kw['header']
1829
1852
1830 for idx in range(start,stop):
1853 for idx in range(start,stop):
1831 elem = lst[idx]
1854 elem = lst[idx]
1832 if type(elem)==type([]):
1855 if type(elem)==type([]):
1833 self.depth += 1
1856 self.depth += 1
1834 self.__call__(elem,itpl('$pos$idx,'),**kw)
1857 self.__call__(elem,itpl('$pos$idx,'),**kw)
1835 self.depth -= 1
1858 self.depth -= 1
1836 else:
1859 else:
1837 printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
1860 printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
1838
1861
1839 nlprint = NLprinter()
1862 nlprint = NLprinter()
1840 #----------------------------------------------------------------------------
1863 #----------------------------------------------------------------------------
1841 def all_belong(candidates,checklist):
1864 def all_belong(candidates,checklist):
1842 """Check whether a list of items ALL appear in a given list of options.
1865 """Check whether a list of items ALL appear in a given list of options.
1843
1866
1844 Returns a single 1 or 0 value."""
1867 Returns a single 1 or 0 value."""
1845
1868
1846 return 1-(0 in [x in checklist for x in candidates])
1869 return 1-(0 in [x in checklist for x in candidates])
1847
1870
1848 #----------------------------------------------------------------------------
1871 #----------------------------------------------------------------------------
1849 def sort_compare(lst1,lst2,inplace = 1):
1872 def sort_compare(lst1,lst2,inplace = 1):
1850 """Sort and compare two lists.
1873 """Sort and compare two lists.
1851
1874
1852 By default it does it in place, thus modifying the lists. Use inplace = 0
1875 By default it does it in place, thus modifying the lists. Use inplace = 0
1853 to avoid that (at the cost of temporary copy creation)."""
1876 to avoid that (at the cost of temporary copy creation)."""
1854 if not inplace:
1877 if not inplace:
1855 lst1 = lst1[:]
1878 lst1 = lst1[:]
1856 lst2 = lst2[:]
1879 lst2 = lst2[:]
1857 lst1.sort(); lst2.sort()
1880 lst1.sort(); lst2.sort()
1858 return lst1 == lst2
1881 return lst1 == lst2
1859
1882
1860 #----------------------------------------------------------------------------
1883 #----------------------------------------------------------------------------
1861 def list2dict(lst):
1884 def list2dict(lst):
1862 """Takes a list of (key,value) pairs and turns it into a dict."""
1885 """Takes a list of (key,value) pairs and turns it into a dict."""
1863
1886
1864 dic = {}
1887 dic = {}
1865 for k,v in lst: dic[k] = v
1888 for k,v in lst: dic[k] = v
1866 return dic
1889 return dic
1867
1890
1868 #----------------------------------------------------------------------------
1891 #----------------------------------------------------------------------------
1869 def list2dict2(lst,default=''):
1892 def list2dict2(lst,default=''):
1870 """Takes a list and turns it into a dict.
1893 """Takes a list and turns it into a dict.
1871 Much slower than list2dict, but more versatile. This version can take
1894 Much slower than list2dict, but more versatile. This version can take
1872 lists with sublists of arbitrary length (including sclars)."""
1895 lists with sublists of arbitrary length (including sclars)."""
1873
1896
1874 dic = {}
1897 dic = {}
1875 for elem in lst:
1898 for elem in lst:
1876 if type(elem) in (types.ListType,types.TupleType):
1899 if type(elem) in (types.ListType,types.TupleType):
1877 size = len(elem)
1900 size = len(elem)
1878 if size == 0:
1901 if size == 0:
1879 pass
1902 pass
1880 elif size == 1:
1903 elif size == 1:
1881 dic[elem] = default
1904 dic[elem] = default
1882 else:
1905 else:
1883 k,v = elem[0], elem[1:]
1906 k,v = elem[0], elem[1:]
1884 if len(v) == 1: v = v[0]
1907 if len(v) == 1: v = v[0]
1885 dic[k] = v
1908 dic[k] = v
1886 else:
1909 else:
1887 dic[elem] = default
1910 dic[elem] = default
1888 return dic
1911 return dic
1889
1912
1890 #----------------------------------------------------------------------------
1913 #----------------------------------------------------------------------------
1891 def flatten(seq):
1914 def flatten(seq):
1892 """Flatten a list of lists (NOT recursive, only works for 2d lists)."""
1915 """Flatten a list of lists (NOT recursive, only works for 2d lists)."""
1893
1916
1894 return [x for subseq in seq for x in subseq]
1917 return [x for subseq in seq for x in subseq]
1895
1918
1896 #----------------------------------------------------------------------------
1919 #----------------------------------------------------------------------------
1897 def get_slice(seq,start=0,stop=None,step=1):
1920 def get_slice(seq,start=0,stop=None,step=1):
1898 """Get a slice of a sequence with variable step. Specify start,stop,step."""
1921 """Get a slice of a sequence with variable step. Specify start,stop,step."""
1899 if stop == None:
1922 if stop == None:
1900 stop = len(seq)
1923 stop = len(seq)
1901 item = lambda i: seq[i]
1924 item = lambda i: seq[i]
1902 return map(item,xrange(start,stop,step))
1925 return map(item,xrange(start,stop,step))
1903
1926
1904 #----------------------------------------------------------------------------
1927 #----------------------------------------------------------------------------
1905 def chop(seq,size):
1928 def chop(seq,size):
1906 """Chop a sequence into chunks of the given size."""
1929 """Chop a sequence into chunks of the given size."""
1907 chunk = lambda i: seq[i:i+size]
1930 chunk = lambda i: seq[i:i+size]
1908 return map(chunk,xrange(0,len(seq),size))
1931 return map(chunk,xrange(0,len(seq),size))
1909
1932
1910 #----------------------------------------------------------------------------
1933 #----------------------------------------------------------------------------
1911 # with is a keyword as of python 2.5, so this function is renamed to withobj
1934 # with is a keyword as of python 2.5, so this function is renamed to withobj
1912 # from its old 'with' name.
1935 # from its old 'with' name.
1913 def with_obj(object, **args):
1936 def with_obj(object, **args):
1914 """Set multiple attributes for an object, similar to Pascal's with.
1937 """Set multiple attributes for an object, similar to Pascal's with.
1915
1938
1916 Example:
1939 Example:
1917 with_obj(jim,
1940 with_obj(jim,
1918 born = 1960,
1941 born = 1960,
1919 haircolour = 'Brown',
1942 haircolour = 'Brown',
1920 eyecolour = 'Green')
1943 eyecolour = 'Green')
1921
1944
1922 Credit: Greg Ewing, in
1945 Credit: Greg Ewing, in
1923 http://mail.python.org/pipermail/python-list/2001-May/040703.html.
1946 http://mail.python.org/pipermail/python-list/2001-May/040703.html.
1924
1947
1925 NOTE: up until IPython 0.7.2, this was called simply 'with', but 'with'
1948 NOTE: up until IPython 0.7.2, this was called simply 'with', but 'with'
1926 has become a keyword for Python 2.5, so we had to rename it."""
1949 has become a keyword for Python 2.5, so we had to rename it."""
1927
1950
1928 object.__dict__.update(args)
1951 object.__dict__.update(args)
1929
1952
1930 #----------------------------------------------------------------------------
1953 #----------------------------------------------------------------------------
1931 def setattr_list(obj,alist,nspace = None):
1954 def setattr_list(obj,alist,nspace = None):
1932 """Set a list of attributes for an object taken from a namespace.
1955 """Set a list of attributes for an object taken from a namespace.
1933
1956
1934 setattr_list(obj,alist,nspace) -> sets in obj all the attributes listed in
1957 setattr_list(obj,alist,nspace) -> sets in obj all the attributes listed in
1935 alist with their values taken from nspace, which must be a dict (something
1958 alist with their values taken from nspace, which must be a dict (something
1936 like locals() will often do) If nspace isn't given, locals() of the
1959 like locals() will often do) If nspace isn't given, locals() of the
1937 *caller* is used, so in most cases you can omit it.
1960 *caller* is used, so in most cases you can omit it.
1938
1961
1939 Note that alist can be given as a string, which will be automatically
1962 Note that alist can be given as a string, which will be automatically
1940 split into a list on whitespace. If given as a list, it must be a list of
1963 split into a list on whitespace. If given as a list, it must be a list of
1941 *strings* (the variable names themselves), not of variables."""
1964 *strings* (the variable names themselves), not of variables."""
1942
1965
1943 # this grabs the local variables from the *previous* call frame -- that is
1966 # this grabs the local variables from the *previous* call frame -- that is
1944 # the locals from the function that called setattr_list().
1967 # the locals from the function that called setattr_list().
1945 # - snipped from weave.inline()
1968 # - snipped from weave.inline()
1946 if nspace is None:
1969 if nspace is None:
1947 call_frame = sys._getframe().f_back
1970 call_frame = sys._getframe().f_back
1948 nspace = call_frame.f_locals
1971 nspace = call_frame.f_locals
1949
1972
1950 if type(alist) in StringTypes:
1973 if type(alist) in StringTypes:
1951 alist = alist.split()
1974 alist = alist.split()
1952 for attr in alist:
1975 for attr in alist:
1953 val = eval(attr,nspace)
1976 val = eval(attr,nspace)
1954 setattr(obj,attr,val)
1977 setattr(obj,attr,val)
1955
1978
1956 #----------------------------------------------------------------------------
1979 #----------------------------------------------------------------------------
1957 def getattr_list(obj,alist,*args):
1980 def getattr_list(obj,alist,*args):
1958 """getattr_list(obj,alist[, default]) -> attribute list.
1981 """getattr_list(obj,alist[, default]) -> attribute list.
1959
1982
1960 Get a list of named attributes for an object. When a default argument is
1983 Get a list of named attributes for an object. When a default argument is
1961 given, it is returned when the attribute doesn't exist; without it, an
1984 given, it is returned when the attribute doesn't exist; without it, an
1962 exception is raised in that case.
1985 exception is raised in that case.
1963
1986
1964 Note that alist can be given as a string, which will be automatically
1987 Note that alist can be given as a string, which will be automatically
1965 split into a list on whitespace. If given as a list, it must be a list of
1988 split into a list on whitespace. If given as a list, it must be a list of
1966 *strings* (the variable names themselves), not of variables."""
1989 *strings* (the variable names themselves), not of variables."""
1967
1990
1968 if type(alist) in StringTypes:
1991 if type(alist) in StringTypes:
1969 alist = alist.split()
1992 alist = alist.split()
1970 if args:
1993 if args:
1971 if len(args)==1:
1994 if len(args)==1:
1972 default = args[0]
1995 default = args[0]
1973 return map(lambda attr: getattr(obj,attr,default),alist)
1996 return map(lambda attr: getattr(obj,attr,default),alist)
1974 else:
1997 else:
1975 raise ValueError,'getattr_list() takes only one optional argument'
1998 raise ValueError,'getattr_list() takes only one optional argument'
1976 else:
1999 else:
1977 return map(lambda attr: getattr(obj,attr),alist)
2000 return map(lambda attr: getattr(obj,attr),alist)
1978
2001
1979 #----------------------------------------------------------------------------
2002 #----------------------------------------------------------------------------
1980 def map_method(method,object_list,*argseq,**kw):
2003 def map_method(method,object_list,*argseq,**kw):
1981 """map_method(method,object_list,*args,**kw) -> list
2004 """map_method(method,object_list,*args,**kw) -> list
1982
2005
1983 Return a list of the results of applying the methods to the items of the
2006 Return a list of the results of applying the methods to the items of the
1984 argument sequence(s). If more than one sequence is given, the method is
2007 argument sequence(s). If more than one sequence is given, the method is
1985 called with an argument list consisting of the corresponding item of each
2008 called with an argument list consisting of the corresponding item of each
1986 sequence. All sequences must be of the same length.
2009 sequence. All sequences must be of the same length.
1987
2010
1988 Keyword arguments are passed verbatim to all objects called.
2011 Keyword arguments are passed verbatim to all objects called.
1989
2012
1990 This is Python code, so it's not nearly as fast as the builtin map()."""
2013 This is Python code, so it's not nearly as fast as the builtin map()."""
1991
2014
1992 out_list = []
2015 out_list = []
1993 idx = 0
2016 idx = 0
1994 for object in object_list:
2017 for object in object_list:
1995 try:
2018 try:
1996 handler = getattr(object, method)
2019 handler = getattr(object, method)
1997 except AttributeError:
2020 except AttributeError:
1998 out_list.append(None)
2021 out_list.append(None)
1999 else:
2022 else:
2000 if argseq:
2023 if argseq:
2001 args = map(lambda lst:lst[idx],argseq)
2024 args = map(lambda lst:lst[idx],argseq)
2002 #print 'ob',object,'hand',handler,'ar',args # dbg
2025 #print 'ob',object,'hand',handler,'ar',args # dbg
2003 out_list.append(handler(args,**kw))
2026 out_list.append(handler(args,**kw))
2004 else:
2027 else:
2005 out_list.append(handler(**kw))
2028 out_list.append(handler(**kw))
2006 idx += 1
2029 idx += 1
2007 return out_list
2030 return out_list
2008
2031
2009 #----------------------------------------------------------------------------
2032 #----------------------------------------------------------------------------
2010 def get_class_members(cls):
2033 def get_class_members(cls):
2011 ret = dir(cls)
2034 ret = dir(cls)
2012 if hasattr(cls,'__bases__'):
2035 if hasattr(cls,'__bases__'):
2013 for base in cls.__bases__:
2036 for base in cls.__bases__:
2014 ret.extend(get_class_members(base))
2037 ret.extend(get_class_members(base))
2015 return ret
2038 return ret
2016
2039
2017 #----------------------------------------------------------------------------
2040 #----------------------------------------------------------------------------
2018 def dir2(obj):
2041 def dir2(obj):
2019 """dir2(obj) -> list of strings
2042 """dir2(obj) -> list of strings
2020
2043
2021 Extended version of the Python builtin dir(), which does a few extra
2044 Extended version of the Python builtin dir(), which does a few extra
2022 checks, and supports common objects with unusual internals that confuse
2045 checks, and supports common objects with unusual internals that confuse
2023 dir(), such as Traits and PyCrust.
2046 dir(), such as Traits and PyCrust.
2024
2047
2025 This version is guaranteed to return only a list of true strings, whereas
2048 This version is guaranteed to return only a list of true strings, whereas
2026 dir() returns anything that objects inject into themselves, even if they
2049 dir() returns anything that objects inject into themselves, even if they
2027 are later not really valid for attribute access (many extension libraries
2050 are later not really valid for attribute access (many extension libraries
2028 have such bugs).
2051 have such bugs).
2029 """
2052 """
2030
2053
2031 # Start building the attribute list via dir(), and then complete it
2054 # Start building the attribute list via dir(), and then complete it
2032 # with a few extra special-purpose calls.
2055 # with a few extra special-purpose calls.
2033 words = dir(obj)
2056 words = dir(obj)
2034
2057
2035 if hasattr(obj,'__class__'):
2058 if hasattr(obj,'__class__'):
2036 words.append('__class__')
2059 words.append('__class__')
2037 words.extend(get_class_members(obj.__class__))
2060 words.extend(get_class_members(obj.__class__))
2038 #if '__base__' in words: 1/0
2061 #if '__base__' in words: 1/0
2039
2062
2040 # Some libraries (such as traits) may introduce duplicates, we want to
2063 # Some libraries (such as traits) may introduce duplicates, we want to
2041 # track and clean this up if it happens
2064 # track and clean this up if it happens
2042 may_have_dupes = False
2065 may_have_dupes = False
2043
2066
2044 # this is the 'dir' function for objects with Enthought's traits
2067 # this is the 'dir' function for objects with Enthought's traits
2045 if hasattr(obj, 'trait_names'):
2068 if hasattr(obj, 'trait_names'):
2046 try:
2069 try:
2047 words.extend(obj.trait_names())
2070 words.extend(obj.trait_names())
2048 may_have_dupes = True
2071 may_have_dupes = True
2049 except TypeError:
2072 except TypeError:
2050 # This will happen if `obj` is a class and not an instance.
2073 # This will happen if `obj` is a class and not an instance.
2051 pass
2074 pass
2052
2075
2053 # Support for PyCrust-style _getAttributeNames magic method.
2076 # Support for PyCrust-style _getAttributeNames magic method.
2054 if hasattr(obj, '_getAttributeNames'):
2077 if hasattr(obj, '_getAttributeNames'):
2055 try:
2078 try:
2056 words.extend(obj._getAttributeNames())
2079 words.extend(obj._getAttributeNames())
2057 may_have_dupes = True
2080 may_have_dupes = True
2058 except TypeError:
2081 except TypeError:
2059 # `obj` is a class and not an instance. Ignore
2082 # `obj` is a class and not an instance. Ignore
2060 # this error.
2083 # this error.
2061 pass
2084 pass
2062
2085
2063 if may_have_dupes:
2086 if may_have_dupes:
2064 # eliminate possible duplicates, as some traits may also
2087 # eliminate possible duplicates, as some traits may also
2065 # appear as normal attributes in the dir() call.
2088 # appear as normal attributes in the dir() call.
2066 words = list(set(words))
2089 words = list(set(words))
2067 words.sort()
2090 words.sort()
2068
2091
2069 # filter out non-string attributes which may be stuffed by dir() calls
2092 # filter out non-string attributes which may be stuffed by dir() calls
2070 # and poor coding in third-party modules
2093 # and poor coding in third-party modules
2071 return [w for w in words if isinstance(w, basestring)]
2094 return [w for w in words if isinstance(w, basestring)]
2072
2095
2073 #----------------------------------------------------------------------------
2096 #----------------------------------------------------------------------------
2074 def import_fail_info(mod_name,fns=None):
2097 def import_fail_info(mod_name,fns=None):
2075 """Inform load failure for a module."""
2098 """Inform load failure for a module."""
2076
2099
2077 if fns == None:
2100 if fns == None:
2078 warn("Loading of %s failed.\n" % (mod_name,))
2101 warn("Loading of %s failed.\n" % (mod_name,))
2079 else:
2102 else:
2080 warn("Loading of %s from %s failed.\n" % (fns,mod_name))
2103 warn("Loading of %s from %s failed.\n" % (fns,mod_name))
2081
2104
2082 #----------------------------------------------------------------------------
2105 #----------------------------------------------------------------------------
2083 # Proposed popitem() extension, written as a method
2106 # Proposed popitem() extension, written as a method
2084
2107
2085
2108
2086 class NotGiven: pass
2109 class NotGiven: pass
2087
2110
2088 def popkey(dct,key,default=NotGiven):
2111 def popkey(dct,key,default=NotGiven):
2089 """Return dct[key] and delete dct[key].
2112 """Return dct[key] and delete dct[key].
2090
2113
2091 If default is given, return it if dct[key] doesn't exist, otherwise raise
2114 If default is given, return it if dct[key] doesn't exist, otherwise raise
2092 KeyError. """
2115 KeyError. """
2093
2116
2094 try:
2117 try:
2095 val = dct[key]
2118 val = dct[key]
2096 except KeyError:
2119 except KeyError:
2097 if default is NotGiven:
2120 if default is NotGiven:
2098 raise
2121 raise
2099 else:
2122 else:
2100 return default
2123 return default
2101 else:
2124 else:
2102 del dct[key]
2125 del dct[key]
2103 return val
2126 return val
2104
2127
2105 def wrap_deprecated(func, suggest = '<nothing>'):
2128 def wrap_deprecated(func, suggest = '<nothing>'):
2106 def newFunc(*args, **kwargs):
2129 def newFunc(*args, **kwargs):
2107 warnings.warn("Call to deprecated function %s, use %s instead" %
2130 warnings.warn("Call to deprecated function %s, use %s instead" %
2108 ( func.__name__, suggest),
2131 ( func.__name__, suggest),
2109 category=DeprecationWarning,
2132 category=DeprecationWarning,
2110 stacklevel = 2)
2133 stacklevel = 2)
2111 return func(*args, **kwargs)
2134 return func(*args, **kwargs)
2112 return newFunc
2135 return newFunc
2113
2136
2114
2137
2115 def _num_cpus_unix():
2138 def _num_cpus_unix():
2116 """Return the number of active CPUs on a Unix system."""
2139 """Return the number of active CPUs on a Unix system."""
2117 return os.sysconf("SC_NPROCESSORS_ONLN")
2140 return os.sysconf("SC_NPROCESSORS_ONLN")
2118
2141
2119
2142
2120 def _num_cpus_darwin():
2143 def _num_cpus_darwin():
2121 """Return the number of active CPUs on a Darwin system."""
2144 """Return the number of active CPUs on a Darwin system."""
2122 p = subprocess.Popen(['sysctl','-n','hw.ncpu'],stdout=subprocess.PIPE)
2145 p = subprocess.Popen(['sysctl','-n','hw.ncpu'],stdout=subprocess.PIPE)
2123 return p.stdout.read()
2146 return p.stdout.read()
2124
2147
2125
2148
2126 def _num_cpus_windows():
2149 def _num_cpus_windows():
2127 """Return the number of active CPUs on a Windows system."""
2150 """Return the number of active CPUs on a Windows system."""
2128 return os.environ.get("NUMBER_OF_PROCESSORS")
2151 return os.environ.get("NUMBER_OF_PROCESSORS")
2129
2152
2130
2153
2131 def num_cpus():
2154 def num_cpus():
2132 """Return the effective number of CPUs in the system as an integer.
2155 """Return the effective number of CPUs in the system as an integer.
2133
2156
2134 This cross-platform function makes an attempt at finding the total number of
2157 This cross-platform function makes an attempt at finding the total number of
2135 available CPUs in the system, as returned by various underlying system and
2158 available CPUs in the system, as returned by various underlying system and
2136 python calls.
2159 python calls.
2137
2160
2138 If it can't find a sensible answer, it returns 1 (though an error *may* make
2161 If it can't find a sensible answer, it returns 1 (though an error *may* make
2139 it return a large positive number that's actually incorrect).
2162 it return a large positive number that's actually incorrect).
2140 """
2163 """
2141
2164
2142 # Many thanks to the Parallel Python project (http://www.parallelpython.com)
2165 # Many thanks to the Parallel Python project (http://www.parallelpython.com)
2143 # for the names of the keys we needed to look up for this function. This
2166 # for the names of the keys we needed to look up for this function. This
2144 # code was inspired by their equivalent function.
2167 # code was inspired by their equivalent function.
2145
2168
2146 ncpufuncs = {'Linux':_num_cpus_unix,
2169 ncpufuncs = {'Linux':_num_cpus_unix,
2147 'Darwin':_num_cpus_darwin,
2170 'Darwin':_num_cpus_darwin,
2148 'Windows':_num_cpus_windows,
2171 'Windows':_num_cpus_windows,
2149 # On Vista, python < 2.5.2 has a bug and returns 'Microsoft'
2172 # On Vista, python < 2.5.2 has a bug and returns 'Microsoft'
2150 # See http://bugs.python.org/issue1082 for details.
2173 # See http://bugs.python.org/issue1082 for details.
2151 'Microsoft':_num_cpus_windows,
2174 'Microsoft':_num_cpus_windows,
2152 }
2175 }
2153
2176
2154 ncpufunc = ncpufuncs.get(platform.system(),
2177 ncpufunc = ncpufuncs.get(platform.system(),
2155 # default to unix version (Solaris, AIX, etc)
2178 # default to unix version (Solaris, AIX, etc)
2156 _num_cpus_unix)
2179 _num_cpus_unix)
2157
2180
2158 try:
2181 try:
2159 ncpus = max(1,int(ncpufunc()))
2182 ncpus = max(1,int(ncpufunc()))
2160 except:
2183 except:
2161 ncpus = 1
2184 ncpus = 1
2162 return ncpus
2185 return ncpus
2163
2186
2164 def extract_vars(*names,**kw):
2187 def extract_vars(*names,**kw):
2165 """Extract a set of variables by name from another frame.
2188 """Extract a set of variables by name from another frame.
2166
2189
2167 :Parameters:
2190 :Parameters:
2168 - `*names`: strings
2191 - `*names`: strings
2169 One or more variable names which will be extracted from the caller's
2192 One or more variable names which will be extracted from the caller's
2170 frame.
2193 frame.
2171
2194
2172 :Keywords:
2195 :Keywords:
2173 - `depth`: integer (0)
2196 - `depth`: integer (0)
2174 How many frames in the stack to walk when looking for your variables.
2197 How many frames in the stack to walk when looking for your variables.
2175
2198
2176
2199
2177 Examples:
2200 Examples:
2178
2201
2179 In [2]: def func(x):
2202 In [2]: def func(x):
2180 ...: y = 1
2203 ...: y = 1
2181 ...: print extract_vars('x','y')
2204 ...: print extract_vars('x','y')
2182 ...:
2205 ...:
2183
2206
2184 In [3]: func('hello')
2207 In [3]: func('hello')
2185 {'y': 1, 'x': 'hello'}
2208 {'y': 1, 'x': 'hello'}
2186 """
2209 """
2187
2210
2188 depth = kw.get('depth',0)
2211 depth = kw.get('depth',0)
2189
2212
2190 callerNS = sys._getframe(depth+1).f_locals
2213 callerNS = sys._getframe(depth+1).f_locals
2191 return dict((k,callerNS[k]) for k in names)
2214 return dict((k,callerNS[k]) for k in names)
2192
2215
2193
2216
2194 def extract_vars_above(*names):
2217 def extract_vars_above(*names):
2195 """Extract a set of variables by name from another frame.
2218 """Extract a set of variables by name from another frame.
2196
2219
2197 Similar to extractVars(), but with a specified depth of 1, so that names
2220 Similar to extractVars(), but with a specified depth of 1, so that names
2198 are exctracted exactly from above the caller.
2221 are exctracted exactly from above the caller.
2199
2222
2200 This is simply a convenience function so that the very common case (for us)
2223 This is simply a convenience function so that the very common case (for us)
2201 of skipping exactly 1 frame doesn't have to construct a special dict for
2224 of skipping exactly 1 frame doesn't have to construct a special dict for
2202 keyword passing."""
2225 keyword passing."""
2203
2226
2204 callerNS = sys._getframe(2).f_locals
2227 callerNS = sys._getframe(2).f_locals
2205 return dict((k,callerNS[k]) for k in names)
2228 return dict((k,callerNS[k]) for k in names)
2206
2229
2207 def shexp(s):
2230 def shexp(s):
2208 """Expand $VARS and ~names in a string, like a shell
2231 """Expand $VARS and ~names in a string, like a shell
2209
2232
2210 :Examples:
2233 :Examples:
2211
2234
2212 In [2]: os.environ['FOO']='test'
2235 In [2]: os.environ['FOO']='test'
2213
2236
2214 In [3]: shexp('variable FOO is $FOO')
2237 In [3]: shexp('variable FOO is $FOO')
2215 Out[3]: 'variable FOO is test'
2238 Out[3]: 'variable FOO is test'
2216 """
2239 """
2217 return os.path.expandvars(os.path.expanduser(s))
2240 return os.path.expandvars(os.path.expanduser(s))
2218
2241
2219
2242
2220 def list_strings(arg):
2243 def list_strings(arg):
2221 """Always return a list of strings, given a string or list of strings
2244 """Always return a list of strings, given a string or list of strings
2222 as input.
2245 as input.
2223
2246
2224 :Examples:
2247 :Examples:
2225
2248
2226 In [7]: list_strings('A single string')
2249 In [7]: list_strings('A single string')
2227 Out[7]: ['A single string']
2250 Out[7]: ['A single string']
2228
2251
2229 In [8]: list_strings(['A single string in a list'])
2252 In [8]: list_strings(['A single string in a list'])
2230 Out[8]: ['A single string in a list']
2253 Out[8]: ['A single string in a list']
2231
2254
2232 In [9]: list_strings(['A','list','of','strings'])
2255 In [9]: list_strings(['A','list','of','strings'])
2233 Out[9]: ['A', 'list', 'of', 'strings']
2256 Out[9]: ['A', 'list', 'of', 'strings']
2234 """
2257 """
2235
2258
2236 if isinstance(arg,basestring): return [arg]
2259 if isinstance(arg,basestring): return [arg]
2237 else: return arg
2260 else: return arg
2238
2261
2239 def marquee(txt='',width=78,mark='*'):
2262 def marquee(txt='',width=78,mark='*'):
2240 """Return the input string centered in a 'marquee'.
2263 """Return the input string centered in a 'marquee'.
2241
2264
2242 :Examples:
2265 :Examples:
2243
2266
2244 In [16]: marquee('A test',40)
2267 In [16]: marquee('A test',40)
2245 Out[16]: '**************** A test ****************'
2268 Out[16]: '**************** A test ****************'
2246
2269
2247 In [17]: marquee('A test',40,'-')
2270 In [17]: marquee('A test',40,'-')
2248 Out[17]: '---------------- A test ----------------'
2271 Out[17]: '---------------- A test ----------------'
2249
2272
2250 In [18]: marquee('A test',40,' ')
2273 In [18]: marquee('A test',40,' ')
2251 Out[18]: ' A test '
2274 Out[18]: ' A test '
2252
2275
2253 """
2276 """
2254 if not txt:
2277 if not txt:
2255 return (mark*width)[:width]
2278 return (mark*width)[:width]
2256 nmark = (width-len(txt)-2)/len(mark)/2
2279 nmark = (width-len(txt)-2)/len(mark)/2
2257 if nmark < 0: nmark =0
2280 if nmark < 0: nmark =0
2258 marks = mark*nmark
2281 marks = mark*nmark
2259 return '%s %s %s' % (marks,txt,marks)
2282 return '%s %s %s' % (marks,txt,marks)
2260
2283
2261 #*************************** end of file <genutils.py> **********************
2284 #*************************** end of file <genutils.py> **********************
@@ -1,667 +1,670 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Tests for IPython.utils.traitlets.
4 Tests for IPython.utils.traitlets.
5
5
6 Authors:
6 Authors:
7
7
8 * Brian Granger
8 * Brian Granger
9 * Enthought, Inc. Some of the code in this file comes from enthought.traits
9 * Enthought, Inc. Some of the code in this file comes from enthought.traits
10 and is licensed under the BSD license. Also, many of the ideas also come
10 and is licensed under the BSD license. Also, many of the ideas also come
11 from enthought.traits even though our implementation is very different.
11 from enthought.traits even though our implementation is very different.
12 """
12 """
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Copyright (C) 2008-2009 The IPython Development Team
15 # Copyright (C) 2008-2009 The IPython Development Team
16 #
16 #
17 # Distributed under the terms of the BSD License. The full license is in
17 # Distributed under the terms of the BSD License. The full license is in
18 # the file COPYING, distributed as part of this software.
18 # the file COPYING, distributed as part of this software.
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Imports
22 # Imports
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 import sys
25 import sys
26 import os
26 import os
27
27
28
28
29 from unittest import TestCase
29 from unittest import TestCase
30
30
31 from IPython.utils.traitlets import (
31 from IPython.utils.traitlets import (
32 HasTraitlets, MetaHasTraitlets, TraitletType, Any,
32 HasTraitlets, MetaHasTraitlets, TraitletType, Any,
33 Int, Long, Float, Complex, Str, Unicode, Bool, TraitletError,
33 Int, Long, Float, Complex, Str, Unicode, Bool, TraitletError,
34 Undefined, Type, This, Instance
34 Undefined, Type, This, Instance
35 )
35 )
36
36
37
37
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39 # Helper classes for testing
39 # Helper classes for testing
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41
41
42
42
43 class HasTraitletsStub(HasTraitlets):
43 class HasTraitletsStub(HasTraitlets):
44
44
45 def _notify_traitlet(self, name, old, new):
45 def _notify_traitlet(self, name, old, new):
46 self._notify_name = name
46 self._notify_name = name
47 self._notify_old = old
47 self._notify_old = old
48 self._notify_new = new
48 self._notify_new = new
49
49
50
50
51 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
52 # Test classes
52 # Test classes
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54
54
55
55
56 class TestTraitletType(TestCase):
56 class TestTraitletType(TestCase):
57
57
58 def test_get_undefined(self):
58 def test_get_undefined(self):
59 class A(HasTraitlets):
59 class A(HasTraitlets):
60 a = TraitletType
60 a = TraitletType
61 a = A()
61 a = A()
62 self.assertEquals(a.a, Undefined)
62 self.assertEquals(a.a, Undefined)
63
63
64 def test_set(self):
64 def test_set(self):
65 class A(HasTraitletsStub):
65 class A(HasTraitletsStub):
66 a = TraitletType
66 a = TraitletType
67
67
68 a = A()
68 a = A()
69 a.a = 10
69 a.a = 10
70 self.assertEquals(a.a, 10)
70 self.assertEquals(a.a, 10)
71 self.assertEquals(a._notify_name, 'a')
71 self.assertEquals(a._notify_name, 'a')
72 self.assertEquals(a._notify_old, Undefined)
72 self.assertEquals(a._notify_old, Undefined)
73 self.assertEquals(a._notify_new, 10)
73 self.assertEquals(a._notify_new, 10)
74
74
75 def test_validate(self):
75 def test_validate(self):
76 class MyTT(TraitletType):
76 class MyTT(TraitletType):
77 def validate(self, inst, value):
77 def validate(self, inst, value):
78 return -1
78 return -1
79 class A(HasTraitletsStub):
79 class A(HasTraitletsStub):
80 tt = MyTT
80 tt = MyTT
81
81
82 a = A()
82 a = A()
83 a.tt = 10
83 a.tt = 10
84 self.assertEquals(a.tt, -1)
84 self.assertEquals(a.tt, -1)
85
85
86 def test_default_validate(self):
86 def test_default_validate(self):
87 class MyIntTT(TraitletType):
87 class MyIntTT(TraitletType):
88 def validate(self, obj, value):
88 def validate(self, obj, value):
89 if isinstance(value, int):
89 if isinstance(value, int):
90 return value
90 return value
91 self.error(obj, value)
91 self.error(obj, value)
92 class A(HasTraitlets):
92 class A(HasTraitlets):
93 tt = MyIntTT(10)
93 tt = MyIntTT(10)
94 a = A()
94 a = A()
95 self.assertEquals(a.tt, 10)
95 self.assertEquals(a.tt, 10)
96
96
97 # Defaults are validated when the HasTraitlets is instantiated
97 # Defaults are validated when the HasTraitlets is instantiated
98 class B(HasTraitlets):
98 class B(HasTraitlets):
99 tt = MyIntTT('bad default')
99 tt = MyIntTT('bad default')
100 self.assertRaises(TraitletError, B)
100 self.assertRaises(TraitletError, B)
101
101
102 def test_is_valid_for(self):
102 def test_is_valid_for(self):
103 class MyTT(TraitletType):
103 class MyTT(TraitletType):
104 def is_valid_for(self, value):
104 def is_valid_for(self, value):
105 return True
105 return True
106 class A(HasTraitlets):
106 class A(HasTraitlets):
107 tt = MyTT
107 tt = MyTT
108
108
109 a = A()
109 a = A()
110 a.tt = 10
110 a.tt = 10
111 self.assertEquals(a.tt, 10)
111 self.assertEquals(a.tt, 10)
112
112
113 def test_value_for(self):
113 def test_value_for(self):
114 class MyTT(TraitletType):
114 class MyTT(TraitletType):
115 def value_for(self, value):
115 def value_for(self, value):
116 return 20
116 return 20
117 class A(HasTraitlets):
117 class A(HasTraitlets):
118 tt = MyTT
118 tt = MyTT
119
119
120 a = A()
120 a = A()
121 a.tt = 10
121 a.tt = 10
122 self.assertEquals(a.tt, 20)
122 self.assertEquals(a.tt, 20)
123
123
124 def test_info(self):
124 def test_info(self):
125 class A(HasTraitlets):
125 class A(HasTraitlets):
126 tt = TraitletType
126 tt = TraitletType
127 a = A()
127 a = A()
128 self.assertEquals(A.tt.info(), 'any value')
128 self.assertEquals(A.tt.info(), 'any value')
129
129
130 def test_error(self):
130 def test_error(self):
131 class A(HasTraitlets):
131 class A(HasTraitlets):
132 tt = TraitletType
132 tt = TraitletType
133 a = A()
133 a = A()
134 self.assertRaises(TraitletError, A.tt.error, a, 10)
134 self.assertRaises(TraitletError, A.tt.error, a, 10)
135
135
136
136
137 class TestHasTraitletsMeta(TestCase):
137 class TestHasTraitletsMeta(TestCase):
138
138
139 def test_metaclass(self):
139 def test_metaclass(self):
140 self.assertEquals(type(HasTraitlets), MetaHasTraitlets)
140 self.assertEquals(type(HasTraitlets), MetaHasTraitlets)
141
141
142 class A(HasTraitlets):
142 class A(HasTraitlets):
143 a = Int
143 a = Int
144
144
145 a = A()
145 a = A()
146 self.assertEquals(type(a.__class__), MetaHasTraitlets)
146 self.assertEquals(type(a.__class__), MetaHasTraitlets)
147 self.assertEquals(a.a,0)
147 self.assertEquals(a.a,0)
148 a.a = 10
148 a.a = 10
149 self.assertEquals(a.a,10)
149 self.assertEquals(a.a,10)
150
150
151 class B(HasTraitlets):
151 class B(HasTraitlets):
152 b = Int()
152 b = Int()
153
153
154 b = B()
154 b = B()
155 self.assertEquals(b.b,0)
155 self.assertEquals(b.b,0)
156 b.b = 10
156 b.b = 10
157 self.assertEquals(b.b,10)
157 self.assertEquals(b.b,10)
158
158
159 class C(HasTraitlets):
159 class C(HasTraitlets):
160 c = Int(30)
160 c = Int(30)
161
161
162 c = C()
162 c = C()
163 self.assertEquals(c.c,30)
163 self.assertEquals(c.c,30)
164 c.c = 10
164 c.c = 10
165 self.assertEquals(c.c,10)
165 self.assertEquals(c.c,10)
166
166
167 def test_this_class(self):
167 def test_this_class(self):
168 class A(HasTraitlets):
168 class A(HasTraitlets):
169 t = This()
169 t = This()
170 tt = This()
170 tt = This()
171 class B(A):
171 class B(A):
172 tt = This()
172 tt = This()
173 ttt = This()
173 ttt = This()
174 self.assertEquals(A.t.this_class, A)
174 self.assertEquals(A.t.this_class, A)
175 self.assertEquals(B.t.this_class, A)
175 self.assertEquals(B.t.this_class, A)
176 self.assertEquals(B.tt.this_class, B)
176 self.assertEquals(B.tt.this_class, B)
177 self.assertEquals(B.ttt.this_class, B)
177 self.assertEquals(B.ttt.this_class, B)
178
178
179 class TestHasTraitletsNotify(TestCase):
179 class TestHasTraitletsNotify(TestCase):
180
180
181 def setUp(self):
181 def setUp(self):
182 self._notify1 = []
182 self._notify1 = []
183 self._notify2 = []
183 self._notify2 = []
184
184
185 def notify1(self, name, old, new):
185 def notify1(self, name, old, new):
186 self._notify1.append((name, old, new))
186 self._notify1.append((name, old, new))
187
187
188 def notify2(self, name, old, new):
188 def notify2(self, name, old, new):
189 self._notify2.append((name, old, new))
189 self._notify2.append((name, old, new))
190
190
191 def test_notify_all(self):
191 def test_notify_all(self):
192
192
193 class A(HasTraitlets):
193 class A(HasTraitlets):
194 a = Int
194 a = Int
195 b = Float
195 b = Float
196
196
197 a = A()
197 a = A()
198 a.on_traitlet_change(self.notify1)
198 a.on_traitlet_change(self.notify1)
199 a.a = 0
199 a.a = 0
200 self.assertEquals(len(self._notify1),0)
200 self.assertEquals(len(self._notify1),0)
201 a.b = 0.0
201 a.b = 0.0
202 self.assertEquals(len(self._notify1),0)
202 self.assertEquals(len(self._notify1),0)
203 a.a = 10
203 a.a = 10
204 self.assert_(('a',0,10) in self._notify1)
204 self.assert_(('a',0,10) in self._notify1)
205 a.b = 10.0
205 a.b = 10.0
206 self.assert_(('b',0.0,10.0) in self._notify1)
206 self.assert_(('b',0.0,10.0) in self._notify1)
207 self.assertRaises(TraitletError,setattr,a,'a','bad string')
207 self.assertRaises(TraitletError,setattr,a,'a','bad string')
208 self.assertRaises(TraitletError,setattr,a,'b','bad string')
208 self.assertRaises(TraitletError,setattr,a,'b','bad string')
209 self._notify1 = []
209 self._notify1 = []
210 a.on_traitlet_change(self.notify1,remove=True)
210 a.on_traitlet_change(self.notify1,remove=True)
211 a.a = 20
211 a.a = 20
212 a.b = 20.0
212 a.b = 20.0
213 self.assertEquals(len(self._notify1),0)
213 self.assertEquals(len(self._notify1),0)
214
214
215 def test_notify_one(self):
215 def test_notify_one(self):
216
216
217 class A(HasTraitlets):
217 class A(HasTraitlets):
218 a = Int
218 a = Int
219 b = Float
219 b = Float
220
220
221 a = A()
221 a = A()
222 a.on_traitlet_change(self.notify1, 'a')
222 a.on_traitlet_change(self.notify1, 'a')
223 a.a = 0
223 a.a = 0
224 self.assertEquals(len(self._notify1),0)
224 self.assertEquals(len(self._notify1),0)
225 a.a = 10
225 a.a = 10
226 self.assert_(('a',0,10) in self._notify1)
226 self.assert_(('a',0,10) in self._notify1)
227 self.assertRaises(TraitletError,setattr,a,'a','bad string')
227 self.assertRaises(TraitletError,setattr,a,'a','bad string')
228
228
229 def test_subclass(self):
229 def test_subclass(self):
230
230
231 class A(HasTraitlets):
231 class A(HasTraitlets):
232 a = Int
232 a = Int
233
233
234 class B(A):
234 class B(A):
235 b = Float
235 b = Float
236
236
237 b = B()
237 b = B()
238 self.assertEquals(b.a,0)
238 self.assertEquals(b.a,0)
239 self.assertEquals(b.b,0.0)
239 self.assertEquals(b.b,0.0)
240 b.a = 100
240 b.a = 100
241 b.b = 100.0
241 b.b = 100.0
242 self.assertEquals(b.a,100)
242 self.assertEquals(b.a,100)
243 self.assertEquals(b.b,100.0)
243 self.assertEquals(b.b,100.0)
244
244
245 def test_notify_subclass(self):
245 def test_notify_subclass(self):
246
246
247 class A(HasTraitlets):
247 class A(HasTraitlets):
248 a = Int
248 a = Int
249
249
250 class B(A):
250 class B(A):
251 b = Float
251 b = Float
252
252
253 b = B()
253 b = B()
254 b.on_traitlet_change(self.notify1, 'a')
254 b.on_traitlet_change(self.notify1, 'a')
255 b.on_traitlet_change(self.notify2, 'b')
255 b.on_traitlet_change(self.notify2, 'b')
256 b.a = 0
256 b.a = 0
257 b.b = 0.0
257 b.b = 0.0
258 self.assertEquals(len(self._notify1),0)
258 self.assertEquals(len(self._notify1),0)
259 self.assertEquals(len(self._notify2),0)
259 self.assertEquals(len(self._notify2),0)
260 b.a = 10
260 b.a = 10
261 b.b = 10.0
261 b.b = 10.0
262 self.assert_(('a',0,10) in self._notify1)
262 self.assert_(('a',0,10) in self._notify1)
263 self.assert_(('b',0.0,10.0) in self._notify2)
263 self.assert_(('b',0.0,10.0) in self._notify2)
264
264
265 def test_static_notify(self):
265 def test_static_notify(self):
266
266
267 class A(HasTraitlets):
267 class A(HasTraitlets):
268 a = Int
268 a = Int
269 _notify1 = []
269 _notify1 = []
270 def _a_changed(self, name, old, new):
270 def _a_changed(self, name, old, new):
271 self._notify1.append((name, old, new))
271 self._notify1.append((name, old, new))
272
272
273 a = A()
273 a = A()
274 a.a = 0
274 a.a = 0
275 # This is broken!!!
275 # This is broken!!!
276 self.assertEquals(len(a._notify1),0)
276 self.assertEquals(len(a._notify1),0)
277 a.a = 10
277 a.a = 10
278 self.assert_(('a',0,10) in a._notify1)
278 self.assert_(('a',0,10) in a._notify1)
279
279
280 class B(A):
280 class B(A):
281 b = Float
281 b = Float
282 _notify2 = []
282 _notify2 = []
283 def _b_changed(self, name, old, new):
283 def _b_changed(self, name, old, new):
284 self._notify2.append((name, old, new))
284 self._notify2.append((name, old, new))
285
285
286 b = B()
286 b = B()
287 b.a = 10
287 b.a = 10
288 b.b = 10.0
288 b.b = 10.0
289 self.assert_(('a',0,10) in b._notify1)
289 self.assert_(('a',0,10) in b._notify1)
290 self.assert_(('b',0.0,10.0) in b._notify2)
290 self.assert_(('b',0.0,10.0) in b._notify2)
291
291
292 def test_notify_args(self):
292 def test_notify_args(self):
293
293
294 def callback0():
294 def callback0():
295 self.cb = ()
295 self.cb = ()
296 def callback1(name):
296 def callback1(name):
297 self.cb = (name,)
297 self.cb = (name,)
298 def callback2(name, new):
298 def callback2(name, new):
299 self.cb = (name, new)
299 self.cb = (name, new)
300 def callback3(name, old, new):
300 def callback3(name, old, new):
301 self.cb = (name, old, new)
301 self.cb = (name, old, new)
302
302
303 class A(HasTraitlets):
303 class A(HasTraitlets):
304 a = Int
304 a = Int
305
305
306 a = A()
306 a = A()
307 a.on_traitlet_change(callback0, 'a')
307 a.on_traitlet_change(callback0, 'a')
308 a.a = 10
308 a.a = 10
309 self.assertEquals(self.cb,())
309 self.assertEquals(self.cb,())
310 a.on_traitlet_change(callback0, 'a', remove=True)
310 a.on_traitlet_change(callback0, 'a', remove=True)
311
311
312 a.on_traitlet_change(callback1, 'a')
312 a.on_traitlet_change(callback1, 'a')
313 a.a = 100
313 a.a = 100
314 self.assertEquals(self.cb,('a',))
314 self.assertEquals(self.cb,('a',))
315 a.on_traitlet_change(callback1, 'a', remove=True)
315 a.on_traitlet_change(callback1, 'a', remove=True)
316
316
317 a.on_traitlet_change(callback2, 'a')
317 a.on_traitlet_change(callback2, 'a')
318 a.a = 1000
318 a.a = 1000
319 self.assertEquals(self.cb,('a',1000))
319 self.assertEquals(self.cb,('a',1000))
320 a.on_traitlet_change(callback2, 'a', remove=True)
320 a.on_traitlet_change(callback2, 'a', remove=True)
321
321
322 a.on_traitlet_change(callback3, 'a')
322 a.on_traitlet_change(callback3, 'a')
323 a.a = 10000
323 a.a = 10000
324 self.assertEquals(self.cb,('a',1000,10000))
324 self.assertEquals(self.cb,('a',1000,10000))
325 a.on_traitlet_change(callback3, 'a', remove=True)
325 a.on_traitlet_change(callback3, 'a', remove=True)
326
326
327 self.assertEquals(len(a._traitlet_notifiers['a']),0)
327 self.assertEquals(len(a._traitlet_notifiers['a']),0)
328
328
329
329
330 class TestHasTraitlets(TestCase):
330 class TestHasTraitlets(TestCase):
331
331
332 def test_traitlet_names(self):
332 def test_traitlet_names(self):
333 class A(HasTraitlets):
333 class A(HasTraitlets):
334 i = Int
334 i = Int
335 f = Float
335 f = Float
336 a = A()
336 a = A()
337 self.assertEquals(a.traitlet_names(),['i','f'])
337 self.assertEquals(a.traitlet_names(),['i','f'])
338
338
339 def test_traitlet_metadata(self):
339 def test_traitlet_metadata(self):
340 class A(HasTraitlets):
340 class A(HasTraitlets):
341 i = Int(config_key='MY_VALUE')
341 i = Int(config_key='MY_VALUE')
342 a = A()
342 a = A()
343 self.assertEquals(a.traitlet_metadata('i','config_key'), 'MY_VALUE')
343 self.assertEquals(a.traitlet_metadata('i','config_key'), 'MY_VALUE')
344
344
345 def test_traitlets(self):
345 def test_traitlets(self):
346 class A(HasTraitlets):
346 class A(HasTraitlets):
347 i = Int
347 i = Int
348 f = Float
348 f = Float
349 a = A()
349 a = A()
350 self.assertEquals(a.traitlets(), dict(i=A.i, f=A.f))
350 self.assertEquals(a.traitlets(), dict(i=A.i, f=A.f))
351
351
352 def test_traitlets_metadata(self):
352 def test_traitlets_metadata(self):
353 class A(HasTraitlets):
353 class A(HasTraitlets):
354 i = Int(config_key='VALUE1', other_thing='VALUE2')
354 i = Int(config_key='VALUE1', other_thing='VALUE2')
355 f = Float(config_key='VALUE3', other_thing='VALUE2')
355 f = Float(config_key='VALUE3', other_thing='VALUE2')
356 a = A()
356 a = A()
357 # traitlets = a.traitlets(config_key=lambda v: True)
357 self.assertEquals(a.traitlets(), dict(i=A.i, f=A.f))
358 # self.assertEquals(traitlets, dict(i=A.i, f=A.f))
358 traitlets = a.traitlets(config_key=lambda v: True)
359 self.assertEquals(traitlets, dict(i=A.i, f=A.f))
359 traitlets = a.traitlets(config_key='VALUE1', other_thing='VALUE2')
360 traitlets = a.traitlets(config_key='VALUE1', other_thing='VALUE2')
360 self.assertEquals(traitlets, dict(i=A.i))
361 self.assertEquals(traitlets, dict(i=A.i))
362 traitlets = a.traitlets('config_key')
363 self.assertEquals(traitlets, dict(i=A.i, f=A.f))
361
364
362 #-----------------------------------------------------------------------------
365 #-----------------------------------------------------------------------------
363 # Tests for specific traitlet types
366 # Tests for specific traitlet types
364 #-----------------------------------------------------------------------------
367 #-----------------------------------------------------------------------------
365
368
366
369
367 class TestType(TestCase):
370 class TestType(TestCase):
368
371
369 def test_default(self):
372 def test_default(self):
370
373
371 class B(object): pass
374 class B(object): pass
372 class A(HasTraitlets):
375 class A(HasTraitlets):
373 klass = Type
376 klass = Type
374
377
375 a = A()
378 a = A()
376 self.assertEquals(a.klass, None)
379 self.assertEquals(a.klass, None)
377 a.klass = B
380 a.klass = B
378 self.assertEquals(a.klass, B)
381 self.assertEquals(a.klass, B)
379 self.assertRaises(TraitletError, setattr, a, 'klass', 10)
382 self.assertRaises(TraitletError, setattr, a, 'klass', 10)
380
383
381 def test_value(self):
384 def test_value(self):
382
385
383 class B(object): pass
386 class B(object): pass
384 class C(object): pass
387 class C(object): pass
385 class A(HasTraitlets):
388 class A(HasTraitlets):
386 klass = Type(B)
389 klass = Type(B)
387
390
388 a = A()
391 a = A()
389 self.assertEquals(a.klass, B)
392 self.assertEquals(a.klass, B)
390 self.assertRaises(TraitletError, setattr, a, 'klass', C)
393 self.assertRaises(TraitletError, setattr, a, 'klass', C)
391 self.assertRaises(TraitletError, setattr, a, 'klass', object)
394 self.assertRaises(TraitletError, setattr, a, 'klass', object)
392 a.klass = B
395 a.klass = B
393
396
394 def test_allow_none(self):
397 def test_allow_none(self):
395
398
396 class B(object): pass
399 class B(object): pass
397 class C(B): pass
400 class C(B): pass
398 class A(HasTraitlets):
401 class A(HasTraitlets):
399 klass = Type(B, allow_none=False)
402 klass = Type(B, allow_none=False)
400
403
401 a = A()
404 a = A()
402 self.assertEquals(a.klass, B)
405 self.assertEquals(a.klass, B)
403 self.assertRaises(TraitletError, setattr, a, 'klass', None)
406 self.assertRaises(TraitletError, setattr, a, 'klass', None)
404 a.klass = C
407 a.klass = C
405 self.assertEquals(a.klass, C)
408 self.assertEquals(a.klass, C)
406
409
407 def test_validate_klass(self):
410 def test_validate_klass(self):
408
411
409 def inner():
412 def inner():
410 class A(HasTraitlets):
413 class A(HasTraitlets):
411 klass = Type('no strings allowed')
414 klass = Type('no strings allowed')
412
415
413 self.assertRaises(TraitletError, inner)
416 self.assertRaises(TraitletError, inner)
414
417
415 def test_validate_default(self):
418 def test_validate_default(self):
416
419
417 class B(object): pass
420 class B(object): pass
418 class A(HasTraitlets):
421 class A(HasTraitlets):
419 klass = Type('bad default', B)
422 klass = Type('bad default', B)
420
423
421 self.assertRaises(TraitletError, A)
424 self.assertRaises(TraitletError, A)
422
425
423 class C(HasTraitlets):
426 class C(HasTraitlets):
424 klass = Type(None, B, allow_none=False)
427 klass = Type(None, B, allow_none=False)
425
428
426 self.assertRaises(TraitletError, C)
429 self.assertRaises(TraitletError, C)
427
430
428 class TestInstance(TestCase):
431 class TestInstance(TestCase):
429
432
430 def test_basic(self):
433 def test_basic(self):
431 class Foo(object): pass
434 class Foo(object): pass
432 class Bar(Foo): pass
435 class Bar(Foo): pass
433 class Bah(object): pass
436 class Bah(object): pass
434
437
435 class A(HasTraitlets):
438 class A(HasTraitlets):
436 inst = Instance(Foo)
439 inst = Instance(Foo)
437
440
438 a = A()
441 a = A()
439 self.assert_(a.inst is None)
442 self.assert_(a.inst is None)
440 a.inst = Foo()
443 a.inst = Foo()
441 self.assert_(isinstance(a.inst, Foo))
444 self.assert_(isinstance(a.inst, Foo))
442 a.inst = Bar()
445 a.inst = Bar()
443 self.assert_(isinstance(a.inst, Foo))
446 self.assert_(isinstance(a.inst, Foo))
444 self.assertRaises(TraitletError, setattr, a, 'inst', Foo)
447 self.assertRaises(TraitletError, setattr, a, 'inst', Foo)
445 self.assertRaises(TraitletError, setattr, a, 'inst', Bar)
448 self.assertRaises(TraitletError, setattr, a, 'inst', Bar)
446 self.assertRaises(TraitletError, setattr, a, 'inst', Bah())
449 self.assertRaises(TraitletError, setattr, a, 'inst', Bah())
447
450
448 def test_unique_default_value(self):
451 def test_unique_default_value(self):
449 class Foo(object): pass
452 class Foo(object): pass
450 class A(HasTraitlets):
453 class A(HasTraitlets):
451 inst = Instance(Foo,(),{})
454 inst = Instance(Foo,(),{})
452
455
453 a = A()
456 a = A()
454 b = A()
457 b = A()
455 self.assert_(a.inst is not b.inst)
458 self.assert_(a.inst is not b.inst)
456
459
457 def test_args_kw(self):
460 def test_args_kw(self):
458 class Foo(object):
461 class Foo(object):
459 def __init__(self, c): self.c = c
462 def __init__(self, c): self.c = c
460 class Bar(object): pass
463 class Bar(object): pass
461 class Bah(object):
464 class Bah(object):
462 def __init__(self, c, d):
465 def __init__(self, c, d):
463 self.c = c; self.d = d
466 self.c = c; self.d = d
464
467
465 class A(HasTraitlets):
468 class A(HasTraitlets):
466 inst = Instance(Foo, (10,))
469 inst = Instance(Foo, (10,))
467 a = A()
470 a = A()
468 self.assertEquals(a.inst.c, 10)
471 self.assertEquals(a.inst.c, 10)
469
472
470 class B(HasTraitlets):
473 class B(HasTraitlets):
471 inst = Instance(Bah, args=(10,), kw=dict(d=20))
474 inst = Instance(Bah, args=(10,), kw=dict(d=20))
472 b = B()
475 b = B()
473 self.assertEquals(b.inst.c, 10)
476 self.assertEquals(b.inst.c, 10)
474 self.assertEquals(b.inst.d, 20)
477 self.assertEquals(b.inst.d, 20)
475
478
476 class C(HasTraitlets):
479 class C(HasTraitlets):
477 inst = Instance(Foo)
480 inst = Instance(Foo)
478 c = C()
481 c = C()
479 self.assert_(c.inst is None)
482 self.assert_(c.inst is None)
480
483
481 def test_bad_default(self):
484 def test_bad_default(self):
482 class Foo(object): pass
485 class Foo(object): pass
483
486
484 class A(HasTraitlets):
487 class A(HasTraitlets):
485 inst = Instance(Foo, allow_none=False)
488 inst = Instance(Foo, allow_none=False)
486
489
487 self.assertRaises(TraitletError, A)
490 self.assertRaises(TraitletError, A)
488
491
489 def test_instance(self):
492 def test_instance(self):
490 class Foo(object): pass
493 class Foo(object): pass
491
494
492 def inner():
495 def inner():
493 class A(HasTraitlets):
496 class A(HasTraitlets):
494 inst = Instance(Foo())
497 inst = Instance(Foo())
495
498
496 self.assertRaises(TraitletError, inner)
499 self.assertRaises(TraitletError, inner)
497
500
498
501
499 class TestThis(TestCase):
502 class TestThis(TestCase):
500
503
501 def test_this_class(self):
504 def test_this_class(self):
502 class Foo(HasTraitlets):
505 class Foo(HasTraitlets):
503 this = This
506 this = This
504
507
505 f = Foo()
508 f = Foo()
506 self.assertEquals(f.this, None)
509 self.assertEquals(f.this, None)
507 g = Foo()
510 g = Foo()
508 f.this = g
511 f.this = g
509 self.assertEquals(f.this, g)
512 self.assertEquals(f.this, g)
510 self.assertRaises(TraitletError, setattr, f, 'this', 10)
513 self.assertRaises(TraitletError, setattr, f, 'this', 10)
511
514
512 def test_this_inst(self):
515 def test_this_inst(self):
513 class Foo(HasTraitlets):
516 class Foo(HasTraitlets):
514 this = This()
517 this = This()
515
518
516 f = Foo()
519 f = Foo()
517 f.this = Foo()
520 f.this = Foo()
518 self.assert_(isinstance(f.this, Foo))
521 self.assert_(isinstance(f.this, Foo))
519
522
520 def test_subclass(self):
523 def test_subclass(self):
521 class Foo(HasTraitlets):
524 class Foo(HasTraitlets):
522 t = This()
525 t = This()
523 class Bar(Foo):
526 class Bar(Foo):
524 pass
527 pass
525 f = Foo()
528 f = Foo()
526 b = Bar()
529 b = Bar()
527 f.t = b
530 f.t = b
528 b.t = f
531 b.t = f
529 self.assertEquals(f.t, b)
532 self.assertEquals(f.t, b)
530 self.assertEquals(b.t, f)
533 self.assertEquals(b.t, f)
531
534
532 def test_subclass_override(self):
535 def test_subclass_override(self):
533 class Foo(HasTraitlets):
536 class Foo(HasTraitlets):
534 t = This()
537 t = This()
535 class Bar(Foo):
538 class Bar(Foo):
536 t = This()
539 t = This()
537 f = Foo()
540 f = Foo()
538 b = Bar()
541 b = Bar()
539 f.t = b
542 f.t = b
540 self.assertEquals(f.t, b)
543 self.assertEquals(f.t, b)
541 self.assertRaises(TraitletError, setattr, b, 't', f)
544 self.assertRaises(TraitletError, setattr, b, 't', f)
542
545
543 class TraitletTestBase(TestCase):
546 class TraitletTestBase(TestCase):
544 """A best testing class for basic traitlet types."""
547 """A best testing class for basic traitlet types."""
545
548
546 def assign(self, value):
549 def assign(self, value):
547 self.obj.value = value
550 self.obj.value = value
548
551
549 def coerce(self, value):
552 def coerce(self, value):
550 return value
553 return value
551
554
552 def test_good_values(self):
555 def test_good_values(self):
553 if hasattr(self, '_good_values'):
556 if hasattr(self, '_good_values'):
554 for value in self._good_values:
557 for value in self._good_values:
555 self.assign(value)
558 self.assign(value)
556 self.assertEquals(self.obj.value, self.coerce(value))
559 self.assertEquals(self.obj.value, self.coerce(value))
557
560
558 def test_bad_values(self):
561 def test_bad_values(self):
559 if hasattr(self, '_bad_values'):
562 if hasattr(self, '_bad_values'):
560 for value in self._bad_values:
563 for value in self._bad_values:
561 self.assertRaises(TraitletError, self.assign, value)
564 self.assertRaises(TraitletError, self.assign, value)
562
565
563 def test_default_value(self):
566 def test_default_value(self):
564 if hasattr(self, '_default_value'):
567 if hasattr(self, '_default_value'):
565 self.assertEquals(self._default_value, self.obj.value)
568 self.assertEquals(self._default_value, self.obj.value)
566
569
567
570
568 class AnyTraitlet(HasTraitlets):
571 class AnyTraitlet(HasTraitlets):
569
572
570 value = Any
573 value = Any
571
574
572 class AnyTraitTest(TraitletTestBase):
575 class AnyTraitTest(TraitletTestBase):
573
576
574 obj = AnyTraitlet()
577 obj = AnyTraitlet()
575
578
576 _default_value = None
579 _default_value = None
577 _good_values = [10.0, 'ten', u'ten', [10], {'ten': 10},(10,), None, 1j]
580 _good_values = [10.0, 'ten', u'ten', [10], {'ten': 10},(10,), None, 1j]
578 _bad_values = []
581 _bad_values = []
579
582
580
583
581 class IntTraitlet(HasTraitlets):
584 class IntTraitlet(HasTraitlets):
582
585
583 value = Int(99)
586 value = Int(99)
584
587
585 class TestInt(TraitletTestBase):
588 class TestInt(TraitletTestBase):
586
589
587 obj = IntTraitlet()
590 obj = IntTraitlet()
588 _default_value = 99
591 _default_value = 99
589 _good_values = [10, -10]
592 _good_values = [10, -10]
590 _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,), None, 1j, 10L,
593 _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,), None, 1j, 10L,
591 -10L, 10.1, -10.1, '10L', '-10L', '10.1', '-10.1', u'10L',
594 -10L, 10.1, -10.1, '10L', '-10L', '10.1', '-10.1', u'10L',
592 u'-10L', u'10.1', u'-10.1', '10', '-10', u'10', u'-10']
595 u'-10L', u'10.1', u'-10.1', '10', '-10', u'10', u'-10']
593
596
594
597
595 class LongTraitlet(HasTraitlets):
598 class LongTraitlet(HasTraitlets):
596
599
597 value = Long(99L)
600 value = Long(99L)
598
601
599 class TestLong(TraitletTestBase):
602 class TestLong(TraitletTestBase):
600
603
601 obj = LongTraitlet()
604 obj = LongTraitlet()
602
605
603 _default_value = 99L
606 _default_value = 99L
604 _good_values = [10, -10, 10L, -10L]
607 _good_values = [10, -10, 10L, -10L]
605 _bad_values = ['ten', u'ten', [10], [10l], {'ten': 10},(10,),(10L,),
608 _bad_values = ['ten', u'ten', [10], [10l], {'ten': 10},(10,),(10L,),
606 None, 1j, 10.1, -10.1, '10', '-10', '10L', '-10L', '10.1',
609 None, 1j, 10.1, -10.1, '10', '-10', '10L', '-10L', '10.1',
607 '-10.1', u'10', u'-10', u'10L', u'-10L', u'10.1',
610 '-10.1', u'10', u'-10', u'10L', u'-10L', u'10.1',
608 u'-10.1']
611 u'-10.1']
609
612
610
613
611 class FloatTraitlet(HasTraitlets):
614 class FloatTraitlet(HasTraitlets):
612
615
613 value = Float(99.0)
616 value = Float(99.0)
614
617
615 class TestFloat(TraitletTestBase):
618 class TestFloat(TraitletTestBase):
616
619
617 obj = FloatTraitlet()
620 obj = FloatTraitlet()
618
621
619 _default_value = 99.0
622 _default_value = 99.0
620 _good_values = [10, -10, 10.1, -10.1]
623 _good_values = [10, -10, 10.1, -10.1]
621 _bad_values = [10L, -10L, 'ten', u'ten', [10], {'ten': 10},(10,), None,
624 _bad_values = [10L, -10L, 'ten', u'ten', [10], {'ten': 10},(10,), None,
622 1j, '10', '-10', '10L', '-10L', '10.1', '-10.1', u'10',
625 1j, '10', '-10', '10L', '-10L', '10.1', '-10.1', u'10',
623 u'-10', u'10L', u'-10L', u'10.1', u'-10.1']
626 u'-10', u'10L', u'-10L', u'10.1', u'-10.1']
624
627
625
628
626 class ComplexTraitlet(HasTraitlets):
629 class ComplexTraitlet(HasTraitlets):
627
630
628 value = Complex(99.0-99.0j)
631 value = Complex(99.0-99.0j)
629
632
630 class TestComplex(TraitletTestBase):
633 class TestComplex(TraitletTestBase):
631
634
632 obj = ComplexTraitlet()
635 obj = ComplexTraitlet()
633
636
634 _default_value = 99.0-99.0j
637 _default_value = 99.0-99.0j
635 _good_values = [10, -10, 10.1, -10.1, 10j, 10+10j, 10-10j,
638 _good_values = [10, -10, 10.1, -10.1, 10j, 10+10j, 10-10j,
636 10.1j, 10.1+10.1j, 10.1-10.1j]
639 10.1j, 10.1+10.1j, 10.1-10.1j]
637 _bad_values = [10L, -10L, u'10L', u'-10L', 'ten', [10], {'ten': 10},(10,), None]
640 _bad_values = [10L, -10L, u'10L', u'-10L', 'ten', [10], {'ten': 10},(10,), None]
638
641
639
642
640 class StringTraitlet(HasTraitlets):
643 class StringTraitlet(HasTraitlets):
641
644
642 value = Str('string')
645 value = Str('string')
643
646
644 class TestString(TraitletTestBase):
647 class TestString(TraitletTestBase):
645
648
646 obj = StringTraitlet()
649 obj = StringTraitlet()
647
650
648 _default_value = 'string'
651 _default_value = 'string'
649 _good_values = ['10', '-10', '10L',
652 _good_values = ['10', '-10', '10L',
650 '-10L', '10.1', '-10.1', 'string']
653 '-10L', '10.1', '-10.1', 'string']
651 _bad_values = [10, -10, 10L, -10L, 10.1, -10.1, 1j, [10],
654 _bad_values = [10, -10, 10L, -10L, 10.1, -10.1, 1j, [10],
652 ['ten'],{'ten': 10},(10,), None, u'string']
655 ['ten'],{'ten': 10},(10,), None, u'string']
653
656
654
657
655 class UnicodeTraitlet(HasTraitlets):
658 class UnicodeTraitlet(HasTraitlets):
656
659
657 value = Unicode(u'unicode')
660 value = Unicode(u'unicode')
658
661
659 class TestUnicode(TraitletTestBase):
662 class TestUnicode(TraitletTestBase):
660
663
661 obj = UnicodeTraitlet()
664 obj = UnicodeTraitlet()
662
665
663 _default_value = u'unicode'
666 _default_value = u'unicode'
664 _good_values = ['10', '-10', '10L', '-10L', '10.1',
667 _good_values = ['10', '-10', '10L', '-10L', '10.1',
665 '-10.1', '', u'', 'string', u'string', ]
668 '-10.1', '', u'', 'string', u'string', ]
666 _bad_values = [10, -10, 10L, -10L, 10.1, -10.1, 1j,
669 _bad_values = [10, -10, 10L, -10L, 10.1, -10.1, 1j,
667 [10], ['ten'], [u'ten'], {'ten': 10},(10,), None]
670 [10], ['ten'], [u'ten'], {'ten': 10},(10,), None]
@@ -1,858 +1,861 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 A lightweight Traits like module.
4 A lightweight Traits like module.
5
5
6 This is designed to provide a lightweight, simple, pure Python version of
6 This is designed to provide a lightweight, simple, pure Python version of
7 many of the capabilities of enthought.traits. This includes:
7 many of the capabilities of enthought.traits. This includes:
8
8
9 * Validation
9 * Validation
10 * Type specification with defaults
10 * Type specification with defaults
11 * Static and dynamic notification
11 * Static and dynamic notification
12 * Basic predefined types
12 * Basic predefined types
13 * An API that is similar to enthought.traits
13 * An API that is similar to enthought.traits
14
14
15 We don't support:
15 We don't support:
16
16
17 * Delegation
17 * Delegation
18 * Automatic GUI generation
18 * Automatic GUI generation
19 * A full set of trait types. Most importantly, we don't provide container
19 * A full set of trait types. Most importantly, we don't provide container
20 traitlets (list, dict, tuple) that can trigger notifications if their
20 traitlets (list, dict, tuple) that can trigger notifications if their
21 contents change.
21 contents change.
22 * API compatibility with enthought.traits
22 * API compatibility with enthought.traits
23
23
24 There are also some important difference in our design:
24 There are also some important difference in our design:
25
25
26 * enthought.traits does not validate default values. We do.
26 * enthought.traits does not validate default values. We do.
27
27
28 We choose to create this module because we need these capabilities, but
28 We choose to create this module because we need these capabilities, but
29 we need them to be pure Python so they work in all Python implementations,
29 we need them to be pure Python so they work in all Python implementations,
30 including Jython and IronPython.
30 including Jython and IronPython.
31
31
32 Authors:
32 Authors:
33
33
34 * Brian Granger
34 * Brian Granger
35 * Enthought, Inc. Some of the code in this file comes from enthought.traits
35 * Enthought, Inc. Some of the code in this file comes from enthought.traits
36 and is licensed under the BSD license. Also, many of the ideas also come
36 and is licensed under the BSD license. Also, many of the ideas also come
37 from enthought.traits even though our implementation is very different.
37 from enthought.traits even though our implementation is very different.
38 """
38 """
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Copyright (C) 2008-2009 The IPython Development Team
41 # Copyright (C) 2008-2009 The IPython Development Team
42 #
42 #
43 # Distributed under the terms of the BSD License. The full license is in
43 # Distributed under the terms of the BSD License. The full license is in
44 # the file COPYING, distributed as part of this software.
44 # the file COPYING, distributed as part of this software.
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48 # Imports
48 # Imports
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50
50
51
51
52 import inspect
52 import inspect
53 import sys
53 import sys
54 import types
54 import types
55 from types import InstanceType, ClassType, FunctionType
55 from types import InstanceType, ClassType, FunctionType
56
56
57 ClassTypes = (ClassType, type)
57 ClassTypes = (ClassType, type)
58
58
59 #-----------------------------------------------------------------------------
59 #-----------------------------------------------------------------------------
60 # Basic classes
60 # Basic classes
61 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
62
62
63
63
64 class NoDefaultSpecified ( object ): pass
64 class NoDefaultSpecified ( object ): pass
65 NoDefaultSpecified = NoDefaultSpecified()
65 NoDefaultSpecified = NoDefaultSpecified()
66
66
67
67
68 class Undefined ( object ): pass
68 class Undefined ( object ): pass
69 Undefined = Undefined()
69 Undefined = Undefined()
70
70
71
71
72 class TraitletError(Exception):
72 class TraitletError(Exception):
73 pass
73 pass
74
74
75
75
76 #-----------------------------------------------------------------------------
76 #-----------------------------------------------------------------------------
77 # Utilities
77 # Utilities
78 #-----------------------------------------------------------------------------
78 #-----------------------------------------------------------------------------
79
79
80
80
81 def class_of ( object ):
81 def class_of ( object ):
82 """ Returns a string containing the class name of an object with the
82 """ Returns a string containing the class name of an object with the
83 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
83 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
84 'a PlotValue').
84 'a PlotValue').
85 """
85 """
86 if isinstance( object, basestring ):
86 if isinstance( object, basestring ):
87 return add_article( object )
87 return add_article( object )
88
88
89 return add_article( object.__class__.__name__ )
89 return add_article( object.__class__.__name__ )
90
90
91
91
92 def add_article ( name ):
92 def add_article ( name ):
93 """ Returns a string containing the correct indefinite article ('a' or 'an')
93 """ Returns a string containing the correct indefinite article ('a' or 'an')
94 prefixed to the specified string.
94 prefixed to the specified string.
95 """
95 """
96 if name[:1].lower() in 'aeiou':
96 if name[:1].lower() in 'aeiou':
97 return 'an ' + name
97 return 'an ' + name
98
98
99 return 'a ' + name
99 return 'a ' + name
100
100
101
101
102 def repr_type(obj):
102 def repr_type(obj):
103 """ Return a string representation of a value and its type for readable
103 """ Return a string representation of a value and its type for readable
104 error messages.
104 error messages.
105 """
105 """
106 the_type = type(obj)
106 the_type = type(obj)
107 if the_type is InstanceType:
107 if the_type is InstanceType:
108 # Old-style class.
108 # Old-style class.
109 the_type = obj.__class__
109 the_type = obj.__class__
110 msg = '%r %r' % (obj, the_type)
110 msg = '%r %r' % (obj, the_type)
111 return msg
111 return msg
112
112
113
113
114 def parse_notifier_name(name):
114 def parse_notifier_name(name):
115 """Convert the name argument to a list of names.
115 """Convert the name argument to a list of names.
116
116
117 Examples
117 Examples
118 --------
118 --------
119
119
120 >>> parse_notifier_name('a')
120 >>> parse_notifier_name('a')
121 ['a']
121 ['a']
122 >>> parse_notifier_name(['a','b'])
122 >>> parse_notifier_name(['a','b'])
123 ['a', 'b']
123 ['a', 'b']
124 >>> parse_notifier_name(None)
124 >>> parse_notifier_name(None)
125 ['anytraitlet']
125 ['anytraitlet']
126 """
126 """
127 if isinstance(name, str):
127 if isinstance(name, str):
128 return [name]
128 return [name]
129 elif name is None:
129 elif name is None:
130 return ['anytraitlet']
130 return ['anytraitlet']
131 elif isinstance(name, (list, tuple)):
131 elif isinstance(name, (list, tuple)):
132 for n in name:
132 for n in name:
133 assert isinstance(n, str), "names must be strings"
133 assert isinstance(n, str), "names must be strings"
134 return name
134 return name
135
135
136
136
137 class _SimpleTest:
137 class _SimpleTest:
138 def __init__ ( self, value ): self.value = value
138 def __init__ ( self, value ): self.value = value
139 def __call__ ( self, test ):
139 def __call__ ( self, test ):
140 print test, self.value
140 print test, self.value
141 return test == self.value
141 return test == self.value
142 def __repr__(self):
142 def __repr__(self):
143 return "<SimpleTest(%r)" % self.value
143 return "<SimpleTest(%r)" % self.value
144 def __str__(self):
144 def __str__(self):
145 return self.__repr__()
145 return self.__repr__()
146
146
147
147
148 #-----------------------------------------------------------------------------
148 #-----------------------------------------------------------------------------
149 # Base TraitletType for all traitlets
149 # Base TraitletType for all traitlets
150 #-----------------------------------------------------------------------------
150 #-----------------------------------------------------------------------------
151
151
152
152
153 class TraitletType(object):
153 class TraitletType(object):
154 """A base class for all traitlet descriptors.
154 """A base class for all traitlet descriptors.
155
155
156 Notes
156 Notes
157 -----
157 -----
158 Our implementation of traitlets is based on Python's descriptor
158 Our implementation of traitlets is based on Python's descriptor
159 prototol. This class is the base class for all such descriptors. The
159 prototol. This class is the base class for all such descriptors. The
160 only magic we use is a custom metaclass for the main :class:`HasTraitlets`
160 only magic we use is a custom metaclass for the main :class:`HasTraitlets`
161 class that does the following:
161 class that does the following:
162
162
163 1. Sets the :attr:`name` attribute of every :class:`TraitletType`
163 1. Sets the :attr:`name` attribute of every :class:`TraitletType`
164 instance in the class dict to the name of the attribute.
164 instance in the class dict to the name of the attribute.
165 2. Sets the :attr:`this_class` attribute of every :class:`TraitletType`
165 2. Sets the :attr:`this_class` attribute of every :class:`TraitletType`
166 instance in the class dict to the *class* that declared the traitlet.
166 instance in the class dict to the *class* that declared the traitlet.
167 This is used by the :class:`This` traitlet to allow subclasses to
167 This is used by the :class:`This` traitlet to allow subclasses to
168 accept superclasses for :class:`This` values.
168 accept superclasses for :class:`This` values.
169 """
169 """
170
170
171
171
172 metadata = {}
172 metadata = {}
173 default_value = Undefined
173 default_value = Undefined
174 info_text = 'any value'
174 info_text = 'any value'
175
175
176 def __init__(self, default_value=NoDefaultSpecified, **metadata):
176 def __init__(self, default_value=NoDefaultSpecified, **metadata):
177 """Create a TraitletType.
177 """Create a TraitletType.
178 """
178 """
179 if default_value is not NoDefaultSpecified:
179 if default_value is not NoDefaultSpecified:
180 self.default_value = default_value
180 self.default_value = default_value
181
181
182 if len(metadata) > 0:
182 if len(metadata) > 0:
183 if len(self.metadata) > 0:
183 if len(self.metadata) > 0:
184 self._metadata = self.metadata.copy()
184 self._metadata = self.metadata.copy()
185 self._metadata.update(metadata)
185 self._metadata.update(metadata)
186 else:
186 else:
187 self._metadata = metadata
187 self._metadata = metadata
188 else:
188 else:
189 self._metadata = self.metadata
189 self._metadata = self.metadata
190
190
191 self.init()
191 self.init()
192
192
193 def init(self):
193 def init(self):
194 pass
194 pass
195
195
196 def get_default_value(self):
196 def get_default_value(self):
197 """Create a new instance of the default value."""
197 """Create a new instance of the default value."""
198 dv = self.default_value
198 dv = self.default_value
199 return dv
199 return dv
200
200
201 def set_default_value(self, obj):
201 def set_default_value(self, obj):
202 dv = self.get_default_value()
202 dv = self.get_default_value()
203 newdv = self._validate(obj, dv)
203 newdv = self._validate(obj, dv)
204 obj._traitlet_values[self.name] = newdv
204 obj._traitlet_values[self.name] = newdv
205
205
206
206
207 def __get__(self, obj, cls=None):
207 def __get__(self, obj, cls=None):
208 """Get the value of the traitlet by self.name for the instance.
208 """Get the value of the traitlet by self.name for the instance.
209
209
210 Default values are instantiated when :meth:`HasTraitlets.__new__`
210 Default values are instantiated when :meth:`HasTraitlets.__new__`
211 is called. Thus by the time this method gets called either the
211 is called. Thus by the time this method gets called either the
212 default value or a user defined value (they called :meth:`__set__`)
212 default value or a user defined value (they called :meth:`__set__`)
213 is in the :class:`HasTraitlets` instance.
213 is in the :class:`HasTraitlets` instance.
214 """
214 """
215 if obj is None:
215 if obj is None:
216 return self
216 return self
217 else:
217 else:
218 try:
218 try:
219 value = obj._traitlet_values[self.name]
219 value = obj._traitlet_values[self.name]
220 except:
220 except:
221 # HasTraitlets should call set_default_value to populate
221 # HasTraitlets should call set_default_value to populate
222 # this. So this should never be reached.
222 # this. So this should never be reached.
223 raise TraitletError('Unexpected error in TraitletType: '
223 raise TraitletError('Unexpected error in TraitletType: '
224 'default value not set properly')
224 'default value not set properly')
225 else:
225 else:
226 return value
226 return value
227
227
228 def __set__(self, obj, value):
228 def __set__(self, obj, value):
229 new_value = self._validate(obj, value)
229 new_value = self._validate(obj, value)
230 old_value = self.__get__(obj)
230 old_value = self.__get__(obj)
231 if old_value != new_value:
231 if old_value != new_value:
232 obj._traitlet_values[self.name] = new_value
232 obj._traitlet_values[self.name] = new_value
233 obj._notify_traitlet(self.name, old_value, new_value)
233 obj._notify_traitlet(self.name, old_value, new_value)
234
234
235 def _validate(self, obj, value):
235 def _validate(self, obj, value):
236 if hasattr(self, 'validate'):
236 if hasattr(self, 'validate'):
237 return self.validate(obj, value)
237 return self.validate(obj, value)
238 elif hasattr(self, 'is_valid_for'):
238 elif hasattr(self, 'is_valid_for'):
239 valid = self.is_valid_for(value)
239 valid = self.is_valid_for(value)
240 if valid:
240 if valid:
241 return value
241 return value
242 else:
242 else:
243 raise TraitletError('invalid value for type: %r' % value)
243 raise TraitletError('invalid value for type: %r' % value)
244 elif hasattr(self, 'value_for'):
244 elif hasattr(self, 'value_for'):
245 return self.value_for(value)
245 return self.value_for(value)
246 else:
246 else:
247 return value
247 return value
248
248
249 def info(self):
249 def info(self):
250 return self.info_text
250 return self.info_text
251
251
252 def error(self, obj, value):
252 def error(self, obj, value):
253 if obj is not None:
253 if obj is not None:
254 e = "The '%s' traitlet of %s instance must be %s, but a value of %s was specified." \
254 e = "The '%s' traitlet of %s instance must be %s, but a value of %s was specified." \
255 % (self.name, class_of(obj),
255 % (self.name, class_of(obj),
256 self.info(), repr_type(value))
256 self.info(), repr_type(value))
257 else:
257 else:
258 e = "The '%s' traitlet must be %s, but a value of %r was specified." \
258 e = "The '%s' traitlet must be %s, but a value of %r was specified." \
259 % (self.name, self.info(), repr_type(value))
259 % (self.name, self.info(), repr_type(value))
260 raise TraitletError(e)
260 raise TraitletError(e)
261
261
262 def get_metadata(self, key):
262 def get_metadata(self, key):
263 return getattr(self, '_metadata', {}).get(key, None)
263 return getattr(self, '_metadata', {}).get(key, None)
264
264
265 def set_metadata(self, key, value):
265 def set_metadata(self, key, value):
266 getattr(self, '_metadata', {})[key] = value
266 getattr(self, '_metadata', {})[key] = value
267
267
268
268
269 #-----------------------------------------------------------------------------
269 #-----------------------------------------------------------------------------
270 # The HasTraitlets implementation
270 # The HasTraitlets implementation
271 #-----------------------------------------------------------------------------
271 #-----------------------------------------------------------------------------
272
272
273
273
274 class MetaHasTraitlets(type):
274 class MetaHasTraitlets(type):
275 """A metaclass for HasTraitlets.
275 """A metaclass for HasTraitlets.
276
276
277 This metaclass makes sure that any TraitletType class attributes are
277 This metaclass makes sure that any TraitletType class attributes are
278 instantiated and sets their name attribute.
278 instantiated and sets their name attribute.
279 """
279 """
280
280
281 def __new__(mcls, name, bases, classdict):
281 def __new__(mcls, name, bases, classdict):
282 """Create the HasTraitlets class.
282 """Create the HasTraitlets class.
283
283
284 This instantiates all TraitletTypes in the class dict and sets their
284 This instantiates all TraitletTypes in the class dict and sets their
285 :attr:`name` attribute.
285 :attr:`name` attribute.
286 """
286 """
287 # print "========================="
287 # print "========================="
288 # print "MetaHasTraitlets.__new__"
288 # print "MetaHasTraitlets.__new__"
289 # print "mcls, ", mcls
289 # print "mcls, ", mcls
290 # print "name, ", name
290 # print "name, ", name
291 # print "bases, ", bases
291 # print "bases, ", bases
292 # print "classdict, ", classdict
292 # print "classdict, ", classdict
293 for k,v in classdict.iteritems():
293 for k,v in classdict.iteritems():
294 if isinstance(v, TraitletType):
294 if isinstance(v, TraitletType):
295 v.name = k
295 v.name = k
296 elif inspect.isclass(v):
296 elif inspect.isclass(v):
297 if issubclass(v, TraitletType):
297 if issubclass(v, TraitletType):
298 vinst = v()
298 vinst = v()
299 vinst.name = k
299 vinst.name = k
300 classdict[k] = vinst
300 classdict[k] = vinst
301 return super(MetaHasTraitlets, mcls).__new__(mcls, name, bases, classdict)
301 return super(MetaHasTraitlets, mcls).__new__(mcls, name, bases, classdict)
302
302
303 def __init__(cls, name, bases, classdict):
303 def __init__(cls, name, bases, classdict):
304 """Finish initializing the HasTraitlets class.
304 """Finish initializing the HasTraitlets class.
305
305
306 This sets the :attr:`this_class` attribute of each TraitletType in the
306 This sets the :attr:`this_class` attribute of each TraitletType in the
307 class dict to the newly created class ``cls``.
307 class dict to the newly created class ``cls``.
308 """
308 """
309 # print "========================="
309 # print "========================="
310 # print "MetaHasTraitlets.__init__"
310 # print "MetaHasTraitlets.__init__"
311 # print "cls, ", cls
311 # print "cls, ", cls
312 # print "name, ", name
312 # print "name, ", name
313 # print "bases, ", bases
313 # print "bases, ", bases
314 # print "classdict, ", classdict
314 # print "classdict, ", classdict
315 for k, v in classdict.iteritems():
315 for k, v in classdict.iteritems():
316 if isinstance(v, TraitletType):
316 if isinstance(v, TraitletType):
317 v.this_class = cls
317 v.this_class = cls
318 super(MetaHasTraitlets, cls).__init__(name, bases, classdict)
318 super(MetaHasTraitlets, cls).__init__(name, bases, classdict)
319
319
320 class HasTraitlets(object):
320 class HasTraitlets(object):
321
321
322 __metaclass__ = MetaHasTraitlets
322 __metaclass__ = MetaHasTraitlets
323
323
324 def __new__(cls, *args, **kw):
324 def __new__(cls, *args, **kw):
325 inst = super(HasTraitlets, cls).__new__(cls, *args, **kw)
325 inst = super(HasTraitlets, cls).__new__(cls, *args, **kw)
326 inst._traitlet_values = {}
326 inst._traitlet_values = {}
327 inst._traitlet_notifiers = {}
327 inst._traitlet_notifiers = {}
328 # Here we tell all the TraitletType instances to set their default
328 # Here we tell all the TraitletType instances to set their default
329 # values on the instance.
329 # values on the instance.
330 for key in dir(cls):
330 for key in dir(cls):
331 value = getattr(cls, key)
331 value = getattr(cls, key)
332 if isinstance(value, TraitletType):
332 if isinstance(value, TraitletType):
333 value.set_default_value(inst)
333 value.set_default_value(inst)
334 return inst
334 return inst
335
335
336 # def __init__(self):
336 # def __init__(self):
337 # self._traitlet_values = {}
337 # self._traitlet_values = {}
338 # self._traitlet_notifiers = {}
338 # self._traitlet_notifiers = {}
339
339
340 def _notify_traitlet(self, name, old_value, new_value):
340 def _notify_traitlet(self, name, old_value, new_value):
341
341
342 # First dynamic ones
342 # First dynamic ones
343 callables = self._traitlet_notifiers.get(name,[])
343 callables = self._traitlet_notifiers.get(name,[])
344 more_callables = self._traitlet_notifiers.get('anytraitlet',[])
344 more_callables = self._traitlet_notifiers.get('anytraitlet',[])
345 callables.extend(more_callables)
345 callables.extend(more_callables)
346
346
347 # Now static ones
347 # Now static ones
348 try:
348 try:
349 cb = getattr(self, '_%s_changed' % name)
349 cb = getattr(self, '_%s_changed' % name)
350 except:
350 except:
351 pass
351 pass
352 else:
352 else:
353 callables.append(cb)
353 callables.append(cb)
354
354
355 # Call them all now
355 # Call them all now
356 for c in callables:
356 for c in callables:
357 # Traits catches and logs errors here. I allow them to raise
357 # Traits catches and logs errors here. I allow them to raise
358 if callable(c):
358 if callable(c):
359 argspec = inspect.getargspec(c)
359 argspec = inspect.getargspec(c)
360 nargs = len(argspec[0])
360 nargs = len(argspec[0])
361 # Bound methods have an additional 'self' argument
361 # Bound methods have an additional 'self' argument
362 # I don't know how to treat unbound methods, but they
362 # I don't know how to treat unbound methods, but they
363 # can't really be used for callbacks.
363 # can't really be used for callbacks.
364 if isinstance(c, types.MethodType):
364 if isinstance(c, types.MethodType):
365 offset = -1
365 offset = -1
366 else:
366 else:
367 offset = 0
367 offset = 0
368 if nargs + offset == 0:
368 if nargs + offset == 0:
369 c()
369 c()
370 elif nargs + offset == 1:
370 elif nargs + offset == 1:
371 c(name)
371 c(name)
372 elif nargs + offset == 2:
372 elif nargs + offset == 2:
373 c(name, new_value)
373 c(name, new_value)
374 elif nargs + offset == 3:
374 elif nargs + offset == 3:
375 c(name, old_value, new_value)
375 c(name, old_value, new_value)
376 else:
376 else:
377 raise TraitletError('a traitlet changed callback '
377 raise TraitletError('a traitlet changed callback '
378 'must have 0-3 arguments.')
378 'must have 0-3 arguments.')
379 else:
379 else:
380 raise TraitletError('a traitlet changed callback '
380 raise TraitletError('a traitlet changed callback '
381 'must be callable.')
381 'must be callable.')
382
382
383
383
384 def _add_notifiers(self, handler, name):
384 def _add_notifiers(self, handler, name):
385 if not self._traitlet_notifiers.has_key(name):
385 if not self._traitlet_notifiers.has_key(name):
386 nlist = []
386 nlist = []
387 self._traitlet_notifiers[name] = nlist
387 self._traitlet_notifiers[name] = nlist
388 else:
388 else:
389 nlist = self._traitlet_notifiers[name]
389 nlist = self._traitlet_notifiers[name]
390 if handler not in nlist:
390 if handler not in nlist:
391 nlist.append(handler)
391 nlist.append(handler)
392
392
393 def _remove_notifiers(self, handler, name):
393 def _remove_notifiers(self, handler, name):
394 if self._traitlet_notifiers.has_key(name):
394 if self._traitlet_notifiers.has_key(name):
395 nlist = self._traitlet_notifiers[name]
395 nlist = self._traitlet_notifiers[name]
396 try:
396 try:
397 index = nlist.index(handler)
397 index = nlist.index(handler)
398 except ValueError:
398 except ValueError:
399 pass
399 pass
400 else:
400 else:
401 del nlist[index]
401 del nlist[index]
402
402
403 def on_traitlet_change(self, handler, name=None, remove=False):
403 def on_traitlet_change(self, handler, name=None, remove=False):
404 """Setup a handler to be called when a traitlet changes.
404 """Setup a handler to be called when a traitlet changes.
405
405
406 This is used to setup dynamic notifications of traitlet changes.
406 This is used to setup dynamic notifications of traitlet changes.
407
407
408 Static handlers can be created by creating methods on a HasTraitlets
408 Static handlers can be created by creating methods on a HasTraitlets
409 subclass with the naming convention '_[traitletname]_changed'. Thus,
409 subclass with the naming convention '_[traitletname]_changed'. Thus,
410 to create static handler for the traitlet 'a', create the method
410 to create static handler for the traitlet 'a', create the method
411 _a_changed(self, name, old, new) (fewer arguments can be used, see
411 _a_changed(self, name, old, new) (fewer arguments can be used, see
412 below).
412 below).
413
413
414 Parameters
414 Parameters
415 ----------
415 ----------
416 handler : callable
416 handler : callable
417 A callable that is called when a traitlet changes. Its
417 A callable that is called when a traitlet changes. Its
418 signature can be handler(), handler(name), handler(name, new)
418 signature can be handler(), handler(name), handler(name, new)
419 or handler(name, old, new).
419 or handler(name, old, new).
420 name : list, str, None
420 name : list, str, None
421 If None, the handler will apply to all traitlets. If a list
421 If None, the handler will apply to all traitlets. If a list
422 of str, handler will apply to all names in the list. If a
422 of str, handler will apply to all names in the list. If a
423 str, the handler will apply just to that name.
423 str, the handler will apply just to that name.
424 remove : bool
424 remove : bool
425 If False (the default), then install the handler. If True
425 If False (the default), then install the handler. If True
426 then unintall it.
426 then unintall it.
427 """
427 """
428 if remove:
428 if remove:
429 names = parse_notifier_name(name)
429 names = parse_notifier_name(name)
430 for n in names:
430 for n in names:
431 self._remove_notifiers(handler, n)
431 self._remove_notifiers(handler, n)
432 else:
432 else:
433 names = parse_notifier_name(name)
433 names = parse_notifier_name(name)
434 for n in names:
434 for n in names:
435 self._add_notifiers(handler, n)
435 self._add_notifiers(handler, n)
436
436
437 def traitlet_names(self, **metadata):
437 def traitlet_names(self, **metadata):
438 """Get a list of all the names of this classes traitlets."""
438 """Get a list of all the names of this classes traitlets."""
439 return self.traitlets(**metadata).keys()
439 return self.traitlets(**metadata).keys()
440
440
441 def traitlets(self, **metadata):
441 def traitlets(self, *args, **metadata):
442 """Get a list of all the traitlets of this class.
442 """Get a list of all the traitlets of this class.
443
443
444 The TraitletTypes returned don't know anything about the values
444 The TraitletTypes returned don't know anything about the values
445 that the various HasTraitlet's instances are holding.
445 that the various HasTraitlet's instances are holding.
446 """
446 """
447 traitlets = dict([memb for memb in inspect.getmembers(self.__class__) if \
447 traitlets = dict([memb for memb in inspect.getmembers(self.__class__) if \
448 isinstance(memb[1], TraitletType)])
448 isinstance(memb[1], TraitletType)])
449 if len(metadata) == 0:
449 if len(metadata) == 0 and len(args) == 0:
450 return traitlets
450 return traitlets
451
451
452 for meta_name in args:
453 metadata[meta_name] = lambda _: True
454
452 for meta_name, meta_eval in metadata.items():
455 for meta_name, meta_eval in metadata.items():
453 if type(meta_eval) is not FunctionType:
456 if type(meta_eval) is not FunctionType:
454 metadata[meta_name] = _SimpleTest(meta_eval)
457 metadata[meta_name] = _SimpleTest(meta_eval)
455
458
456 result = {}
459 result = {}
457 for name, traitlet in traitlets.items():
460 for name, traitlet in traitlets.items():
458 for meta_name, meta_eval in metadata.items():
461 for meta_name, meta_eval in metadata.items():
459 if not meta_eval(traitlet.get_metadata(meta_name)):
462 if not meta_eval(traitlet.get_metadata(meta_name)):
460 break
463 break
461 else:
464 else:
462 result[name] = traitlet
465 result[name] = traitlet
463
466
464 return result
467 return result
465
468
466 def traitlet_metadata(self, traitletname, key):
469 def traitlet_metadata(self, traitletname, key):
467 """Get metadata values for traitlet by key."""
470 """Get metadata values for traitlet by key."""
468 try:
471 try:
469 traitlet = getattr(self.__class__, traitletname)
472 traitlet = getattr(self.__class__, traitletname)
470 except AttributeError:
473 except AttributeError:
471 raise TraitletError("Class %s does not have a traitlet named %s" %
474 raise TraitletError("Class %s does not have a traitlet named %s" %
472 (self.__class__.__name__, traitletname))
475 (self.__class__.__name__, traitletname))
473 else:
476 else:
474 return traitlet.get_metadata(key)
477 return traitlet.get_metadata(key)
475
478
476 #-----------------------------------------------------------------------------
479 #-----------------------------------------------------------------------------
477 # Actual TraitletTypes implementations/subclasses
480 # Actual TraitletTypes implementations/subclasses
478 #-----------------------------------------------------------------------------
481 #-----------------------------------------------------------------------------
479
482
480 #-----------------------------------------------------------------------------
483 #-----------------------------------------------------------------------------
481 # TraitletTypes subclasses for handling classes and instances of classes
484 # TraitletTypes subclasses for handling classes and instances of classes
482 #-----------------------------------------------------------------------------
485 #-----------------------------------------------------------------------------
483
486
484
487
485 class ClassBasedTraitletType(TraitletType):
488 class ClassBasedTraitletType(TraitletType):
486 """A traitlet with error reporting for Type, Instance and This."""
489 """A traitlet with error reporting for Type, Instance and This."""
487
490
488 def error(self, obj, value):
491 def error(self, obj, value):
489 kind = type(value)
492 kind = type(value)
490 if kind is InstanceType:
493 if kind is InstanceType:
491 msg = 'class %s' % value.__class__.__name__
494 msg = 'class %s' % value.__class__.__name__
492 else:
495 else:
493 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
496 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
494
497
495 super(ClassBasedTraitletType, self).error(obj, msg)
498 super(ClassBasedTraitletType, self).error(obj, msg)
496
499
497
500
498 class Type(ClassBasedTraitletType):
501 class Type(ClassBasedTraitletType):
499 """A traitlet whose value must be a subclass of a specified class."""
502 """A traitlet whose value must be a subclass of a specified class."""
500
503
501 def __init__ (self, default_value=None, klass=None, allow_none=True, **metadata ):
504 def __init__ (self, default_value=None, klass=None, allow_none=True, **metadata ):
502 """Construct a Type traitlet
505 """Construct a Type traitlet
503
506
504 A Type traitlet specifies that its values must be subclasses of
507 A Type traitlet specifies that its values must be subclasses of
505 a particular class.
508 a particular class.
506
509
507 Parameters
510 Parameters
508 ----------
511 ----------
509 default_value : class
512 default_value : class
510 The default value must be a subclass of klass.
513 The default value must be a subclass of klass.
511 klass : class, str, None
514 klass : class, str, None
512 Values of this traitlet must be a subclass of klass. The klass
515 Values of this traitlet must be a subclass of klass. The klass
513 may be specified in a string like: 'foo.bar.MyClass'.
516 may be specified in a string like: 'foo.bar.MyClass'.
514 allow_none : boolean
517 allow_none : boolean
515 Indicates whether None is allowed as an assignable value. Even if
518 Indicates whether None is allowed as an assignable value. Even if
516 ``False``, the default value may be ``None``.
519 ``False``, the default value may be ``None``.
517 """
520 """
518 if default_value is None:
521 if default_value is None:
519 if klass is None:
522 if klass is None:
520 klass = object
523 klass = object
521 elif klass is None:
524 elif klass is None:
522 klass = default_value
525 klass = default_value
523
526
524 if not inspect.isclass(klass):
527 if not inspect.isclass(klass):
525 raise TraitletError("A Type traitlet must specify a class.")
528 raise TraitletError("A Type traitlet must specify a class.")
526
529
527 self.klass = klass
530 self.klass = klass
528 self._allow_none = allow_none
531 self._allow_none = allow_none
529
532
530 super(Type, self).__init__(default_value, **metadata)
533 super(Type, self).__init__(default_value, **metadata)
531
534
532 def validate(self, obj, value):
535 def validate(self, obj, value):
533 """Validates that the value is a valid object instance."""
536 """Validates that the value is a valid object instance."""
534 try:
537 try:
535 if issubclass(value, self.klass):
538 if issubclass(value, self.klass):
536 return value
539 return value
537 except:
540 except:
538 if (value is None) and (self._allow_none):
541 if (value is None) and (self._allow_none):
539 return value
542 return value
540
543
541 self.error(obj, value)
544 self.error(obj, value)
542
545
543 def info(self):
546 def info(self):
544 """ Returns a description of the trait."""
547 """ Returns a description of the trait."""
545 klass = self.klass.__name__
548 klass = self.klass.__name__
546 result = 'a subclass of ' + klass
549 result = 'a subclass of ' + klass
547 if self._allow_none:
550 if self._allow_none:
548 return result + ' or None'
551 return result + ' or None'
549 return result
552 return result
550
553
551
554
552 class DefaultValueGenerator(object):
555 class DefaultValueGenerator(object):
553 """A class for generating new default value instances."""
556 """A class for generating new default value instances."""
554
557
555 def __init__(self, klass, *args, **kw):
558 def __init__(self, klass, *args, **kw):
556 self.klass = klass
559 self.klass = klass
557 self.args = args
560 self.args = args
558 self.kw = kw
561 self.kw = kw
559
562
560 def generate(self):
563 def generate(self):
561 return self.klass(*self.args, **self.kw)
564 return self.klass(*self.args, **self.kw)
562
565
563
566
564 class Instance(ClassBasedTraitletType):
567 class Instance(ClassBasedTraitletType):
565 """A trait whose value must be an instance of a specified class.
568 """A trait whose value must be an instance of a specified class.
566
569
567 The value can also be an instance of a subclass of the specified class.
570 The value can also be an instance of a subclass of the specified class.
568 """
571 """
569
572
570 def __init__(self, klass=None, args=None, kw=None,
573 def __init__(self, klass=None, args=None, kw=None,
571 allow_none=True, **metadata ):
574 allow_none=True, **metadata ):
572 """Construct an Instance traitlet.
575 """Construct an Instance traitlet.
573
576
574 This traitlet allows values that are instances of a particular
577 This traitlet allows values that are instances of a particular
575 class or its sublclasses. Our implementation is quite different
578 class or its sublclasses. Our implementation is quite different
576 from that of enthough.traits as we don't allow instances to be used
579 from that of enthough.traits as we don't allow instances to be used
577 for klass and we handle the ``args`` and ``kw`` arguments differently.
580 for klass and we handle the ``args`` and ``kw`` arguments differently.
578
581
579 Parameters
582 Parameters
580 ----------
583 ----------
581 klass : class
584 klass : class
582 The class that forms the basis for the traitlet. Instances
585 The class that forms the basis for the traitlet. Instances
583 and strings are not allowed.
586 and strings are not allowed.
584 args : tuple
587 args : tuple
585 Positional arguments for generating the default value.
588 Positional arguments for generating the default value.
586 kw : dict
589 kw : dict
587 Keyword arguments for generating the default value.
590 Keyword arguments for generating the default value.
588 allow_none : bool
591 allow_none : bool
589 Indicates whether None is allowed as a value.
592 Indicates whether None is allowed as a value.
590
593
591 Default Value
594 Default Value
592 -------------
595 -------------
593 If both ``args`` and ``kw`` are None, then the default value is None.
596 If both ``args`` and ``kw`` are None, then the default value is None.
594 If ``args`` is a tuple and ``kw`` is a dict, then the default is
597 If ``args`` is a tuple and ``kw`` is a dict, then the default is
595 created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
598 created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
596 not (but not both), None is replace by ``()`` or ``{}``.
599 not (but not both), None is replace by ``()`` or ``{}``.
597 """
600 """
598
601
599 self._allow_none = allow_none
602 self._allow_none = allow_none
600
603
601 if (klass is None) or (not inspect.isclass(klass)):
604 if (klass is None) or (not inspect.isclass(klass)):
602 raise TraitletError('The klass argument must be a class'
605 raise TraitletError('The klass argument must be a class'
603 ' you gave: %r' % klass)
606 ' you gave: %r' % klass)
604 self.klass = klass
607 self.klass = klass
605
608
606 # self.klass is a class, so handle default_value
609 # self.klass is a class, so handle default_value
607 if args is None and kw is None:
610 if args is None and kw is None:
608 default_value = None
611 default_value = None
609 else:
612 else:
610 if args is None:
613 if args is None:
611 # kw is not None
614 # kw is not None
612 args = ()
615 args = ()
613 elif kw is None:
616 elif kw is None:
614 # args is not None
617 # args is not None
615 kw = {}
618 kw = {}
616
619
617 if not isinstance(kw, dict):
620 if not isinstance(kw, dict):
618 raise TraitletError("The 'kw' argument must be a dict or None.")
621 raise TraitletError("The 'kw' argument must be a dict or None.")
619 if not isinstance(args, tuple):
622 if not isinstance(args, tuple):
620 raise TraitletError("The 'args' argument must be a tuple or None.")
623 raise TraitletError("The 'args' argument must be a tuple or None.")
621
624
622 default_value = DefaultValueGenerator(self.klass, *args, **kw)
625 default_value = DefaultValueGenerator(self.klass, *args, **kw)
623
626
624 super(Instance, self).__init__(default_value, **metadata)
627 super(Instance, self).__init__(default_value, **metadata)
625
628
626 def validate(self, obj, value):
629 def validate(self, obj, value):
627 if value is None:
630 if value is None:
628 if self._allow_none:
631 if self._allow_none:
629 return value
632 return value
630 self.error(obj, value)
633 self.error(obj, value)
631
634
632 if isinstance(value, self.klass):
635 if isinstance(value, self.klass):
633 return value
636 return value
634 else:
637 else:
635 self.error(obj, value)
638 self.error(obj, value)
636
639
637 def info(self):
640 def info(self):
638 klass = self.klass.__name__
641 klass = self.klass.__name__
639 result = class_of(klass)
642 result = class_of(klass)
640 if self._allow_none:
643 if self._allow_none:
641 return result + ' or None'
644 return result + ' or None'
642
645
643 return result
646 return result
644
647
645 def get_default_value(self):
648 def get_default_value(self):
646 """Instantiate a default value instance.
649 """Instantiate a default value instance.
647
650
648 This is called when the containing HasTraitlets classes'
651 This is called when the containing HasTraitlets classes'
649 :meth:`__new__` method is called to ensure that a unique instance
652 :meth:`__new__` method is called to ensure that a unique instance
650 is created for each HasTraitlets instance.
653 is created for each HasTraitlets instance.
651 """
654 """
652 dv = self.default_value
655 dv = self.default_value
653 if isinstance(dv, DefaultValueGenerator):
656 if isinstance(dv, DefaultValueGenerator):
654 return dv.generate()
657 return dv.generate()
655 else:
658 else:
656 return dv
659 return dv
657
660
658
661
659 class This(ClassBasedTraitletType):
662 class This(ClassBasedTraitletType):
660 """A traitlet for instances of the class containing this trait.
663 """A traitlet for instances of the class containing this trait.
661
664
662 Because how how and when class bodies are executed, the ``This``
665 Because how how and when class bodies are executed, the ``This``
663 traitlet can only have a default value of None. This, and because we
666 traitlet can only have a default value of None. This, and because we
664 always validate default values, ``allow_none`` is *always* true.
667 always validate default values, ``allow_none`` is *always* true.
665 """
668 """
666
669
667 info_text = 'an instance of the same type as the receiver or None'
670 info_text = 'an instance of the same type as the receiver or None'
668
671
669 def __init__(self, **metadata):
672 def __init__(self, **metadata):
670 super(This, self).__init__(None, **metadata)
673 super(This, self).__init__(None, **metadata)
671
674
672 def validate(self, obj, value):
675 def validate(self, obj, value):
673 # What if value is a superclass of obj.__class__? This is
676 # What if value is a superclass of obj.__class__? This is
674 # complicated if it was the superclass that defined the This
677 # complicated if it was the superclass that defined the This
675 # traitlet.
678 # traitlet.
676 if isinstance(value, self.this_class) or (value is None):
679 if isinstance(value, self.this_class) or (value is None):
677 return value
680 return value
678 else:
681 else:
679 self.error(obj, value)
682 self.error(obj, value)
680
683
681
684
682 #-----------------------------------------------------------------------------
685 #-----------------------------------------------------------------------------
683 # Basic TraitletTypes implementations/subclasses
686 # Basic TraitletTypes implementations/subclasses
684 #-----------------------------------------------------------------------------
687 #-----------------------------------------------------------------------------
685
688
686
689
687 class Any(TraitletType):
690 class Any(TraitletType):
688 default_value = None
691 default_value = None
689 info_text = 'any value'
692 info_text = 'any value'
690
693
691
694
692 class Int(TraitletType):
695 class Int(TraitletType):
693 """A integer traitlet."""
696 """A integer traitlet."""
694
697
695 evaluate = int
698 evaluate = int
696 default_value = 0
699 default_value = 0
697 info_text = 'an integer'
700 info_text = 'an integer'
698
701
699 def validate(self, obj, value):
702 def validate(self, obj, value):
700 if isinstance(value, int):
703 if isinstance(value, int):
701 return value
704 return value
702 self.error(obj, value)
705 self.error(obj, value)
703
706
704 class CInt(Int):
707 class CInt(Int):
705 """A casting version of the int traitlet."""
708 """A casting version of the int traitlet."""
706
709
707 def validate(self, obj, value):
710 def validate(self, obj, value):
708 try:
711 try:
709 return int(value)
712 return int(value)
710 except:
713 except:
711 self.error(obj, value)
714 self.error(obj, value)
712
715
713
716
714 class Long(TraitletType):
717 class Long(TraitletType):
715 """A long integer traitlet."""
718 """A long integer traitlet."""
716
719
717 evaluate = long
720 evaluate = long
718 default_value = 0L
721 default_value = 0L
719 info_text = 'a long'
722 info_text = 'a long'
720
723
721 def validate(self, obj, value):
724 def validate(self, obj, value):
722 if isinstance(value, long):
725 if isinstance(value, long):
723 return value
726 return value
724 if isinstance(value, int):
727 if isinstance(value, int):
725 return long(value)
728 return long(value)
726 self.error(obj, value)
729 self.error(obj, value)
727
730
728
731
729 class CLong(Long):
732 class CLong(Long):
730 """A casting version of the long integer traitlet."""
733 """A casting version of the long integer traitlet."""
731
734
732 def validate(self, obj, value):
735 def validate(self, obj, value):
733 try:
736 try:
734 return long(value)
737 return long(value)
735 except:
738 except:
736 self.error(obj, value)
739 self.error(obj, value)
737
740
738
741
739 class Float(TraitletType):
742 class Float(TraitletType):
740 """A float traitlet."""
743 """A float traitlet."""
741
744
742 evaluate = float
745 evaluate = float
743 default_value = 0.0
746 default_value = 0.0
744 info_text = 'a float'
747 info_text = 'a float'
745
748
746 def validate(self, obj, value):
749 def validate(self, obj, value):
747 if isinstance(value, float):
750 if isinstance(value, float):
748 return value
751 return value
749 if isinstance(value, int):
752 if isinstance(value, int):
750 return float(value)
753 return float(value)
751 self.error(obj, value)
754 self.error(obj, value)
752
755
753
756
754 class CFloat(Float):
757 class CFloat(Float):
755 """A casting version of the float traitlet."""
758 """A casting version of the float traitlet."""
756
759
757 def validate(self, obj, value):
760 def validate(self, obj, value):
758 try:
761 try:
759 return float(value)
762 return float(value)
760 except:
763 except:
761 self.error(obj, value)
764 self.error(obj, value)
762
765
763 class Complex(TraitletType):
766 class Complex(TraitletType):
764 """A traitlet for complex numbers."""
767 """A traitlet for complex numbers."""
765
768
766 evaluate = complex
769 evaluate = complex
767 default_value = 0.0 + 0.0j
770 default_value = 0.0 + 0.0j
768 info_text = 'a complex number'
771 info_text = 'a complex number'
769
772
770 def validate(self, obj, value):
773 def validate(self, obj, value):
771 if isinstance(value, complex):
774 if isinstance(value, complex):
772 return value
775 return value
773 if isinstance(value, (float, int)):
776 if isinstance(value, (float, int)):
774 return complex(value)
777 return complex(value)
775 self.error(obj, value)
778 self.error(obj, value)
776
779
777
780
778 class CComplex(Complex):
781 class CComplex(Complex):
779 """A casting version of the complex number traitlet."""
782 """A casting version of the complex number traitlet."""
780
783
781 def validate (self, obj, value):
784 def validate (self, obj, value):
782 try:
785 try:
783 return complex(value)
786 return complex(value)
784 except:
787 except:
785 self.error(obj, value)
788 self.error(obj, value)
786
789
787
790
788 class Str(TraitletType):
791 class Str(TraitletType):
789 """A traitlet for strings."""
792 """A traitlet for strings."""
790
793
791 evaluate = lambda x: x
794 evaluate = lambda x: x
792 default_value = ''
795 default_value = ''
793 info_text = 'a string'
796 info_text = 'a string'
794
797
795 def validate(self, obj, value):
798 def validate(self, obj, value):
796 if isinstance(value, str):
799 if isinstance(value, str):
797 return value
800 return value
798 self.error(obj, value)
801 self.error(obj, value)
799
802
800
803
801 class CStr(Str):
804 class CStr(Str):
802 """A casting version of the string traitlet."""
805 """A casting version of the string traitlet."""
803
806
804 def validate(self, obj, value):
807 def validate(self, obj, value):
805 try:
808 try:
806 return str(value)
809 return str(value)
807 except:
810 except:
808 try:
811 try:
809 return unicode(value)
812 return unicode(value)
810 except:
813 except:
811 self.error(obj, value)
814 self.error(obj, value)
812
815
813
816
814 class Unicode(TraitletType):
817 class Unicode(TraitletType):
815 """A traitlet for unicode strings."""
818 """A traitlet for unicode strings."""
816
819
817 evaluate = unicode
820 evaluate = unicode
818 default_value = u''
821 default_value = u''
819 info_text = 'a unicode string'
822 info_text = 'a unicode string'
820
823
821 def validate(self, obj, value):
824 def validate(self, obj, value):
822 if isinstance(value, unicode):
825 if isinstance(value, unicode):
823 return value
826 return value
824 if isinstance(value, str):
827 if isinstance(value, str):
825 return unicode(value)
828 return unicode(value)
826 self.error(obj, value)
829 self.error(obj, value)
827
830
828
831
829 class CUnicode(Unicode):
832 class CUnicode(Unicode):
830 """A casting version of the unicode traitlet."""
833 """A casting version of the unicode traitlet."""
831
834
832 def validate(self, obj, value):
835 def validate(self, obj, value):
833 try:
836 try:
834 return unicode(value)
837 return unicode(value)
835 except:
838 except:
836 self.error(obj, value)
839 self.error(obj, value)
837
840
838
841
839 class Bool(TraitletType):
842 class Bool(TraitletType):
840 """A boolean (True, False) traitlet."""
843 """A boolean (True, False) traitlet."""
841 evaluate = bool
844 evaluate = bool
842 default_value = False
845 default_value = False
843 info_text = 'a boolean'
846 info_text = 'a boolean'
844
847
845 def validate(self, obj, value):
848 def validate(self, obj, value):
846 if isinstance(value, bool):
849 if isinstance(value, bool):
847 return value
850 return value
848 self.error(obj, value)
851 self.error(obj, value)
849
852
850
853
851 class CBool(Bool):
854 class CBool(Bool):
852 """A casting version of the boolean traitlet."""
855 """A casting version of the boolean traitlet."""
853
856
854 def validate(self, obj, value):
857 def validate(self, obj, value):
855 try:
858 try:
856 return bool(value)
859 return bool(value)
857 except:
860 except:
858 self.error(obj, value) No newline at end of file
861 self.error(obj, value)
General Comments 0
You need to be logged in to leave comments. Login now